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

stk1160-i2c.c (5859B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * STK1160 driver
      4 *
      5 * Copyright (C) 2012 Ezequiel Garcia
      6 * <elezegarcia--a.t--gmail.com>
      7 *
      8 * Based on Easycap driver by R.M. Thomas
      9 *	Copyright (C) 2010 R.M. Thomas
     10 *	<rmthomas--a.t--sciolus.org>
     11 */
     12
     13#include <linux/module.h>
     14#include <linux/usb.h>
     15#include <linux/i2c.h>
     16
     17#include "stk1160.h"
     18#include "stk1160-reg.h"
     19
     20static unsigned int i2c_debug;
     21module_param(i2c_debug, int, 0644);
     22MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
     23
     24#define dprintk_i2c(fmt, args...)				\
     25do {								\
     26	if (i2c_debug)						\
     27		printk(KERN_DEBUG fmt, ##args);			\
     28} while (0)
     29
     30static int stk1160_i2c_busy_wait(struct stk1160 *dev, u8 wait_bit_mask)
     31{
     32	unsigned long end;
     33	u8 flag;
     34
     35	/* Wait until read/write finish bit is set */
     36	end = jiffies + msecs_to_jiffies(STK1160_I2C_TIMEOUT);
     37	while (time_is_after_jiffies(end)) {
     38
     39		stk1160_read_reg(dev, STK1160_SICTL+1, &flag);
     40		/* read/write done? */
     41		if (flag & wait_bit_mask)
     42			goto done;
     43
     44		usleep_range(10 * USEC_PER_MSEC, 20 * USEC_PER_MSEC);
     45	}
     46
     47	return -ETIMEDOUT;
     48
     49done:
     50	return 0;
     51}
     52
     53static int stk1160_i2c_write_reg(struct stk1160 *dev, u8 addr,
     54		u8 reg, u8 value)
     55{
     56	int rc;
     57
     58	/* Set serial device address */
     59	rc = stk1160_write_reg(dev, STK1160_SICTL_SDA, addr);
     60	if (rc < 0)
     61		return rc;
     62
     63	/* Set i2c device register sub-address */
     64	rc = stk1160_write_reg(dev, STK1160_SBUSW_WA, reg);
     65	if (rc < 0)
     66		return rc;
     67
     68	/* Set i2c device register value */
     69	rc = stk1160_write_reg(dev, STK1160_SBUSW_WD, value);
     70	if (rc < 0)
     71		return rc;
     72
     73	/* Start write now */
     74	rc = stk1160_write_reg(dev, STK1160_SICTL, 0x01);
     75	if (rc < 0)
     76		return rc;
     77
     78	rc = stk1160_i2c_busy_wait(dev, 0x04);
     79	if (rc < 0)
     80		return rc;
     81
     82	return 0;
     83}
     84
     85static int stk1160_i2c_read_reg(struct stk1160 *dev, u8 addr,
     86		u8 reg, u8 *value)
     87{
     88	int rc;
     89
     90	/* Set serial device address */
     91	rc = stk1160_write_reg(dev, STK1160_SICTL_SDA, addr);
     92	if (rc < 0)
     93		return rc;
     94
     95	/* Set i2c device register sub-address */
     96	rc = stk1160_write_reg(dev, STK1160_SBUSR_RA, reg);
     97	if (rc < 0)
     98		return rc;
     99
    100	/* Start read now */
    101	rc = stk1160_write_reg(dev, STK1160_SICTL, 0x20);
    102	if (rc < 0)
    103		return rc;
    104
    105	rc = stk1160_i2c_busy_wait(dev, 0x01);
    106	if (rc < 0)
    107		return rc;
    108
    109	rc = stk1160_read_reg(dev, STK1160_SBUSR_RD, value);
    110	if (rc < 0)
    111		return rc;
    112
    113	return 0;
    114}
    115
    116/*
    117 * stk1160_i2c_check_for_device()
    118 * check if there is a i2c_device at the supplied address
    119 */
    120static int stk1160_i2c_check_for_device(struct stk1160 *dev,
    121		unsigned char addr)
    122{
    123	int rc;
    124
    125	/* Set serial device address */
    126	rc = stk1160_write_reg(dev, STK1160_SICTL_SDA, addr);
    127	if (rc < 0)
    128		return rc;
    129
    130	/* Set device sub-address, we'll chip version reg */
    131	rc = stk1160_write_reg(dev, STK1160_SBUSR_RA, 0x00);
    132	if (rc < 0)
    133		return rc;
    134
    135	/* Start read now */
    136	rc = stk1160_write_reg(dev, STK1160_SICTL, 0x20);
    137	if (rc < 0)
    138		return rc;
    139
    140	rc = stk1160_i2c_busy_wait(dev, 0x01);
    141	if (rc < 0)
    142		return -ENODEV;
    143
    144	return 0;
    145}
    146
    147/*
    148 * stk1160_i2c_xfer()
    149 * the main i2c transfer function
    150 */
    151static int stk1160_i2c_xfer(struct i2c_adapter *i2c_adap,
    152			   struct i2c_msg msgs[], int num)
    153{
    154	struct stk1160 *dev = i2c_adap->algo_data;
    155	int addr, rc, i;
    156
    157	for (i = 0; i < num; i++) {
    158		addr = msgs[i].addr << 1;
    159		dprintk_i2c("%s: addr=%x", __func__, addr);
    160
    161		if (!msgs[i].len) {
    162			/* no len: check only for device presence */
    163			rc = stk1160_i2c_check_for_device(dev, addr);
    164			if (rc < 0) {
    165				dprintk_i2c(" no device\n");
    166				return rc;
    167			}
    168
    169		} else if (msgs[i].flags & I2C_M_RD) {
    170			/* read request without preceding register selection */
    171			dprintk_i2c(" subaddr not selected");
    172			rc = -EOPNOTSUPP;
    173			goto err;
    174
    175		} else if (i + 1 < num && msgs[i].len <= 2 &&
    176			   (msgs[i + 1].flags & I2C_M_RD) &&
    177			   msgs[i].addr == msgs[i + 1].addr) {
    178
    179			if (msgs[i].len != 1 || msgs[i + 1].len != 1) {
    180				dprintk_i2c(" len not supported");
    181				rc = -EOPNOTSUPP;
    182				goto err;
    183			}
    184
    185			dprintk_i2c(" subaddr=%x", msgs[i].buf[0]);
    186
    187			rc = stk1160_i2c_read_reg(dev, addr, msgs[i].buf[0],
    188				msgs[i + 1].buf);
    189
    190			dprintk_i2c(" read=%x", *msgs[i + 1].buf);
    191
    192			/* consumed two msgs, so we skip one of them */
    193			i++;
    194
    195		} else {
    196			if (msgs[i].len != 2) {
    197				dprintk_i2c(" len not supported");
    198				rc = -EOPNOTSUPP;
    199				goto err;
    200			}
    201
    202			dprintk_i2c(" subaddr=%x write=%x",
    203				msgs[i].buf[0],  msgs[i].buf[1]);
    204
    205			rc = stk1160_i2c_write_reg(dev, addr, msgs[i].buf[0],
    206				msgs[i].buf[1]);
    207		}
    208
    209		if (rc < 0)
    210			goto err;
    211		dprintk_i2c(" OK\n");
    212	}
    213
    214	return num;
    215err:
    216	dprintk_i2c(" ERROR: %d\n", rc);
    217	return num;
    218}
    219
    220/*
    221 * functionality(), what da heck is this?
    222 */
    223static u32 functionality(struct i2c_adapter *adap)
    224{
    225	return I2C_FUNC_SMBUS_EMUL;
    226}
    227
    228static const struct i2c_algorithm algo = {
    229	.master_xfer   = stk1160_i2c_xfer,
    230	.functionality = functionality,
    231};
    232
    233static const struct i2c_adapter adap_template = {
    234	.owner = THIS_MODULE,
    235	.name = "stk1160",
    236	.algo = &algo,
    237};
    238
    239static const struct i2c_client client_template = {
    240	.name = "stk1160 internal",
    241};
    242
    243/*
    244 * stk1160_i2c_register()
    245 * register i2c bus
    246 */
    247int stk1160_i2c_register(struct stk1160 *dev)
    248{
    249	int rc;
    250
    251	dev->i2c_adap = adap_template;
    252	dev->i2c_adap.dev.parent = dev->dev;
    253	strscpy(dev->i2c_adap.name, "stk1160", sizeof(dev->i2c_adap.name));
    254	dev->i2c_adap.algo_data = dev;
    255
    256	i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
    257
    258	rc = i2c_add_adapter(&dev->i2c_adap);
    259	if (rc < 0) {
    260		stk1160_err("cannot add i2c adapter (%d)\n", rc);
    261		return rc;
    262	}
    263
    264	dev->i2c_client = client_template;
    265	dev->i2c_client.adapter = &dev->i2c_adap;
    266
    267	/* Set i2c clock divider device address */
    268	stk1160_write_reg(dev, STK1160_SICTL_CD,  0x0f);
    269
    270	/* ??? */
    271	stk1160_write_reg(dev, STK1160_ASIC + 3,  0x00);
    272
    273	return 0;
    274}
    275
    276/*
    277 * stk1160_i2c_unregister()
    278 * unregister i2c_bus
    279 */
    280int stk1160_i2c_unregister(struct stk1160 *dev)
    281{
    282	i2c_del_adapter(&dev->i2c_adap);
    283	return 0;
    284}