linux/drivers/media/pci/cx88/cx88-vp3054-i2c.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * cx88-vp3054-i2c.c -- support for the secondary I2C bus of the
   4 *                      DNTV Live! DVB-T Pro (VP-3054), wired as:
   5 *                      GPIO[0] -> SCL, GPIO[1] -> SDA
   6 *
   7 * (c) 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
   8 */
   9
  10#include "cx88.h"
  11#include "cx88-vp3054-i2c.h"
  12
  13#include <linux/module.h>
  14#include <linux/slab.h>
  15#include <linux/init.h>
  16#include <linux/io.h>
  17
  18MODULE_DESCRIPTION("driver for cx2388x VP3054 design");
  19MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
  20MODULE_LICENSE("GPL");
  21
  22/* ----------------------------------------------------------------------- */
  23
  24static void vp3054_bit_setscl(void *data, int state)
  25{
  26        struct cx8802_dev *dev = data;
  27        struct cx88_core *core = dev->core;
  28        struct vp3054_i2c_state *vp3054_i2c = dev->vp3054;
  29
  30        if (state) {
  31                vp3054_i2c->state |=  0x0001;   /* SCL high */
  32                vp3054_i2c->state &= ~0x0100;   /* external pullup */
  33        } else {
  34                vp3054_i2c->state &= ~0x0001;   /* SCL low */
  35                vp3054_i2c->state |=  0x0100;   /* drive pin */
  36        }
  37        cx_write(MO_GP0_IO, 0x010000 | vp3054_i2c->state);
  38        cx_read(MO_GP0_IO);
  39}
  40
  41static void vp3054_bit_setsda(void *data, int state)
  42{
  43        struct cx8802_dev *dev = data;
  44        struct cx88_core *core = dev->core;
  45        struct vp3054_i2c_state *vp3054_i2c = dev->vp3054;
  46
  47        if (state) {
  48                vp3054_i2c->state |=  0x0002;   /* SDA high */
  49                vp3054_i2c->state &= ~0x0200;   /* tristate pin */
  50        } else {
  51                vp3054_i2c->state &= ~0x0002;   /* SDA low */
  52                vp3054_i2c->state |=  0x0200;   /* drive pin */
  53        }
  54        cx_write(MO_GP0_IO, 0x020000 | vp3054_i2c->state);
  55        cx_read(MO_GP0_IO);
  56}
  57
  58static int vp3054_bit_getscl(void *data)
  59{
  60        struct cx8802_dev *dev = data;
  61        struct cx88_core *core = dev->core;
  62        u32 state;
  63
  64        state = cx_read(MO_GP0_IO);
  65        return (state & 0x01) ? 1 : 0;
  66}
  67
  68static int vp3054_bit_getsda(void *data)
  69{
  70        struct cx8802_dev *dev = data;
  71        struct cx88_core *core = dev->core;
  72        u32 state;
  73
  74        state = cx_read(MO_GP0_IO);
  75        return (state & 0x02) ? 1 : 0;
  76}
  77
  78/* ----------------------------------------------------------------------- */
  79
  80static const struct i2c_algo_bit_data vp3054_i2c_algo_template = {
  81        .setsda  = vp3054_bit_setsda,
  82        .setscl  = vp3054_bit_setscl,
  83        .getsda  = vp3054_bit_getsda,
  84        .getscl  = vp3054_bit_getscl,
  85        .udelay  = 16,
  86        .timeout = 200,
  87};
  88
  89/* ----------------------------------------------------------------------- */
  90
  91int vp3054_i2c_probe(struct cx8802_dev *dev)
  92{
  93        struct cx88_core *core = dev->core;
  94        struct vp3054_i2c_state *vp3054_i2c;
  95        int rc;
  96
  97        if (core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
  98                return 0;
  99
 100        vp3054_i2c = kzalloc(sizeof(*vp3054_i2c), GFP_KERNEL);
 101        if (!vp3054_i2c)
 102                return -ENOMEM;
 103        dev->vp3054 = vp3054_i2c;
 104
 105        vp3054_i2c->algo = vp3054_i2c_algo_template;
 106
 107        vp3054_i2c->adap.dev.parent = &dev->pci->dev;
 108        strscpy(vp3054_i2c->adap.name, core->name,
 109                sizeof(vp3054_i2c->adap.name));
 110        vp3054_i2c->adap.owner = THIS_MODULE;
 111        vp3054_i2c->algo.data = dev;
 112        i2c_set_adapdata(&vp3054_i2c->adap, dev);
 113        vp3054_i2c->adap.algo_data = &vp3054_i2c->algo;
 114
 115        vp3054_bit_setscl(dev, 1);
 116        vp3054_bit_setsda(dev, 1);
 117
 118        rc = i2c_bit_add_bus(&vp3054_i2c->adap);
 119        if (rc != 0) {
 120                pr_err("vp3054_i2c register FAILED\n");
 121
 122                kfree(dev->vp3054);
 123                dev->vp3054 = NULL;
 124        }
 125
 126        return rc;
 127}
 128EXPORT_SYMBOL(vp3054_i2c_probe);
 129
 130void vp3054_i2c_remove(struct cx8802_dev *dev)
 131{
 132        struct vp3054_i2c_state *vp3054_i2c = dev->vp3054;
 133
 134        if (!vp3054_i2c ||
 135            dev->core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
 136                return;
 137
 138        i2c_del_adapter(&vp3054_i2c->adap);
 139        kfree(vp3054_i2c);
 140}
 141EXPORT_SYMBOL(vp3054_i2c_remove);
 142