cx88-vp3054-i2c.c (3519B)
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);