root/arch/arm/plat-pxa/ssp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pxa_ssp_request
  2. pxa_ssp_request_of
  3. pxa_ssp_free
  4. pxa_ssp_probe
  5. pxa_ssp_remove
  6. pxa_ssp_init
  7. pxa_ssp_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  *  linux/arch/arm/mach-pxa/ssp.c
   4  *
   5  *  based on linux/arch/arm/mach-sa1100/ssp.c by Russell King
   6  *
   7  *  Copyright (C) 2003 Russell King.
   8  *  Copyright (C) 2003 Wolfson Microelectronics PLC
   9  *
  10  *  PXA2xx SSP driver.  This provides the generic core for simple
  11  *  IO-based SSP applications and allows easy port setup for DMA access.
  12  *
  13  *  Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
  14  */
  15 
  16 #include <linux/module.h>
  17 #include <linux/kernel.h>
  18 #include <linux/sched.h>
  19 #include <linux/slab.h>
  20 #include <linux/errno.h>
  21 #include <linux/interrupt.h>
  22 #include <linux/ioport.h>
  23 #include <linux/init.h>
  24 #include <linux/mutex.h>
  25 #include <linux/clk.h>
  26 #include <linux/err.h>
  27 #include <linux/platform_device.h>
  28 #include <linux/spi/pxa2xx_spi.h>
  29 #include <linux/io.h>
  30 #include <linux/of.h>
  31 #include <linux/of_device.h>
  32 
  33 #include <asm/irq.h>
  34 
  35 static DEFINE_MUTEX(ssp_lock);
  36 static LIST_HEAD(ssp_list);
  37 
  38 struct ssp_device *pxa_ssp_request(int port, const char *label)
  39 {
  40         struct ssp_device *ssp = NULL;
  41 
  42         mutex_lock(&ssp_lock);
  43 
  44         list_for_each_entry(ssp, &ssp_list, node) {
  45                 if (ssp->port_id == port && ssp->use_count == 0) {
  46                         ssp->use_count++;
  47                         ssp->label = label;
  48                         break;
  49                 }
  50         }
  51 
  52         mutex_unlock(&ssp_lock);
  53 
  54         if (&ssp->node == &ssp_list)
  55                 return NULL;
  56 
  57         return ssp;
  58 }
  59 EXPORT_SYMBOL(pxa_ssp_request);
  60 
  61 struct ssp_device *pxa_ssp_request_of(const struct device_node *of_node,
  62                                       const char *label)
  63 {
  64         struct ssp_device *ssp = NULL;
  65 
  66         mutex_lock(&ssp_lock);
  67 
  68         list_for_each_entry(ssp, &ssp_list, node) {
  69                 if (ssp->of_node == of_node && ssp->use_count == 0) {
  70                         ssp->use_count++;
  71                         ssp->label = label;
  72                         break;
  73                 }
  74         }
  75 
  76         mutex_unlock(&ssp_lock);
  77 
  78         if (&ssp->node == &ssp_list)
  79                 return NULL;
  80 
  81         return ssp;
  82 }
  83 EXPORT_SYMBOL(pxa_ssp_request_of);
  84 
  85 void pxa_ssp_free(struct ssp_device *ssp)
  86 {
  87         mutex_lock(&ssp_lock);
  88         if (ssp->use_count) {
  89                 ssp->use_count--;
  90                 ssp->label = NULL;
  91         } else
  92                 dev_err(&ssp->pdev->dev, "device already free\n");
  93         mutex_unlock(&ssp_lock);
  94 }
  95 EXPORT_SYMBOL(pxa_ssp_free);
  96 
  97 #ifdef CONFIG_OF
  98 static const struct of_device_id pxa_ssp_of_ids[] = {
  99         { .compatible = "mrvl,pxa25x-ssp",      .data = (void *) PXA25x_SSP },
 100         { .compatible = "mvrl,pxa25x-nssp",     .data = (void *) PXA25x_NSSP },
 101         { .compatible = "mrvl,pxa27x-ssp",      .data = (void *) PXA27x_SSP },
 102         { .compatible = "mrvl,pxa3xx-ssp",      .data = (void *) PXA3xx_SSP },
 103         { .compatible = "mvrl,pxa168-ssp",      .data = (void *) PXA168_SSP },
 104         { .compatible = "mrvl,pxa910-ssp",      .data = (void *) PXA910_SSP },
 105         { .compatible = "mrvl,ce4100-ssp",      .data = (void *) CE4100_SSP },
 106         { },
 107 };
 108 MODULE_DEVICE_TABLE(of, pxa_ssp_of_ids);
 109 #endif
 110 
 111 static int pxa_ssp_probe(struct platform_device *pdev)
 112 {
 113         struct resource *res;
 114         struct ssp_device *ssp;
 115         struct device *dev = &pdev->dev;
 116 
 117         ssp = devm_kzalloc(dev, sizeof(struct ssp_device), GFP_KERNEL);
 118         if (ssp == NULL)
 119                 return -ENOMEM;
 120 
 121         ssp->pdev = pdev;
 122 
 123         ssp->clk = devm_clk_get(dev, NULL);
 124         if (IS_ERR(ssp->clk))
 125                 return PTR_ERR(ssp->clk);
 126 
 127         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 128         if (res == NULL) {
 129                 dev_err(dev, "no memory resource defined\n");
 130                 return -ENODEV;
 131         }
 132 
 133         res = devm_request_mem_region(dev, res->start, resource_size(res),
 134                                       pdev->name);
 135         if (res == NULL) {
 136                 dev_err(dev, "failed to request memory resource\n");
 137                 return -EBUSY;
 138         }
 139 
 140         ssp->phys_base = res->start;
 141 
 142         ssp->mmio_base = devm_ioremap(dev, res->start, resource_size(res));
 143         if (ssp->mmio_base == NULL) {
 144                 dev_err(dev, "failed to ioremap() registers\n");
 145                 return -ENODEV;
 146         }
 147 
 148         ssp->irq = platform_get_irq(pdev, 0);
 149         if (ssp->irq < 0) {
 150                 dev_err(dev, "no IRQ resource defined\n");
 151                 return -ENODEV;
 152         }
 153 
 154         if (dev->of_node) {
 155                 const struct of_device_id *id =
 156                         of_match_device(of_match_ptr(pxa_ssp_of_ids), dev);
 157                 ssp->type = (int) id->data;
 158         } else {
 159                 const struct platform_device_id *id =
 160                         platform_get_device_id(pdev);
 161                 ssp->type = (int) id->driver_data;
 162 
 163                 /* PXA2xx/3xx SSP ports starts from 1 and the internal pdev->id
 164                  * starts from 0, do a translation here
 165                  */
 166                 ssp->port_id = pdev->id + 1;
 167         }
 168 
 169         ssp->use_count = 0;
 170         ssp->of_node = dev->of_node;
 171 
 172         mutex_lock(&ssp_lock);
 173         list_add(&ssp->node, &ssp_list);
 174         mutex_unlock(&ssp_lock);
 175 
 176         platform_set_drvdata(pdev, ssp);
 177 
 178         return 0;
 179 }
 180 
 181 static int pxa_ssp_remove(struct platform_device *pdev)
 182 {
 183         struct ssp_device *ssp;
 184 
 185         ssp = platform_get_drvdata(pdev);
 186         if (ssp == NULL)
 187                 return -ENODEV;
 188 
 189         mutex_lock(&ssp_lock);
 190         list_del(&ssp->node);
 191         mutex_unlock(&ssp_lock);
 192 
 193         return 0;
 194 }
 195 
 196 static const struct platform_device_id ssp_id_table[] = {
 197         { "pxa25x-ssp",         PXA25x_SSP },
 198         { "pxa25x-nssp",        PXA25x_NSSP },
 199         { "pxa27x-ssp",         PXA27x_SSP },
 200         { "pxa3xx-ssp",         PXA3xx_SSP },
 201         { "pxa168-ssp",         PXA168_SSP },
 202         { "pxa910-ssp",         PXA910_SSP },
 203         { },
 204 };
 205 
 206 static struct platform_driver pxa_ssp_driver = {
 207         .probe          = pxa_ssp_probe,
 208         .remove         = pxa_ssp_remove,
 209         .driver         = {
 210                 .name           = "pxa2xx-ssp",
 211                 .of_match_table = of_match_ptr(pxa_ssp_of_ids),
 212         },
 213         .id_table       = ssp_id_table,
 214 };
 215 
 216 static int __init pxa_ssp_init(void)
 217 {
 218         return platform_driver_register(&pxa_ssp_driver);
 219 }
 220 
 221 static void __exit pxa_ssp_exit(void)
 222 {
 223         platform_driver_unregister(&pxa_ssp_driver);
 224 }
 225 
 226 arch_initcall(pxa_ssp_init);
 227 module_exit(pxa_ssp_exit);
 228 
 229 MODULE_DESCRIPTION("PXA SSP driver");
 230 MODULE_AUTHOR("Liam Girdwood");
 231 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */