Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * cx88-vp3054-i2c.c -- support for the secondary I2C bus of the
0004  *          DNTV Live! DVB-T Pro (VP-3054), wired as:
0005  *          GPIO[0] -> SCL, GPIO[1] -> SDA
0006  *
0007  * (c) 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
0008  */
0009 
0010 #include "cx88.h"
0011 #include "cx88-vp3054-i2c.h"
0012 
0013 #include <linux/module.h>
0014 #include <linux/slab.h>
0015 #include <linux/init.h>
0016 #include <linux/io.h>
0017 
0018 MODULE_DESCRIPTION("driver for cx2388x VP3054 design");
0019 MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
0020 MODULE_LICENSE("GPL");
0021 
0022 /* ----------------------------------------------------------------------- */
0023 
0024 static void vp3054_bit_setscl(void *data, int state)
0025 {
0026     struct cx8802_dev *dev = data;
0027     struct cx88_core *core = dev->core;
0028     struct vp3054_i2c_state *vp3054_i2c = dev->vp3054;
0029 
0030     if (state) {
0031         vp3054_i2c->state |=  0x0001;   /* SCL high */
0032         vp3054_i2c->state &= ~0x0100;   /* external pullup */
0033     } else {
0034         vp3054_i2c->state &= ~0x0001;   /* SCL low */
0035         vp3054_i2c->state |=  0x0100;   /* drive pin */
0036     }
0037     cx_write(MO_GP0_IO, 0x010000 | vp3054_i2c->state);
0038     cx_read(MO_GP0_IO);
0039 }
0040 
0041 static void vp3054_bit_setsda(void *data, int state)
0042 {
0043     struct cx8802_dev *dev = data;
0044     struct cx88_core *core = dev->core;
0045     struct vp3054_i2c_state *vp3054_i2c = dev->vp3054;
0046 
0047     if (state) {
0048         vp3054_i2c->state |=  0x0002;   /* SDA high */
0049         vp3054_i2c->state &= ~0x0200;   /* tristate pin */
0050     } else {
0051         vp3054_i2c->state &= ~0x0002;   /* SDA low */
0052         vp3054_i2c->state |=  0x0200;   /* drive pin */
0053     }
0054     cx_write(MO_GP0_IO, 0x020000 | vp3054_i2c->state);
0055     cx_read(MO_GP0_IO);
0056 }
0057 
0058 static int vp3054_bit_getscl(void *data)
0059 {
0060     struct cx8802_dev *dev = data;
0061     struct cx88_core *core = dev->core;
0062     u32 state;
0063 
0064     state = cx_read(MO_GP0_IO);
0065     return (state & 0x01) ? 1 : 0;
0066 }
0067 
0068 static int vp3054_bit_getsda(void *data)
0069 {
0070     struct cx8802_dev *dev = data;
0071     struct cx88_core *core = dev->core;
0072     u32 state;
0073 
0074     state = cx_read(MO_GP0_IO);
0075     return (state & 0x02) ? 1 : 0;
0076 }
0077 
0078 /* ----------------------------------------------------------------------- */
0079 
0080 static const struct i2c_algo_bit_data vp3054_i2c_algo_template = {
0081     .setsda  = vp3054_bit_setsda,
0082     .setscl  = vp3054_bit_setscl,
0083     .getsda  = vp3054_bit_getsda,
0084     .getscl  = vp3054_bit_getscl,
0085     .udelay  = 16,
0086     .timeout = 200,
0087 };
0088 
0089 /* ----------------------------------------------------------------------- */
0090 
0091 int vp3054_i2c_probe(struct cx8802_dev *dev)
0092 {
0093     struct cx88_core *core = dev->core;
0094     struct vp3054_i2c_state *vp3054_i2c;
0095     int rc;
0096 
0097     if (core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
0098         return 0;
0099 
0100     vp3054_i2c = kzalloc(sizeof(*vp3054_i2c), GFP_KERNEL);
0101     if (!vp3054_i2c)
0102         return -ENOMEM;
0103     dev->vp3054 = vp3054_i2c;
0104 
0105     vp3054_i2c->algo = vp3054_i2c_algo_template;
0106 
0107     vp3054_i2c->adap.dev.parent = &dev->pci->dev;
0108     strscpy(vp3054_i2c->adap.name, core->name,
0109         sizeof(vp3054_i2c->adap.name));
0110     vp3054_i2c->adap.owner = THIS_MODULE;
0111     vp3054_i2c->algo.data = dev;
0112     i2c_set_adapdata(&vp3054_i2c->adap, dev);
0113     vp3054_i2c->adap.algo_data = &vp3054_i2c->algo;
0114 
0115     vp3054_bit_setscl(dev, 1);
0116     vp3054_bit_setsda(dev, 1);
0117 
0118     rc = i2c_bit_add_bus(&vp3054_i2c->adap);
0119     if (rc != 0) {
0120         pr_err("vp3054_i2c register FAILED\n");
0121 
0122         kfree(dev->vp3054);
0123         dev->vp3054 = NULL;
0124     }
0125 
0126     return rc;
0127 }
0128 EXPORT_SYMBOL(vp3054_i2c_probe);
0129 
0130 void vp3054_i2c_remove(struct cx8802_dev *dev)
0131 {
0132     struct vp3054_i2c_state *vp3054_i2c = dev->vp3054;
0133 
0134     if (!vp3054_i2c ||
0135         dev->core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
0136         return;
0137 
0138     i2c_del_adapter(&vp3054_i2c->adap);
0139     kfree(vp3054_i2c);
0140 }
0141 EXPORT_SYMBOL(vp3054_i2c_remove);