285 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * STK1160 driver4 *5 * Copyright (C) 2012 Ezequiel Garcia6 * <elezegarcia--a.t--gmail.com>7 *8 * Based on Easycap driver by R.M. Thomas9 * Copyright (C) 2010 R.M. Thomas10 * <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 address119 */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 function150 */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 bus246 */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_bus279 */280int stk1160_i2c_unregister(struct stk1160 *dev)281{282 i2c_del_adapter(&dev->i2c_adap);283 return 0;284}285