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-digicolor.c (8054B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * I2C bus driver for Conexant Digicolor SoCs
      4 *
      5 * Author: Baruch Siach <baruch@tkos.co.il>
      6 *
      7 * Copyright (C) 2015 Paradox Innovation Ltd.
      8 */
      9
     10#include <linux/clk.h>
     11#include <linux/completion.h>
     12#include <linux/delay.h>
     13#include <linux/i2c.h>
     14#include <linux/interrupt.h>
     15#include <linux/io.h>
     16#include <linux/kernel.h>
     17#include <linux/module.h>
     18#include <linux/of.h>
     19#include <linux/platform_device.h>
     20
     21#define TIMEOUT_MS		100
     22
     23#define II_CONTROL		0x0
     24#define II_CONTROL_LOCAL_RESET	BIT(0)
     25
     26#define II_CLOCKTIME		0x1
     27
     28#define II_COMMAND		0x2
     29#define II_CMD_START		1
     30#define II_CMD_RESTART		2
     31#define II_CMD_SEND_ACK		3
     32#define II_CMD_GET_ACK		6
     33#define II_CMD_GET_NOACK	7
     34#define II_CMD_STOP		10
     35#define II_COMMAND_GO		BIT(7)
     36#define II_COMMAND_COMPLETION_STATUS(r)	(((r) >> 5) & 3)
     37#define II_CMD_STATUS_NORMAL	0
     38#define II_CMD_STATUS_ACK_GOOD	1
     39#define II_CMD_STATUS_ACK_BAD	2
     40#define II_CMD_STATUS_ABORT	3
     41
     42#define II_DATA			0x3
     43#define II_INTFLAG_CLEAR	0x8
     44#define II_INTENABLE		0xa
     45
     46struct dc_i2c {
     47	struct i2c_adapter	adap;
     48	struct device		*dev;
     49	void __iomem		*regs;
     50	struct clk		*clk;
     51	unsigned int		frequency;
     52
     53	struct i2c_msg		*msg;
     54	unsigned int		msgbuf_ptr;
     55	int			last;
     56	spinlock_t		lock;
     57	struct completion	done;
     58	int			state;
     59	int			error;
     60};
     61
     62enum {
     63	STATE_IDLE,
     64	STATE_START,
     65	STATE_ADDR,
     66	STATE_WRITE,
     67	STATE_READ,
     68	STATE_STOP,
     69};
     70
     71static void dc_i2c_cmd(struct dc_i2c *i2c, u8 cmd)
     72{
     73	writeb_relaxed(cmd | II_COMMAND_GO, i2c->regs + II_COMMAND);
     74}
     75
     76static u8 dc_i2c_addr_cmd(struct i2c_msg *msg)
     77{
     78	u8 addr = (msg->addr & 0x7f) << 1;
     79
     80	if (msg->flags & I2C_M_RD)
     81		addr |= 1;
     82
     83	return addr;
     84}
     85
     86static void dc_i2c_data(struct dc_i2c *i2c, u8 data)
     87{
     88	writeb_relaxed(data, i2c->regs + II_DATA);
     89}
     90
     91static void dc_i2c_write_byte(struct dc_i2c *i2c, u8 byte)
     92{
     93	dc_i2c_data(i2c, byte);
     94	dc_i2c_cmd(i2c, II_CMD_SEND_ACK);
     95}
     96
     97static void dc_i2c_write_buf(struct dc_i2c *i2c)
     98{
     99	dc_i2c_write_byte(i2c, i2c->msg->buf[i2c->msgbuf_ptr++]);
    100}
    101
    102static void dc_i2c_next_read(struct dc_i2c *i2c)
    103{
    104	bool last = (i2c->msgbuf_ptr + 1 == i2c->msg->len);
    105
    106	dc_i2c_cmd(i2c, last ? II_CMD_GET_NOACK : II_CMD_GET_ACK);
    107}
    108
    109static void dc_i2c_stop(struct dc_i2c *i2c)
    110{
    111	i2c->state = STATE_STOP;
    112	if (i2c->last)
    113		dc_i2c_cmd(i2c, II_CMD_STOP);
    114	else
    115		complete(&i2c->done);
    116}
    117
    118static u8 dc_i2c_read_byte(struct dc_i2c *i2c)
    119{
    120	return readb_relaxed(i2c->regs + II_DATA);
    121}
    122
    123static void dc_i2c_read_buf(struct dc_i2c *i2c)
    124{
    125	i2c->msg->buf[i2c->msgbuf_ptr++] = dc_i2c_read_byte(i2c);
    126	dc_i2c_next_read(i2c);
    127}
    128
    129static void dc_i2c_set_irq(struct dc_i2c *i2c, int enable)
    130{
    131	if (enable)
    132		writeb_relaxed(1, i2c->regs + II_INTFLAG_CLEAR);
    133	writeb_relaxed(!!enable, i2c->regs + II_INTENABLE);
    134}
    135
    136static int dc_i2c_cmd_status(struct dc_i2c *i2c)
    137{
    138	u8 cmd = readb_relaxed(i2c->regs + II_COMMAND);
    139
    140	return II_COMMAND_COMPLETION_STATUS(cmd);
    141}
    142
    143static void dc_i2c_start_msg(struct dc_i2c *i2c, int first)
    144{
    145	struct i2c_msg *msg = i2c->msg;
    146
    147	if (!(msg->flags & I2C_M_NOSTART)) {
    148		i2c->state = STATE_START;
    149		dc_i2c_cmd(i2c, first ? II_CMD_START : II_CMD_RESTART);
    150	} else if (msg->flags & I2C_M_RD) {
    151		i2c->state = STATE_READ;
    152		dc_i2c_next_read(i2c);
    153	} else {
    154		i2c->state = STATE_WRITE;
    155		dc_i2c_write_buf(i2c);
    156	}
    157}
    158
    159static irqreturn_t dc_i2c_irq(int irq, void *dev_id)
    160{
    161	struct dc_i2c *i2c = dev_id;
    162	int cmd_status = dc_i2c_cmd_status(i2c);
    163	u8 addr_cmd;
    164
    165	writeb_relaxed(1, i2c->regs + II_INTFLAG_CLEAR);
    166
    167	spin_lock(&i2c->lock);
    168
    169	if (cmd_status == II_CMD_STATUS_ACK_BAD
    170	    || cmd_status == II_CMD_STATUS_ABORT) {
    171		i2c->error = -EIO;
    172		complete(&i2c->done);
    173		goto out;
    174	}
    175
    176	switch (i2c->state) {
    177	case STATE_START:
    178		addr_cmd = dc_i2c_addr_cmd(i2c->msg);
    179		dc_i2c_write_byte(i2c, addr_cmd);
    180		i2c->state = STATE_ADDR;
    181		break;
    182	case STATE_ADDR:
    183		if (i2c->msg->flags & I2C_M_RD) {
    184			dc_i2c_next_read(i2c);
    185			i2c->state = STATE_READ;
    186			break;
    187		}
    188		i2c->state = STATE_WRITE;
    189		fallthrough;
    190	case STATE_WRITE:
    191		if (i2c->msgbuf_ptr < i2c->msg->len)
    192			dc_i2c_write_buf(i2c);
    193		else
    194			dc_i2c_stop(i2c);
    195		break;
    196	case STATE_READ:
    197		if (i2c->msgbuf_ptr < i2c->msg->len)
    198			dc_i2c_read_buf(i2c);
    199		else
    200			dc_i2c_stop(i2c);
    201		break;
    202	case STATE_STOP:
    203		i2c->state = STATE_IDLE;
    204		complete(&i2c->done);
    205		break;
    206	}
    207
    208out:
    209	spin_unlock(&i2c->lock);
    210	return IRQ_HANDLED;
    211}
    212
    213static int dc_i2c_xfer_msg(struct dc_i2c *i2c, struct i2c_msg *msg, int first,
    214			   int last)
    215{
    216	unsigned long timeout = msecs_to_jiffies(TIMEOUT_MS);
    217	unsigned long flags;
    218
    219	spin_lock_irqsave(&i2c->lock, flags);
    220	i2c->msg = msg;
    221	i2c->msgbuf_ptr = 0;
    222	i2c->last = last;
    223	i2c->error = 0;
    224
    225	reinit_completion(&i2c->done);
    226	dc_i2c_set_irq(i2c, 1);
    227	dc_i2c_start_msg(i2c, first);
    228	spin_unlock_irqrestore(&i2c->lock, flags);
    229
    230	timeout = wait_for_completion_timeout(&i2c->done, timeout);
    231	dc_i2c_set_irq(i2c, 0);
    232	if (timeout == 0) {
    233		i2c->state = STATE_IDLE;
    234		return -ETIMEDOUT;
    235	}
    236
    237	if (i2c->error)
    238		return i2c->error;
    239
    240	return 0;
    241}
    242
    243static int dc_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
    244{
    245	struct dc_i2c *i2c = adap->algo_data;
    246	int i, ret;
    247
    248	for (i = 0; i < num; i++) {
    249		ret = dc_i2c_xfer_msg(i2c, &msgs[i], i == 0, i == num - 1);
    250		if (ret)
    251			return ret;
    252	}
    253
    254	return num;
    255}
    256
    257static int dc_i2c_init_hw(struct dc_i2c *i2c)
    258{
    259	unsigned long clk_rate = clk_get_rate(i2c->clk);
    260	unsigned int clocktime;
    261
    262	writeb_relaxed(II_CONTROL_LOCAL_RESET, i2c->regs + II_CONTROL);
    263	udelay(100);
    264	writeb_relaxed(0, i2c->regs + II_CONTROL);
    265	udelay(100);
    266
    267	clocktime = DIV_ROUND_UP(clk_rate, 64 * i2c->frequency);
    268	if (clocktime < 1 || clocktime > 0xff) {
    269		dev_err(i2c->dev, "can't set bus speed of %u Hz\n",
    270			i2c->frequency);
    271		return -EINVAL;
    272	}
    273	writeb_relaxed(clocktime - 1, i2c->regs + II_CLOCKTIME);
    274
    275	return 0;
    276}
    277
    278static u32 dc_i2c_func(struct i2c_adapter *adap)
    279{
    280	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
    281}
    282
    283static const struct i2c_algorithm dc_i2c_algorithm = {
    284	.master_xfer	= dc_i2c_xfer,
    285	.functionality	= dc_i2c_func,
    286};
    287
    288static int dc_i2c_probe(struct platform_device *pdev)
    289{
    290	struct device_node *np = pdev->dev.of_node;
    291	struct dc_i2c *i2c;
    292	int ret = 0, irq;
    293
    294	i2c = devm_kzalloc(&pdev->dev, sizeof(struct dc_i2c), GFP_KERNEL);
    295	if (!i2c)
    296		return -ENOMEM;
    297
    298	if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
    299				 &i2c->frequency))
    300		i2c->frequency = I2C_MAX_STANDARD_MODE_FREQ;
    301
    302	i2c->dev = &pdev->dev;
    303	platform_set_drvdata(pdev, i2c);
    304
    305	spin_lock_init(&i2c->lock);
    306	init_completion(&i2c->done);
    307
    308	i2c->clk = devm_clk_get(&pdev->dev, NULL);
    309	if (IS_ERR(i2c->clk))
    310		return PTR_ERR(i2c->clk);
    311
    312	i2c->regs = devm_platform_ioremap_resource(pdev, 0);
    313	if (IS_ERR(i2c->regs))
    314		return PTR_ERR(i2c->regs);
    315
    316	irq = platform_get_irq(pdev, 0);
    317	if (irq < 0)
    318		return irq;
    319
    320	ret = devm_request_irq(&pdev->dev, irq, dc_i2c_irq, 0,
    321			       dev_name(&pdev->dev), i2c);
    322	if (ret < 0)
    323		return ret;
    324
    325	strlcpy(i2c->adap.name, "Conexant Digicolor I2C adapter",
    326		sizeof(i2c->adap.name));
    327	i2c->adap.owner = THIS_MODULE;
    328	i2c->adap.algo = &dc_i2c_algorithm;
    329	i2c->adap.dev.parent = &pdev->dev;
    330	i2c->adap.dev.of_node = np;
    331	i2c->adap.algo_data = i2c;
    332
    333	ret = dc_i2c_init_hw(i2c);
    334	if (ret)
    335		return ret;
    336
    337	ret = clk_prepare_enable(i2c->clk);
    338	if (ret < 0)
    339		return ret;
    340
    341	ret = i2c_add_adapter(&i2c->adap);
    342	if (ret < 0) {
    343		clk_disable_unprepare(i2c->clk);
    344		return ret;
    345	}
    346
    347	return 0;
    348}
    349
    350static int dc_i2c_remove(struct platform_device *pdev)
    351{
    352	struct dc_i2c *i2c = platform_get_drvdata(pdev);
    353
    354	i2c_del_adapter(&i2c->adap);
    355	clk_disable_unprepare(i2c->clk);
    356
    357	return 0;
    358}
    359
    360static const struct of_device_id dc_i2c_match[] = {
    361	{ .compatible = "cnxt,cx92755-i2c" },
    362	{ },
    363};
    364MODULE_DEVICE_TABLE(of, dc_i2c_match);
    365
    366static struct platform_driver dc_i2c_driver = {
    367	.probe   = dc_i2c_probe,
    368	.remove  = dc_i2c_remove,
    369	.driver  = {
    370		.name  = "digicolor-i2c",
    371		.of_match_table = dc_i2c_match,
    372	},
    373};
    374module_platform_driver(dc_i2c_driver);
    375
    376MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
    377MODULE_DESCRIPTION("Conexant Digicolor I2C master driver");
    378MODULE_LICENSE("GPL v2");