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

au0828-i2c.c (9062B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Driver for the Auvitek AU0828 USB bridge
      4 *
      5 *  Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
      6 */
      7
      8#include "au0828.h"
      9
     10#include <linux/module.h>
     11#include <linux/moduleparam.h>
     12#include <linux/init.h>
     13#include <linux/delay.h>
     14#include <linux/io.h>
     15
     16#include "media/tuner.h"
     17#include <media/v4l2-common.h>
     18
     19static int i2c_scan;
     20module_param(i2c_scan, int, 0444);
     21MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
     22
     23#define I2C_WAIT_DELAY 25
     24#define I2C_WAIT_RETRY 1000
     25
     26static inline int i2c_slave_did_read_ack(struct i2c_adapter *i2c_adap)
     27{
     28	struct au0828_dev *dev = i2c_adap->algo_data;
     29	return au0828_read(dev, AU0828_I2C_STATUS_201) &
     30		AU0828_I2C_STATUS_NO_READ_ACK ? 0 : 1;
     31}
     32
     33static int i2c_wait_read_ack(struct i2c_adapter *i2c_adap)
     34{
     35	int count;
     36
     37	for (count = 0; count < I2C_WAIT_RETRY; count++) {
     38		if (!i2c_slave_did_read_ack(i2c_adap))
     39			break;
     40		udelay(I2C_WAIT_DELAY);
     41	}
     42
     43	if (I2C_WAIT_RETRY == count)
     44		return 0;
     45
     46	return 1;
     47}
     48
     49static inline int i2c_is_read_busy(struct i2c_adapter *i2c_adap)
     50{
     51	struct au0828_dev *dev = i2c_adap->algo_data;
     52	return au0828_read(dev, AU0828_I2C_STATUS_201) &
     53		AU0828_I2C_STATUS_READ_DONE ? 0 : 1;
     54}
     55
     56static int i2c_wait_read_done(struct i2c_adapter *i2c_adap)
     57{
     58	int count;
     59
     60	for (count = 0; count < I2C_WAIT_RETRY; count++) {
     61		if (!i2c_is_read_busy(i2c_adap))
     62			break;
     63		udelay(I2C_WAIT_DELAY);
     64	}
     65
     66	if (I2C_WAIT_RETRY == count)
     67		return 0;
     68
     69	return 1;
     70}
     71
     72static inline int i2c_is_write_done(struct i2c_adapter *i2c_adap)
     73{
     74	struct au0828_dev *dev = i2c_adap->algo_data;
     75	return au0828_read(dev, AU0828_I2C_STATUS_201) &
     76		AU0828_I2C_STATUS_WRITE_DONE ? 1 : 0;
     77}
     78
     79static int i2c_wait_write_done(struct i2c_adapter *i2c_adap)
     80{
     81	int count;
     82
     83	for (count = 0; count < I2C_WAIT_RETRY; count++) {
     84		if (i2c_is_write_done(i2c_adap))
     85			break;
     86		udelay(I2C_WAIT_DELAY);
     87	}
     88
     89	if (I2C_WAIT_RETRY == count)
     90		return 0;
     91
     92	return 1;
     93}
     94
     95static inline int i2c_is_busy(struct i2c_adapter *i2c_adap)
     96{
     97	struct au0828_dev *dev = i2c_adap->algo_data;
     98	return au0828_read(dev, AU0828_I2C_STATUS_201) &
     99		AU0828_I2C_STATUS_BUSY ? 1 : 0;
    100}
    101
    102static int i2c_wait_done(struct i2c_adapter *i2c_adap)
    103{
    104	int count;
    105
    106	for (count = 0; count < I2C_WAIT_RETRY; count++) {
    107		if (!i2c_is_busy(i2c_adap))
    108			break;
    109		udelay(I2C_WAIT_DELAY);
    110	}
    111
    112	if (I2C_WAIT_RETRY == count)
    113		return 0;
    114
    115	return 1;
    116}
    117
    118/* FIXME: Implement join handling correctly */
    119static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
    120	const struct i2c_msg *msg, int joined_rlen)
    121{
    122	int i, strobe = 0;
    123	struct au0828_dev *dev = i2c_adap->algo_data;
    124	u8 i2c_speed = dev->board.i2c_clk_divider;
    125
    126	dprintk(4, "%s()\n", __func__);
    127
    128	au0828_write(dev, AU0828_I2C_MULTIBYTE_MODE_2FF, 0x01);
    129
    130	if (((dev->board.tuner_type == TUNER_XC5000) ||
    131	     (dev->board.tuner_type == TUNER_XC5000C)) &&
    132	    (dev->board.tuner_addr == msg->addr)) {
    133		/*
    134		 * Due to I2C clock stretch, we need to use a lower speed
    135		 * on xc5000 for commands. However, firmware transfer can
    136		 * speed up to 400 KHz.
    137		 */
    138		if (msg->len == 64)
    139			i2c_speed = AU0828_I2C_CLK_250KHZ;
    140		else
    141			i2c_speed = AU0828_I2C_CLK_20KHZ;
    142	}
    143	/* Set the I2C clock */
    144	au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202, i2c_speed);
    145
    146	/* Hardware needs 8 bit addresses */
    147	au0828_write(dev, AU0828_I2C_DEST_ADDR_203, msg->addr << 1);
    148
    149	dprintk(4, "SEND: %02x\n", msg->addr);
    150
    151	/* Deal with i2c_scan */
    152	if (msg->len == 0) {
    153		/* The analog tuner detection code makes use of the SMBUS_QUICK
    154		   message (which involves a zero length i2c write).  To avoid
    155		   checking the status register when we didn't strobe out any
    156		   actual bytes to the bus, just do a read check.  This is
    157		   consistent with how I saw i2c device checking done in the
    158		   USB trace of the Windows driver */
    159		au0828_write(dev, AU0828_I2C_TRIGGER_200,
    160			     AU0828_I2C_TRIGGER_READ);
    161
    162		if (!i2c_wait_done(i2c_adap))
    163			return -EIO;
    164
    165		if (i2c_wait_read_ack(i2c_adap))
    166			return -EIO;
    167
    168		return 0;
    169	}
    170
    171	for (i = 0; i < msg->len;) {
    172
    173		dprintk(4, " %02x\n", msg->buf[i]);
    174
    175		au0828_write(dev, AU0828_I2C_WRITE_FIFO_205, msg->buf[i]);
    176
    177		strobe++;
    178		i++;
    179
    180		if ((strobe >= 4) || (i >= msg->len)) {
    181
    182			/* Strobe the byte into the bus */
    183			if (i < msg->len)
    184				au0828_write(dev, AU0828_I2C_TRIGGER_200,
    185					     AU0828_I2C_TRIGGER_WRITE |
    186					     AU0828_I2C_TRIGGER_HOLD);
    187			else
    188				au0828_write(dev, AU0828_I2C_TRIGGER_200,
    189					     AU0828_I2C_TRIGGER_WRITE);
    190
    191			/* Reset strobe trigger */
    192			strobe = 0;
    193
    194			if (!i2c_wait_write_done(i2c_adap))
    195				return -EIO;
    196
    197		}
    198
    199	}
    200	if (!i2c_wait_done(i2c_adap))
    201		return -EIO;
    202
    203	dprintk(4, "\n");
    204
    205	return msg->len;
    206}
    207
    208/* FIXME: Implement join handling correctly */
    209static int i2c_readbytes(struct i2c_adapter *i2c_adap,
    210	const struct i2c_msg *msg, int joined)
    211{
    212	struct au0828_dev *dev = i2c_adap->algo_data;
    213	u8 i2c_speed = dev->board.i2c_clk_divider;
    214	int i;
    215
    216	dprintk(4, "%s()\n", __func__);
    217
    218	au0828_write(dev, AU0828_I2C_MULTIBYTE_MODE_2FF, 0x01);
    219
    220	/*
    221	 * Due to xc5000c clock stretch, we cannot use full speed at
    222	 * readings from xc5000, as otherwise they'll fail.
    223	 */
    224	if (((dev->board.tuner_type == TUNER_XC5000) ||
    225	     (dev->board.tuner_type == TUNER_XC5000C)) &&
    226	    (dev->board.tuner_addr == msg->addr))
    227		i2c_speed = AU0828_I2C_CLK_20KHZ;
    228
    229	/* Set the I2C clock */
    230	au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202, i2c_speed);
    231
    232	/* Hardware needs 8 bit addresses */
    233	au0828_write(dev, AU0828_I2C_DEST_ADDR_203, msg->addr << 1);
    234
    235	dprintk(4, " RECV:\n");
    236
    237	/* Deal with i2c_scan */
    238	if (msg->len == 0) {
    239		au0828_write(dev, AU0828_I2C_TRIGGER_200,
    240			     AU0828_I2C_TRIGGER_READ);
    241
    242		if (i2c_wait_read_ack(i2c_adap))
    243			return -EIO;
    244		return 0;
    245	}
    246
    247	for (i = 0; i < msg->len;) {
    248
    249		i++;
    250
    251		if (i < msg->len)
    252			au0828_write(dev, AU0828_I2C_TRIGGER_200,
    253				     AU0828_I2C_TRIGGER_READ |
    254				     AU0828_I2C_TRIGGER_HOLD);
    255		else
    256			au0828_write(dev, AU0828_I2C_TRIGGER_200,
    257				     AU0828_I2C_TRIGGER_READ);
    258
    259		if (!i2c_wait_read_done(i2c_adap))
    260			return -EIO;
    261
    262		msg->buf[i-1] = au0828_read(dev, AU0828_I2C_READ_FIFO_209) &
    263			0xff;
    264
    265		dprintk(4, " %02x\n", msg->buf[i-1]);
    266	}
    267	if (!i2c_wait_done(i2c_adap))
    268		return -EIO;
    269
    270	dprintk(4, "\n");
    271
    272	return msg->len;
    273}
    274
    275static int i2c_xfer(struct i2c_adapter *i2c_adap,
    276		    struct i2c_msg *msgs, int num)
    277{
    278	int i, retval = 0;
    279
    280	dprintk(4, "%s(num = %d)\n", __func__, num);
    281
    282	for (i = 0; i < num; i++) {
    283		dprintk(4, "%s(num = %d) addr = 0x%02x  len = 0x%x\n",
    284			__func__, num, msgs[i].addr, msgs[i].len);
    285		if (msgs[i].flags & I2C_M_RD) {
    286			/* read */
    287			retval = i2c_readbytes(i2c_adap, &msgs[i], 0);
    288		} else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&
    289			   msgs[i].addr == msgs[i + 1].addr) {
    290			/* write then read from same address */
    291			retval = i2c_sendbytes(i2c_adap, &msgs[i],
    292					       msgs[i + 1].len);
    293			if (retval < 0)
    294				goto err;
    295			i++;
    296			retval = i2c_readbytes(i2c_adap, &msgs[i], 1);
    297		} else {
    298			/* write */
    299			retval = i2c_sendbytes(i2c_adap, &msgs[i], 0);
    300		}
    301		if (retval < 0)
    302			goto err;
    303	}
    304	return num;
    305
    306err:
    307	return retval;
    308}
    309
    310static u32 au0828_functionality(struct i2c_adapter *adap)
    311{
    312	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
    313}
    314
    315static const struct i2c_algorithm au0828_i2c_algo_template = {
    316	.master_xfer	= i2c_xfer,
    317	.functionality	= au0828_functionality,
    318};
    319
    320/* ----------------------------------------------------------------------- */
    321
    322static const struct i2c_adapter au0828_i2c_adap_template = {
    323	.name              = KBUILD_MODNAME,
    324	.owner             = THIS_MODULE,
    325	.algo              = &au0828_i2c_algo_template,
    326};
    327
    328static const struct i2c_client au0828_i2c_client_template = {
    329	.name	= "au0828 internal",
    330};
    331
    332static char *i2c_devs[128] = {
    333	[0x8e >> 1] = "au8522",
    334	[0xa0 >> 1] = "eeprom",
    335	[0xc2 >> 1] = "tuner/xc5000",
    336};
    337
    338static void do_i2c_scan(char *name, struct i2c_client *c)
    339{
    340	unsigned char buf;
    341	int i, rc;
    342
    343	for (i = 0; i < 128; i++) {
    344		c->addr = i;
    345		rc = i2c_master_recv(c, &buf, 0);
    346		if (rc < 0)
    347			continue;
    348		pr_info("%s: i2c scan: found device @ 0x%x  [%s]\n",
    349		       name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
    350	}
    351}
    352
    353/* init + register i2c adapter */
    354int au0828_i2c_register(struct au0828_dev *dev)
    355{
    356	dprintk(1, "%s()\n", __func__);
    357
    358	dev->i2c_adap = au0828_i2c_adap_template;
    359	dev->i2c_algo = au0828_i2c_algo_template;
    360	dev->i2c_client = au0828_i2c_client_template;
    361
    362	dev->i2c_adap.dev.parent = &dev->usbdev->dev;
    363
    364	strscpy(dev->i2c_adap.name, KBUILD_MODNAME,
    365		sizeof(dev->i2c_adap.name));
    366
    367	dev->i2c_adap.algo = &dev->i2c_algo;
    368	dev->i2c_adap.algo_data = dev;
    369#ifdef CONFIG_VIDEO_AU0828_V4L2
    370	i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
    371#else
    372	i2c_set_adapdata(&dev->i2c_adap, dev);
    373#endif
    374	i2c_add_adapter(&dev->i2c_adap);
    375
    376	dev->i2c_client.adapter = &dev->i2c_adap;
    377
    378	if (0 == dev->i2c_rc) {
    379		pr_info("i2c bus registered\n");
    380		if (i2c_scan)
    381			do_i2c_scan(KBUILD_MODNAME, &dev->i2c_client);
    382	} else
    383		pr_info("i2c bus register FAILED\n");
    384
    385	return dev->i2c_rc;
    386}
    387
    388int au0828_i2c_unregister(struct au0828_dev *dev)
    389{
    390	i2c_del_adapter(&dev->i2c_adap);
    391	return 0;
    392}
    393