cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ssp.c (5315B)


      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
     35static DEFINE_MUTEX(ssp_lock);
     36static LIST_HEAD(ssp_list);
     37
     38struct 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}
     59EXPORT_SYMBOL(pxa_ssp_request);
     60
     61struct 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}
     83EXPORT_SYMBOL(pxa_ssp_request_of);
     84
     85void 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->dev, "device already free\n");
     93	mutex_unlock(&ssp_lock);
     94}
     95EXPORT_SYMBOL(pxa_ssp_free);
     96
     97#ifdef CONFIG_OF
     98static 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};
    108MODULE_DEVICE_TABLE(of, pxa_ssp_of_ids);
    109#endif
    110
    111static 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->dev = dev;
    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
    181static 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
    196static 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
    206static 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
    216static int __init pxa_ssp_init(void)
    217{
    218	return platform_driver_register(&pxa_ssp_driver);
    219}
    220
    221static void __exit pxa_ssp_exit(void)
    222{
    223	platform_driver_unregister(&pxa_ssp_driver);
    224}
    225
    226arch_initcall(pxa_ssp_init);
    227module_exit(pxa_ssp_exit);
    228
    229MODULE_DESCRIPTION("PXA SSP driver");
    230MODULE_AUTHOR("Liam Girdwood");
    231MODULE_LICENSE("GPL");