Path: blob/master/drivers/media/video/cx23885/cx23885-i2c.c
17900 views
/*1* Driver for the Conexant CX23885 PCIe bridge2*3* Copyright (c) 2006 Steven Toth <[email protected]>4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* (at your option) any later version.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13*14* GNU General Public License for more details.15*16* You should have received a copy of the GNU General Public License17* along with this program; if not, write to the Free Software18* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.19*/2021#include <linux/module.h>22#include <linux/moduleparam.h>23#include <linux/init.h>24#include <linux/delay.h>25#include <asm/io.h>2627#include "cx23885.h"2829#include <media/v4l2-common.h>3031static unsigned int i2c_debug;32module_param(i2c_debug, int, 0644);33MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");3435static unsigned int i2c_scan;36module_param(i2c_scan, int, 0444);37MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");3839#define dprintk(level, fmt, arg...)\40do { if (i2c_debug >= level)\41printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\42} while (0)4344#define I2C_WAIT_DELAY 3245#define I2C_WAIT_RETRY 644647#define I2C_EXTEND (1 << 3)48#define I2C_NOSTOP (1 << 4)4950static inline int i2c_slave_did_ack(struct i2c_adapter *i2c_adap)51{52struct cx23885_i2c *bus = i2c_adap->algo_data;53struct cx23885_dev *dev = bus->dev;54return cx_read(bus->reg_stat) & 0x01;55}5657static inline int i2c_is_busy(struct i2c_adapter *i2c_adap)58{59struct cx23885_i2c *bus = i2c_adap->algo_data;60struct cx23885_dev *dev = bus->dev;61return cx_read(bus->reg_stat) & 0x02 ? 1 : 0;62}6364static int i2c_wait_done(struct i2c_adapter *i2c_adap)65{66int count;6768for (count = 0; count < I2C_WAIT_RETRY; count++) {69if (!i2c_is_busy(i2c_adap))70break;71udelay(I2C_WAIT_DELAY);72}7374if (I2C_WAIT_RETRY == count)75return 0;7677return 1;78}7980static int i2c_sendbytes(struct i2c_adapter *i2c_adap,81const struct i2c_msg *msg, int joined_rlen)82{83struct cx23885_i2c *bus = i2c_adap->algo_data;84struct cx23885_dev *dev = bus->dev;85u32 wdata, addr, ctrl;86int retval, cnt;8788if (joined_rlen)89dprintk(1, "%s(msg->wlen=%d, nextmsg->rlen=%d)\n", __func__,90msg->len, joined_rlen);91else92dprintk(1, "%s(msg->len=%d)\n", __func__, msg->len);9394/* Deal with i2c probe functions with zero payload */95if (msg->len == 0) {96cx_write(bus->reg_addr, msg->addr << 25);97cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2));98if (!i2c_wait_done(i2c_adap))99return -EIO;100if (!i2c_slave_did_ack(i2c_adap))101return -ENXIO;102103dprintk(1, "%s() returns 0\n", __func__);104return 0;105}106107108/* dev, reg + first byte */109addr = (msg->addr << 25) | msg->buf[0];110wdata = msg->buf[0];111ctrl = bus->i2c_period | (1 << 12) | (1 << 2);112113if (msg->len > 1)114ctrl |= I2C_NOSTOP | I2C_EXTEND;115else if (joined_rlen)116ctrl |= I2C_NOSTOP;117118cx_write(bus->reg_addr, addr);119cx_write(bus->reg_wdata, wdata);120cx_write(bus->reg_ctrl, ctrl);121122if (!i2c_wait_done(i2c_adap))123goto eio;124if (i2c_debug) {125printk(" <W %02x %02x", msg->addr << 1, msg->buf[0]);126if (!(ctrl & I2C_NOSTOP))127printk(" >\n");128}129130for (cnt = 1; cnt < msg->len; cnt++) {131/* following bytes */132wdata = msg->buf[cnt];133ctrl = bus->i2c_period | (1 << 12) | (1 << 2);134135if (cnt < msg->len - 1)136ctrl |= I2C_NOSTOP | I2C_EXTEND;137else if (joined_rlen)138ctrl |= I2C_NOSTOP;139140cx_write(bus->reg_addr, addr);141cx_write(bus->reg_wdata, wdata);142cx_write(bus->reg_ctrl, ctrl);143144if (!i2c_wait_done(i2c_adap))145goto eio;146if (i2c_debug) {147dprintk(1, " %02x", msg->buf[cnt]);148if (!(ctrl & I2C_NOSTOP))149dprintk(1, " >\n");150}151}152return msg->len;153154eio:155retval = -EIO;156if (i2c_debug)157printk(KERN_ERR " ERR: %d\n", retval);158return retval;159}160161static int i2c_readbytes(struct i2c_adapter *i2c_adap,162const struct i2c_msg *msg, int joined)163{164struct cx23885_i2c *bus = i2c_adap->algo_data;165struct cx23885_dev *dev = bus->dev;166u32 ctrl, cnt;167int retval;168169170if (i2c_debug && !joined)171dprintk(1, "%s(msg->len=%d)\n", __func__, msg->len);172173/* Deal with i2c probe functions with zero payload */174if (msg->len == 0) {175cx_write(bus->reg_addr, msg->addr << 25);176cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2) | 1);177if (!i2c_wait_done(i2c_adap))178return -EIO;179if (!i2c_slave_did_ack(i2c_adap))180return -ENXIO;181182183dprintk(1, "%s() returns 0\n", __func__);184return 0;185}186187if (i2c_debug) {188if (joined)189dprintk(1, " R");190else191dprintk(1, " <R %02x", (msg->addr << 1) + 1);192}193194for (cnt = 0; cnt < msg->len; cnt++) {195196ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1;197198if (cnt < msg->len - 1)199ctrl |= I2C_NOSTOP | I2C_EXTEND;200201cx_write(bus->reg_addr, msg->addr << 25);202cx_write(bus->reg_ctrl, ctrl);203204if (!i2c_wait_done(i2c_adap))205goto eio;206msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff;207if (i2c_debug) {208dprintk(1, " %02x", msg->buf[cnt]);209if (!(ctrl & I2C_NOSTOP))210dprintk(1, " >\n");211}212}213return msg->len;214215eio:216retval = -EIO;217if (i2c_debug)218printk(KERN_ERR " ERR: %d\n", retval);219return retval;220}221222static int i2c_xfer(struct i2c_adapter *i2c_adap,223struct i2c_msg *msgs, int num)224{225struct cx23885_i2c *bus = i2c_adap->algo_data;226struct cx23885_dev *dev = bus->dev;227int i, retval = 0;228229dprintk(1, "%s(num = %d)\n", __func__, num);230231for (i = 0 ; i < num; i++) {232dprintk(1, "%s(num = %d) addr = 0x%02x len = 0x%x\n",233__func__, num, msgs[i].addr, msgs[i].len);234if (msgs[i].flags & I2C_M_RD) {235/* read */236retval = i2c_readbytes(i2c_adap, &msgs[i], 0);237} else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&238msgs[i].addr == msgs[i + 1].addr) {239/* write then read from same address */240retval = i2c_sendbytes(i2c_adap, &msgs[i],241msgs[i + 1].len);242if (retval < 0)243goto err;244i++;245retval = i2c_readbytes(i2c_adap, &msgs[i], 1);246} else {247/* write */248retval = i2c_sendbytes(i2c_adap, &msgs[i], 0);249}250if (retval < 0)251goto err;252}253return num;254255err:256return retval;257}258259static u32 cx23885_functionality(struct i2c_adapter *adap)260{261return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;262}263264static struct i2c_algorithm cx23885_i2c_algo_template = {265.master_xfer = i2c_xfer,266.functionality = cx23885_functionality,267};268269/* ----------------------------------------------------------------------- */270271static struct i2c_adapter cx23885_i2c_adap_template = {272.name = "cx23885",273.owner = THIS_MODULE,274.algo = &cx23885_i2c_algo_template,275};276277static struct i2c_client cx23885_i2c_client_template = {278.name = "cx23885 internal",279};280281static char *i2c_devs[128] = {282[0x10 >> 1] = "tda10048",283[0x12 >> 1] = "dib7000pc",284[0x1c >> 1] = "lgdt3303",285[0x86 >> 1] = "tda9887",286[0x32 >> 1] = "cx24227",287[0x88 >> 1] = "cx25837",288[0x84 >> 1] = "tda8295",289[0xa0 >> 1] = "eeprom",290[0xc0 >> 1] = "tuner/mt2131/tda8275",291[0xc2 >> 1] = "tuner/mt2131/tda8275/xc5000/xc3028",292[0xc8 >> 1] = "tuner/xc3028L",293};294295static void do_i2c_scan(char *name, struct i2c_client *c)296{297unsigned char buf;298int i, rc;299300for (i = 0; i < 128; i++) {301c->addr = i;302rc = i2c_master_recv(c, &buf, 0);303if (rc < 0)304continue;305printk(KERN_INFO "%s: i2c scan: found device @ 0x%x [%s]\n",306name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");307}308}309310/* init + register i2c algo-bit adapter */311int cx23885_i2c_register(struct cx23885_i2c *bus)312{313struct cx23885_dev *dev = bus->dev;314315dprintk(1, "%s(bus = %d)\n", __func__, bus->nr);316317memcpy(&bus->i2c_adap, &cx23885_i2c_adap_template,318sizeof(bus->i2c_adap));319memcpy(&bus->i2c_algo, &cx23885_i2c_algo_template,320sizeof(bus->i2c_algo));321memcpy(&bus->i2c_client, &cx23885_i2c_client_template,322sizeof(bus->i2c_client));323324bus->i2c_adap.dev.parent = &dev->pci->dev;325326strlcpy(bus->i2c_adap.name, bus->dev->name,327sizeof(bus->i2c_adap.name));328329bus->i2c_algo.data = bus;330bus->i2c_adap.algo_data = bus;331i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev);332i2c_add_adapter(&bus->i2c_adap);333334bus->i2c_client.adapter = &bus->i2c_adap;335336if (0 == bus->i2c_rc) {337dprintk(1, "%s: i2c bus %d registered\n", dev->name, bus->nr);338if (i2c_scan) {339printk(KERN_INFO "%s: scan bus %d:\n",340dev->name, bus->nr);341do_i2c_scan(dev->name, &bus->i2c_client);342}343} else344printk(KERN_WARNING "%s: i2c bus %d register FAILED\n",345dev->name, bus->nr);346347/* Instantiate the IR receiver device, if present */348if (0 == bus->i2c_rc) {349struct i2c_board_info info;350const unsigned short addr_list[] = {3510x6b, I2C_CLIENT_END352};353354memset(&info, 0, sizeof(struct i2c_board_info));355strlcpy(info.type, "ir_video", I2C_NAME_SIZE);356/* Use quick read command for probe, some IR chips don't357* support writes */358i2c_new_probed_device(&bus->i2c_adap, &info, addr_list,359i2c_probe_func_quick_read);360}361362return bus->i2c_rc;363}364365int cx23885_i2c_unregister(struct cx23885_i2c *bus)366{367i2c_del_adapter(&bus->i2c_adap);368return 0;369}370371void cx23885_av_clk(struct cx23885_dev *dev, int enable)372{373/* write 0 to bus 2 addr 0x144 via i2x_xfer() */374char buffer[3];375struct i2c_msg msg;376dprintk(1, "%s(enabled = %d)\n", __func__, enable);377378/* Register 0x144 */379buffer[0] = 0x01;380buffer[1] = 0x44;381if (enable == 1)382buffer[2] = 0x05;383else384buffer[2] = 0x00;385386msg.addr = 0x44;387msg.flags = I2C_M_TEN;388msg.len = 3;389msg.buf = buffer;390391i2c_xfer(&dev->i2c_bus[2].i2c_adap, &msg, 1);392}393394/* ----------------------------------------------------------------------- */395396/*397* Local variables:398* c-basic-offset: 8399* End:400*/401402403