162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * STK1160 driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2012 Ezequiel Garcia 662306a36Sopenharmony_ci * <elezegarcia--a.t--gmail.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Based on Easycap driver by R.M. Thomas 962306a36Sopenharmony_ci * Copyright (C) 2010 R.M. Thomas 1062306a36Sopenharmony_ci * <rmthomas--a.t--sciolus.org> 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/usb.h> 1562306a36Sopenharmony_ci#include <linux/i2c.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "stk1160.h" 1862306a36Sopenharmony_ci#include "stk1160-reg.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic unsigned int i2c_debug; 2162306a36Sopenharmony_cimodule_param(i2c_debug, int, 0644); 2262306a36Sopenharmony_ciMODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define dprintk_i2c(fmt, args...) \ 2562306a36Sopenharmony_cido { \ 2662306a36Sopenharmony_ci if (i2c_debug) \ 2762306a36Sopenharmony_ci printk(KERN_DEBUG fmt, ##args); \ 2862306a36Sopenharmony_ci} while (0) 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic int stk1160_i2c_busy_wait(struct stk1160 *dev, u8 wait_bit_mask) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci unsigned long end; 3362306a36Sopenharmony_ci u8 flag; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci /* Wait until read/write finish bit is set */ 3662306a36Sopenharmony_ci end = jiffies + msecs_to_jiffies(STK1160_I2C_TIMEOUT); 3762306a36Sopenharmony_ci while (time_is_after_jiffies(end)) { 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci stk1160_read_reg(dev, STK1160_SICTL+1, &flag); 4062306a36Sopenharmony_ci /* read/write done? */ 4162306a36Sopenharmony_ci if (flag & wait_bit_mask) 4262306a36Sopenharmony_ci goto done; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci usleep_range(10 * USEC_PER_MSEC, 20 * USEC_PER_MSEC); 4562306a36Sopenharmony_ci } 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci return -ETIMEDOUT; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cidone: 5062306a36Sopenharmony_ci return 0; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic int stk1160_i2c_write_reg(struct stk1160 *dev, u8 addr, 5462306a36Sopenharmony_ci u8 reg, u8 value) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci int rc; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci /* Set serial device address */ 5962306a36Sopenharmony_ci rc = stk1160_write_reg(dev, STK1160_SICTL_SDA, addr); 6062306a36Sopenharmony_ci if (rc < 0) 6162306a36Sopenharmony_ci return rc; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci /* Set i2c device register sub-address */ 6462306a36Sopenharmony_ci rc = stk1160_write_reg(dev, STK1160_SBUSW_WA, reg); 6562306a36Sopenharmony_ci if (rc < 0) 6662306a36Sopenharmony_ci return rc; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci /* Set i2c device register value */ 6962306a36Sopenharmony_ci rc = stk1160_write_reg(dev, STK1160_SBUSW_WD, value); 7062306a36Sopenharmony_ci if (rc < 0) 7162306a36Sopenharmony_ci return rc; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci /* Start write now */ 7462306a36Sopenharmony_ci rc = stk1160_write_reg(dev, STK1160_SICTL, 0x01); 7562306a36Sopenharmony_ci if (rc < 0) 7662306a36Sopenharmony_ci return rc; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci rc = stk1160_i2c_busy_wait(dev, 0x04); 7962306a36Sopenharmony_ci if (rc < 0) 8062306a36Sopenharmony_ci return rc; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci return 0; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic int stk1160_i2c_read_reg(struct stk1160 *dev, u8 addr, 8662306a36Sopenharmony_ci u8 reg, u8 *value) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci int rc; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci /* Set serial device address */ 9162306a36Sopenharmony_ci rc = stk1160_write_reg(dev, STK1160_SICTL_SDA, addr); 9262306a36Sopenharmony_ci if (rc < 0) 9362306a36Sopenharmony_ci return rc; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci /* Set i2c device register sub-address */ 9662306a36Sopenharmony_ci rc = stk1160_write_reg(dev, STK1160_SBUSR_RA, reg); 9762306a36Sopenharmony_ci if (rc < 0) 9862306a36Sopenharmony_ci return rc; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci /* Start read now */ 10162306a36Sopenharmony_ci rc = stk1160_write_reg(dev, STK1160_SICTL, 0x20); 10262306a36Sopenharmony_ci if (rc < 0) 10362306a36Sopenharmony_ci return rc; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci rc = stk1160_i2c_busy_wait(dev, 0x01); 10662306a36Sopenharmony_ci if (rc < 0) 10762306a36Sopenharmony_ci return rc; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci rc = stk1160_read_reg(dev, STK1160_SBUSR_RD, value); 11062306a36Sopenharmony_ci if (rc < 0) 11162306a36Sopenharmony_ci return rc; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return 0; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci/* 11762306a36Sopenharmony_ci * stk1160_i2c_check_for_device() 11862306a36Sopenharmony_ci * check if there is a i2c_device at the supplied address 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_cistatic int stk1160_i2c_check_for_device(struct stk1160 *dev, 12162306a36Sopenharmony_ci unsigned char addr) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci int rc; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* Set serial device address */ 12662306a36Sopenharmony_ci rc = stk1160_write_reg(dev, STK1160_SICTL_SDA, addr); 12762306a36Sopenharmony_ci if (rc < 0) 12862306a36Sopenharmony_ci return rc; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* Set device sub-address, we'll chip version reg */ 13162306a36Sopenharmony_ci rc = stk1160_write_reg(dev, STK1160_SBUSR_RA, 0x00); 13262306a36Sopenharmony_ci if (rc < 0) 13362306a36Sopenharmony_ci return rc; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci /* Start read now */ 13662306a36Sopenharmony_ci rc = stk1160_write_reg(dev, STK1160_SICTL, 0x20); 13762306a36Sopenharmony_ci if (rc < 0) 13862306a36Sopenharmony_ci return rc; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci rc = stk1160_i2c_busy_wait(dev, 0x01); 14162306a36Sopenharmony_ci if (rc < 0) 14262306a36Sopenharmony_ci return -ENODEV; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci return 0; 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci/* 14862306a36Sopenharmony_ci * stk1160_i2c_xfer() 14962306a36Sopenharmony_ci * the main i2c transfer function 15062306a36Sopenharmony_ci */ 15162306a36Sopenharmony_cistatic int stk1160_i2c_xfer(struct i2c_adapter *i2c_adap, 15262306a36Sopenharmony_ci struct i2c_msg msgs[], int num) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci struct stk1160 *dev = i2c_adap->algo_data; 15562306a36Sopenharmony_ci int addr, rc, i; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci for (i = 0; i < num; i++) { 15862306a36Sopenharmony_ci addr = msgs[i].addr << 1; 15962306a36Sopenharmony_ci dprintk_i2c("%s: addr=%x", __func__, addr); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (!msgs[i].len) { 16262306a36Sopenharmony_ci /* no len: check only for device presence */ 16362306a36Sopenharmony_ci rc = stk1160_i2c_check_for_device(dev, addr); 16462306a36Sopenharmony_ci if (rc < 0) { 16562306a36Sopenharmony_ci dprintk_i2c(" no device\n"); 16662306a36Sopenharmony_ci return rc; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci } else if (msgs[i].flags & I2C_M_RD) { 17062306a36Sopenharmony_ci /* read request without preceding register selection */ 17162306a36Sopenharmony_ci dprintk_i2c(" subaddr not selected"); 17262306a36Sopenharmony_ci rc = -EOPNOTSUPP; 17362306a36Sopenharmony_ci goto err; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci } else if (i + 1 < num && msgs[i].len <= 2 && 17662306a36Sopenharmony_ci (msgs[i + 1].flags & I2C_M_RD) && 17762306a36Sopenharmony_ci msgs[i].addr == msgs[i + 1].addr) { 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci if (msgs[i].len != 1 || msgs[i + 1].len != 1) { 18062306a36Sopenharmony_ci dprintk_i2c(" len not supported"); 18162306a36Sopenharmony_ci rc = -EOPNOTSUPP; 18262306a36Sopenharmony_ci goto err; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci dprintk_i2c(" subaddr=%x", msgs[i].buf[0]); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci rc = stk1160_i2c_read_reg(dev, addr, msgs[i].buf[0], 18862306a36Sopenharmony_ci msgs[i + 1].buf); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci dprintk_i2c(" read=%x", *msgs[i + 1].buf); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci /* consumed two msgs, so we skip one of them */ 19362306a36Sopenharmony_ci i++; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci } else { 19662306a36Sopenharmony_ci if (msgs[i].len != 2) { 19762306a36Sopenharmony_ci dprintk_i2c(" len not supported"); 19862306a36Sopenharmony_ci rc = -EOPNOTSUPP; 19962306a36Sopenharmony_ci goto err; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci dprintk_i2c(" subaddr=%x write=%x", 20362306a36Sopenharmony_ci msgs[i].buf[0], msgs[i].buf[1]); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci rc = stk1160_i2c_write_reg(dev, addr, msgs[i].buf[0], 20662306a36Sopenharmony_ci msgs[i].buf[1]); 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (rc < 0) 21062306a36Sopenharmony_ci goto err; 21162306a36Sopenharmony_ci dprintk_i2c(" OK\n"); 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci return num; 21562306a36Sopenharmony_cierr: 21662306a36Sopenharmony_ci dprintk_i2c(" ERROR: %d\n", rc); 21762306a36Sopenharmony_ci return num; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci/* 22162306a36Sopenharmony_ci * functionality(), what da heck is this? 22262306a36Sopenharmony_ci */ 22362306a36Sopenharmony_cistatic u32 functionality(struct i2c_adapter *adap) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci return I2C_FUNC_SMBUS_EMUL; 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic const struct i2c_algorithm algo = { 22962306a36Sopenharmony_ci .master_xfer = stk1160_i2c_xfer, 23062306a36Sopenharmony_ci .functionality = functionality, 23162306a36Sopenharmony_ci}; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic const struct i2c_adapter adap_template = { 23462306a36Sopenharmony_ci .owner = THIS_MODULE, 23562306a36Sopenharmony_ci .name = "stk1160", 23662306a36Sopenharmony_ci .algo = &algo, 23762306a36Sopenharmony_ci}; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic const struct i2c_client client_template = { 24062306a36Sopenharmony_ci .name = "stk1160 internal", 24162306a36Sopenharmony_ci}; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci/* 24462306a36Sopenharmony_ci * stk1160_i2c_register() 24562306a36Sopenharmony_ci * register i2c bus 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_ciint stk1160_i2c_register(struct stk1160 *dev) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci int rc; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci dev->i2c_adap = adap_template; 25262306a36Sopenharmony_ci dev->i2c_adap.dev.parent = dev->dev; 25362306a36Sopenharmony_ci strscpy(dev->i2c_adap.name, "stk1160", sizeof(dev->i2c_adap.name)); 25462306a36Sopenharmony_ci dev->i2c_adap.algo_data = dev; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci rc = i2c_add_adapter(&dev->i2c_adap); 25962306a36Sopenharmony_ci if (rc < 0) { 26062306a36Sopenharmony_ci stk1160_err("cannot add i2c adapter (%d)\n", rc); 26162306a36Sopenharmony_ci return rc; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci dev->i2c_client = client_template; 26562306a36Sopenharmony_ci dev->i2c_client.adapter = &dev->i2c_adap; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci /* Set i2c clock divider device address */ 26862306a36Sopenharmony_ci stk1160_write_reg(dev, STK1160_SICTL_CD, 0x0f); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* ??? */ 27162306a36Sopenharmony_ci stk1160_write_reg(dev, STK1160_ASIC + 3, 0x00); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci return 0; 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci/* 27762306a36Sopenharmony_ci * stk1160_i2c_unregister() 27862306a36Sopenharmony_ci * unregister i2c_bus 27962306a36Sopenharmony_ci */ 28062306a36Sopenharmony_ciint stk1160_i2c_unregister(struct stk1160 *dev) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci i2c_del_adapter(&dev->i2c_adap); 28362306a36Sopenharmony_ci return 0; 28462306a36Sopenharmony_ci} 285