linux/drivers/media/video/saa7134/saa7134-i2c.c
<<
>>
Prefs
   1/*
   2 *
   3 * device driver for philips saa7134 based TV cards
   4 * i2c interface support
   5 *
   6 * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
   7 *
   8 *  This program is free software; you can redistribute it and/or modify
   9 *  it under the terms of the GNU General Public License as published by
  10 *  the Free Software Foundation; either version 2 of the License, or
  11 *  (at your option) any later version.
  12 *
  13 *  This program is distributed in the hope that it will be useful,
  14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 *  GNU General Public License for more details.
  17 *
  18 *  You should have received a copy of the GNU General Public License
  19 *  along with this program; if not, write to the Free Software
  20 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21 */
  22
  23#include <linux/init.h>
  24#include <linux/list.h>
  25#include <linux/module.h>
  26#include <linux/kernel.h>
  27#include <linux/slab.h>
  28#include <linux/delay.h>
  29
  30#include "saa7134-reg.h"
  31#include "saa7134.h"
  32#include <media/v4l2-common.h>
  33
  34/* ----------------------------------------------------------- */
  35
  36static unsigned int i2c_debug;
  37module_param(i2c_debug, int, 0644);
  38MODULE_PARM_DESC(i2c_debug,"enable debug messages [i2c]");
  39
  40static unsigned int i2c_scan;
  41module_param(i2c_scan, int, 0444);
  42MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
  43
  44#define d1printk if (1 == i2c_debug) printk
  45#define d2printk if (2 == i2c_debug) printk
  46
  47#define I2C_WAIT_DELAY  32
  48#define I2C_WAIT_RETRY  16
  49
  50/* ----------------------------------------------------------- */
  51
  52static char *str_i2c_status[] = {
  53        "IDLE", "DONE_STOP", "BUSY", "TO_SCL", "TO_ARB", "DONE_WRITE",
  54        "DONE_READ", "DONE_WRITE_TO", "DONE_READ_TO", "NO_DEVICE",
  55        "NO_ACKN", "BUS_ERR", "ARB_LOST", "SEQ_ERR", "ST_ERR", "SW_ERR"
  56};
  57
  58enum i2c_status {
  59        IDLE          = 0,  // no I2C command pending
  60        DONE_STOP     = 1,  // I2C command done and STOP executed
  61        BUSY          = 2,  // executing I2C command
  62        TO_SCL        = 3,  // executing I2C command, time out on clock stretching
  63        TO_ARB        = 4,  // time out on arbitration trial, still trying
  64        DONE_WRITE    = 5,  // I2C command done and awaiting next write command
  65        DONE_READ     = 6,  // I2C command done and awaiting next read command
  66        DONE_WRITE_TO = 7,  // see 5, and time out on status echo
  67        DONE_READ_TO  = 8,  // see 6, and time out on status echo
  68        NO_DEVICE     = 9,  // no acknowledge on device slave address
  69        NO_ACKN       = 10, // no acknowledge after data byte transfer
  70        BUS_ERR       = 11, // bus error
  71        ARB_LOST      = 12, // arbitration lost during transfer
  72        SEQ_ERR       = 13, // erroneous programming sequence
  73        ST_ERR        = 14, // wrong status echoing
  74        SW_ERR        = 15  // software error
  75};
  76
  77static char *str_i2c_attr[] = {
  78        "NOP", "STOP", "CONTINUE", "START"
  79};
  80
  81enum i2c_attr {
  82        NOP           = 0,  // no operation on I2C bus
  83        STOP          = 1,  // stop condition, no associated byte transfer
  84        CONTINUE      = 2,  // continue with byte transfer
  85        START         = 3   // start condition with byte transfer
  86};
  87
  88static inline enum i2c_status i2c_get_status(struct saa7134_dev *dev)
  89{
  90        enum i2c_status status;
  91
  92        status = saa_readb(SAA7134_I2C_ATTR_STATUS) & 0x0f;
  93        d2printk(KERN_DEBUG "%s: i2c stat <= %s\n",dev->name,
  94                 str_i2c_status[status]);
  95        return status;
  96}
  97
  98static inline void i2c_set_status(struct saa7134_dev *dev,
  99                                  enum i2c_status status)
 100{
 101        d2printk(KERN_DEBUG "%s: i2c stat => %s\n",dev->name,
 102                 str_i2c_status[status]);
 103        saa_andorb(SAA7134_I2C_ATTR_STATUS,0x0f,status);
 104}
 105
 106static inline void i2c_set_attr(struct saa7134_dev *dev, enum i2c_attr attr)
 107{
 108        d2printk(KERN_DEBUG "%s: i2c attr => %s\n",dev->name,
 109                 str_i2c_attr[attr]);
 110        saa_andorb(SAA7134_I2C_ATTR_STATUS,0xc0,attr << 6);
 111}
 112
 113static inline int i2c_is_error(enum i2c_status status)
 114{
 115        switch (status) {
 116        case NO_DEVICE:
 117        case NO_ACKN:
 118        case BUS_ERR:
 119        case ARB_LOST:
 120        case SEQ_ERR:
 121        case ST_ERR:
 122                return true;
 123        default:
 124                return false;
 125        }
 126}
 127
 128static inline int i2c_is_idle(enum i2c_status status)
 129{
 130        switch (status) {
 131        case IDLE:
 132        case DONE_STOP:
 133                return true;
 134        default:
 135                return false;
 136        }
 137}
 138
 139static inline int i2c_is_busy(enum i2c_status status)
 140{
 141        switch (status) {
 142        case BUSY:
 143        case TO_SCL:
 144        case TO_ARB:
 145                return true;
 146        default:
 147                return false;
 148        }
 149}
 150
 151static int i2c_is_busy_wait(struct saa7134_dev *dev)
 152{
 153        enum i2c_status status;
 154        int count;
 155
 156        for (count = 0; count < I2C_WAIT_RETRY; count++) {
 157                status = i2c_get_status(dev);
 158                if (!i2c_is_busy(status))
 159                        break;
 160                saa_wait(I2C_WAIT_DELAY);
 161        }
 162        if (I2C_WAIT_RETRY == count)
 163                return false;
 164        return true;
 165}
 166
 167static int i2c_reset(struct saa7134_dev *dev)
 168{
 169        enum i2c_status status;
 170        int count;
 171
 172        d2printk(KERN_DEBUG "%s: i2c reset\n",dev->name);
 173        status = i2c_get_status(dev);
 174        if (!i2c_is_error(status))
 175                return true;
 176        i2c_set_status(dev,status);
 177
 178        for (count = 0; count < I2C_WAIT_RETRY; count++) {
 179                status = i2c_get_status(dev);
 180                if (!i2c_is_error(status))
 181                        break;
 182                udelay(I2C_WAIT_DELAY);
 183        }
 184        if (I2C_WAIT_RETRY == count)
 185                return false;
 186
 187        if (!i2c_is_idle(status))
 188                return false;
 189
 190        i2c_set_attr(dev,NOP);
 191        return true;
 192}
 193
 194static inline int i2c_send_byte(struct saa7134_dev *dev,
 195                                enum i2c_attr attr,
 196                                unsigned char data)
 197{
 198        enum i2c_status status;
 199        __u32 dword;
 200
 201        /* have to write both attr + data in one 32bit word */
 202        dword  = saa_readl(SAA7134_I2C_ATTR_STATUS >> 2);
 203        dword &= 0x0f;
 204        dword |= (attr << 6);
 205        dword |= ((__u32)data << 8);
 206        dword |= 0x00 << 16;  /* 100 kHz */
 207//      dword |= 0x40 << 16;  /* 400 kHz */
 208        dword |= 0xf0 << 24;
 209        saa_writel(SAA7134_I2C_ATTR_STATUS >> 2, dword);
 210        d2printk(KERN_DEBUG "%s: i2c data => 0x%x\n",dev->name,data);
 211
 212        if (!i2c_is_busy_wait(dev))
 213                return -EIO;
 214        status = i2c_get_status(dev);
 215        if (i2c_is_error(status))
 216                return -EIO;
 217        return 0;
 218}
 219
 220static inline int i2c_recv_byte(struct saa7134_dev *dev)
 221{
 222        enum i2c_status status;
 223        unsigned char data;
 224
 225        i2c_set_attr(dev,CONTINUE);
 226        if (!i2c_is_busy_wait(dev))
 227                return -EIO;
 228        status = i2c_get_status(dev);
 229        if (i2c_is_error(status))
 230                return -EIO;
 231        data = saa_readb(SAA7134_I2C_DATA);
 232        d2printk(KERN_DEBUG "%s: i2c data <= 0x%x\n",dev->name,data);
 233        return data;
 234}
 235
 236static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap,
 237                            struct i2c_msg *msgs, int num)
 238{
 239        struct saa7134_dev *dev = i2c_adap->algo_data;
 240        enum i2c_status status;
 241        unsigned char data;
 242        int addr,rc,i,byte;
 243
 244        status = i2c_get_status(dev);
 245        if (!i2c_is_idle(status))
 246                if (!i2c_reset(dev))
 247                        return -EIO;
 248
 249        d2printk("start xfer\n");
 250        d1printk(KERN_DEBUG "%s: i2c xfer:",dev->name);
 251        for (i = 0; i < num; i++) {
 252                if (!(msgs[i].flags & I2C_M_NOSTART) || 0 == i) {
 253                        /* send address */
 254                        d2printk("send address\n");
 255                        addr  = msgs[i].addr << 1;
 256                        if (msgs[i].flags & I2C_M_RD)
 257                                addr |= 1;
 258                        if (i > 0 && msgs[i].flags & I2C_M_RD && msgs[i].addr != 0x40) {
 259                                /* workaround for a saa7134 i2c bug
 260                                 * needed to talk to the mt352 demux
 261                                 * thanks to pinnacle for the hint */
 262                                int quirk = 0xfe;
 263                                d1printk(" [%02x quirk]",quirk);
 264                                i2c_send_byte(dev,START,quirk);
 265                                i2c_recv_byte(dev);
 266                        }
 267                        d1printk(" < %02x", addr);
 268                        rc = i2c_send_byte(dev,START,addr);
 269                        if (rc < 0)
 270                                 goto err;
 271                }
 272                if (msgs[i].flags & I2C_M_RD) {
 273                        /* read bytes */
 274                        d2printk("read bytes\n");
 275                        for (byte = 0; byte < msgs[i].len; byte++) {
 276                                d1printk(" =");
 277                                rc = i2c_recv_byte(dev);
 278                                if (rc < 0)
 279                                        goto err;
 280                                d1printk("%02x", rc);
 281                                msgs[i].buf[byte] = rc;
 282                        }
 283                } else {
 284                        /* write bytes */
 285                        d2printk("write bytes\n");
 286                        for (byte = 0; byte < msgs[i].len; byte++) {
 287                                data = msgs[i].buf[byte];
 288                                d1printk(" %02x", data);
 289                                rc = i2c_send_byte(dev,CONTINUE,data);
 290                                if (rc < 0)
 291                                        goto err;
 292                        }
 293                }
 294        }
 295        d2printk("xfer done\n");
 296        d1printk(" >");
 297        i2c_set_attr(dev,STOP);
 298        rc = -EIO;
 299        if (!i2c_is_busy_wait(dev))
 300                goto err;
 301        status = i2c_get_status(dev);
 302        if (i2c_is_error(status))
 303                goto err;
 304        /* ensure that the bus is idle for at least one bit slot */
 305        msleep(1);
 306
 307        d1printk("\n");
 308        return num;
 309 err:
 310        if (1 == i2c_debug) {
 311                status = i2c_get_status(dev);
 312                printk(" ERROR: %s\n",str_i2c_status[status]);
 313        }
 314        return rc;
 315}
 316
 317/* ----------------------------------------------------------- */
 318
 319static u32 functionality(struct i2c_adapter *adap)
 320{
 321        return I2C_FUNC_SMBUS_EMUL;
 322}
 323
 324static struct i2c_algorithm saa7134_algo = {
 325        .master_xfer   = saa7134_i2c_xfer,
 326        .functionality = functionality,
 327};
 328
 329static struct i2c_adapter saa7134_adap_template = {
 330        .owner         = THIS_MODULE,
 331        .name          = "saa7134",
 332        .id            = I2C_HW_SAA7134,
 333        .algo          = &saa7134_algo,
 334};
 335
 336static struct i2c_client saa7134_client_template = {
 337        .name   = "saa7134 internal",
 338};
 339
 340/* ----------------------------------------------------------- */
 341
 342static int
 343saa7134_i2c_eeprom(struct saa7134_dev *dev, unsigned char *eedata, int len)
 344{
 345        unsigned char buf;
 346        int i,err;
 347
 348        dev->i2c_client.addr = 0xa0 >> 1;
 349        buf = 0;
 350        if (1 != (err = i2c_master_send(&dev->i2c_client,&buf,1))) {
 351                printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
 352                       dev->name,err);
 353                return -1;
 354        }
 355        if (len != (err = i2c_master_recv(&dev->i2c_client,eedata,len))) {
 356                printk(KERN_WARNING "%s: i2c eeprom read error (err=%d)\n",
 357                       dev->name,err);
 358                return -1;
 359        }
 360        for (i = 0; i < len; i++) {
 361                if (0 == (i % 16))
 362                        printk(KERN_INFO "%s: i2c eeprom %02x:",dev->name,i);
 363                printk(" %02x",eedata[i]);
 364                if (15 == (i % 16))
 365                        printk("\n");
 366        }
 367        return 0;
 368}
 369
 370static char *i2c_devs[128] = {
 371        [ 0x20      ] = "mpeg encoder (saa6752hs)",
 372        [ 0xa0 >> 1 ] = "eeprom",
 373        [ 0xc0 >> 1 ] = "tuner (analog)",
 374        [ 0x86 >> 1 ] = "tda9887",
 375        [ 0x5a >> 1 ] = "remote control",
 376};
 377
 378static void do_i2c_scan(char *name, struct i2c_client *c)
 379{
 380        unsigned char buf;
 381        int i,rc;
 382
 383        for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
 384                c->addr = i;
 385                rc = i2c_master_recv(c,&buf,0);
 386                if (rc < 0)
 387                        continue;
 388                printk("%s: i2c scan: found device @ 0x%x  [%s]\n",
 389                       name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
 390        }
 391}
 392
 393int saa7134_i2c_register(struct saa7134_dev *dev)
 394{
 395        dev->i2c_adap = saa7134_adap_template;
 396        dev->i2c_adap.dev.parent = &dev->pci->dev;
 397        strcpy(dev->i2c_adap.name,dev->name);
 398        dev->i2c_adap.algo_data = dev;
 399        i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
 400        i2c_add_adapter(&dev->i2c_adap);
 401
 402        dev->i2c_client = saa7134_client_template;
 403        dev->i2c_client.adapter = &dev->i2c_adap;
 404
 405        saa7134_i2c_eeprom(dev,dev->eedata,sizeof(dev->eedata));
 406        if (i2c_scan)
 407                do_i2c_scan(dev->name,&dev->i2c_client);
 408
 409        /* Instantiate the IR receiver device, if present */
 410        saa7134_probe_i2c_ir(dev);
 411        return 0;
 412}
 413
 414int saa7134_i2c_unregister(struct saa7134_dev *dev)
 415{
 416        i2c_del_adapter(&dev->i2c_adap);
 417        return 0;
 418}
 419
 420/* ----------------------------------------------------------- */
 421/*
 422 * Local variables:
 423 * c-basic-offset: 8
 424 * End:
 425 */
 426