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

i2c-pca-platform.c (5971B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *  i2c_pca_platform.c
      4 *
      5 *  Platform driver for the PCA9564 I2C controller.
      6 *
      7 *  Copyright (C) 2008 Pengutronix
      8 *
      9
     10 */
     11#include <linux/kernel.h>
     12#include <linux/module.h>
     13#include <linux/slab.h>
     14#include <linux/delay.h>
     15#include <linux/jiffies.h>
     16#include <linux/errno.h>
     17#include <linux/i2c.h>
     18#include <linux/interrupt.h>
     19#include <linux/platform_device.h>
     20#include <linux/i2c-algo-pca.h>
     21#include <linux/platform_data/i2c-pca-platform.h>
     22#include <linux/gpio/consumer.h>
     23#include <linux/io.h>
     24#include <linux/of.h>
     25#include <linux/of_device.h>
     26
     27#include <asm/irq.h>
     28
     29struct i2c_pca_pf_data {
     30	void __iomem			*reg_base;
     31	int				irq;	/* if 0, use polling */
     32	struct gpio_desc		*gpio;
     33	wait_queue_head_t		wait;
     34	struct i2c_adapter		adap;
     35	struct i2c_algo_pca_data	algo_data;
     36};
     37
     38/* Read/Write functions for different register alignments */
     39
     40static int i2c_pca_pf_readbyte8(void *pd, int reg)
     41{
     42	struct i2c_pca_pf_data *i2c = pd;
     43	return ioread8(i2c->reg_base + reg);
     44}
     45
     46static int i2c_pca_pf_readbyte16(void *pd, int reg)
     47{
     48	struct i2c_pca_pf_data *i2c = pd;
     49	return ioread8(i2c->reg_base + reg * 2);
     50}
     51
     52static int i2c_pca_pf_readbyte32(void *pd, int reg)
     53{
     54	struct i2c_pca_pf_data *i2c = pd;
     55	return ioread8(i2c->reg_base + reg * 4);
     56}
     57
     58static void i2c_pca_pf_writebyte8(void *pd, int reg, int val)
     59{
     60	struct i2c_pca_pf_data *i2c = pd;
     61	iowrite8(val, i2c->reg_base + reg);
     62}
     63
     64static void i2c_pca_pf_writebyte16(void *pd, int reg, int val)
     65{
     66	struct i2c_pca_pf_data *i2c = pd;
     67	iowrite8(val, i2c->reg_base + reg * 2);
     68}
     69
     70static void i2c_pca_pf_writebyte32(void *pd, int reg, int val)
     71{
     72	struct i2c_pca_pf_data *i2c = pd;
     73	iowrite8(val, i2c->reg_base + reg * 4);
     74}
     75
     76
     77static int i2c_pca_pf_waitforcompletion(void *pd)
     78{
     79	struct i2c_pca_pf_data *i2c = pd;
     80	unsigned long timeout;
     81	long ret;
     82
     83	if (i2c->irq) {
     84		ret = wait_event_timeout(i2c->wait,
     85			i2c->algo_data.read_byte(i2c, I2C_PCA_CON)
     86			& I2C_PCA_CON_SI, i2c->adap.timeout);
     87	} else {
     88		/* Do polling */
     89		timeout = jiffies + i2c->adap.timeout;
     90		do {
     91			ret = time_before(jiffies, timeout);
     92			if (i2c->algo_data.read_byte(i2c, I2C_PCA_CON)
     93					& I2C_PCA_CON_SI)
     94				break;
     95			udelay(100);
     96		} while (ret);
     97	}
     98
     99	return ret > 0;
    100}
    101
    102static void i2c_pca_pf_dummyreset(void *pd)
    103{
    104	struct i2c_pca_pf_data *i2c = pd;
    105
    106	dev_warn(&i2c->adap.dev, "No reset-pin found. Chip may get stuck!\n");
    107}
    108
    109static void i2c_pca_pf_resetchip(void *pd)
    110{
    111	struct i2c_pca_pf_data *i2c = pd;
    112
    113	gpiod_set_value(i2c->gpio, 1);
    114	ndelay(100);
    115	gpiod_set_value(i2c->gpio, 0);
    116}
    117
    118static irqreturn_t i2c_pca_pf_handler(int this_irq, void *dev_id)
    119{
    120	struct i2c_pca_pf_data *i2c = dev_id;
    121
    122	if ((i2c->algo_data.read_byte(i2c, I2C_PCA_CON) & I2C_PCA_CON_SI) == 0)
    123		return IRQ_NONE;
    124
    125	wake_up(&i2c->wait);
    126
    127	return IRQ_HANDLED;
    128}
    129
    130
    131static int i2c_pca_pf_probe(struct platform_device *pdev)
    132{
    133	struct i2c_pca_pf_data *i2c;
    134	struct resource *res;
    135	struct i2c_pca9564_pf_platform_data *platform_data =
    136				dev_get_platdata(&pdev->dev);
    137	struct device_node *np = pdev->dev.of_node;
    138	int ret = 0;
    139	int irq;
    140
    141	irq = platform_get_irq_optional(pdev, 0);
    142	/* If irq is 0, we do polling. */
    143	if (irq < 0)
    144		irq = 0;
    145
    146	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
    147	if (!i2c)
    148		return -ENOMEM;
    149
    150	i2c->reg_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
    151	if (IS_ERR(i2c->reg_base))
    152		return PTR_ERR(i2c->reg_base);
    153
    154
    155	init_waitqueue_head(&i2c->wait);
    156
    157	i2c->irq = irq;
    158
    159	i2c->adap.nr = pdev->id;
    160	i2c->adap.owner = THIS_MODULE;
    161	snprintf(i2c->adap.name, sizeof(i2c->adap.name),
    162		 "PCA9564/PCA9665 at 0x%08lx",
    163		 (unsigned long) res->start);
    164	i2c->adap.algo_data = &i2c->algo_data;
    165	i2c->adap.dev.parent = &pdev->dev;
    166	i2c->adap.dev.of_node = np;
    167
    168	i2c->gpio = devm_gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW);
    169	if (IS_ERR(i2c->gpio))
    170		return PTR_ERR(i2c->gpio);
    171
    172	i2c->adap.timeout = HZ;
    173	ret = device_property_read_u32(&pdev->dev, "clock-frequency",
    174				       &i2c->algo_data.i2c_clock);
    175	if (ret)
    176		i2c->algo_data.i2c_clock = 59000;
    177
    178	if (platform_data) {
    179		i2c->adap.timeout = platform_data->timeout;
    180		i2c->algo_data.i2c_clock = platform_data->i2c_clock_speed;
    181	}
    182
    183	i2c->algo_data.data = i2c;
    184	i2c->algo_data.wait_for_completion = i2c_pca_pf_waitforcompletion;
    185	if (i2c->gpio)
    186		i2c->algo_data.reset_chip = i2c_pca_pf_resetchip;
    187	else
    188		i2c->algo_data.reset_chip = i2c_pca_pf_dummyreset;
    189
    190	switch (res->flags & IORESOURCE_MEM_TYPE_MASK) {
    191	case IORESOURCE_MEM_32BIT:
    192		i2c->algo_data.write_byte = i2c_pca_pf_writebyte32;
    193		i2c->algo_data.read_byte = i2c_pca_pf_readbyte32;
    194		break;
    195	case IORESOURCE_MEM_16BIT:
    196		i2c->algo_data.write_byte = i2c_pca_pf_writebyte16;
    197		i2c->algo_data.read_byte = i2c_pca_pf_readbyte16;
    198		break;
    199	case IORESOURCE_MEM_8BIT:
    200	default:
    201		i2c->algo_data.write_byte = i2c_pca_pf_writebyte8;
    202		i2c->algo_data.read_byte = i2c_pca_pf_readbyte8;
    203		break;
    204	}
    205
    206	if (irq) {
    207		ret = devm_request_irq(&pdev->dev, irq, i2c_pca_pf_handler,
    208			IRQF_TRIGGER_FALLING, pdev->name, i2c);
    209		if (ret)
    210			return ret;
    211	}
    212
    213	ret = i2c_pca_add_numbered_bus(&i2c->adap);
    214	if (ret)
    215		return ret;
    216
    217	platform_set_drvdata(pdev, i2c);
    218
    219	dev_info(&pdev->dev, "registered.\n");
    220
    221	return 0;
    222}
    223
    224static int i2c_pca_pf_remove(struct platform_device *pdev)
    225{
    226	struct i2c_pca_pf_data *i2c = platform_get_drvdata(pdev);
    227
    228	i2c_del_adapter(&i2c->adap);
    229
    230	return 0;
    231}
    232
    233#ifdef CONFIG_OF
    234static const struct of_device_id i2c_pca_of_match_table[] = {
    235	{ .compatible = "nxp,pca9564" },
    236	{ .compatible = "nxp,pca9665" },
    237	{},
    238};
    239MODULE_DEVICE_TABLE(of, i2c_pca_of_match_table);
    240#endif
    241
    242static struct platform_driver i2c_pca_pf_driver = {
    243	.probe = i2c_pca_pf_probe,
    244	.remove = i2c_pca_pf_remove,
    245	.driver = {
    246		.name = "i2c-pca-platform",
    247		.of_match_table = of_match_ptr(i2c_pca_of_match_table),
    248	},
    249};
    250
    251module_platform_driver(i2c_pca_pf_driver);
    252
    253MODULE_AUTHOR("Wolfram Sang <kernel@pengutronix.de>");
    254MODULE_DESCRIPTION("I2C-PCA9564/PCA9665 platform driver");
    255MODULE_LICENSE("GPL");