linux/drivers/media/usb/stk1160/stk1160-i2c.c
<<
>>
Prefs
   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}
 285