linux/drivers/media/pci/pt3/pt3_i2c.c
<<
>>
Prefs
   1/*
   2 * Earthsoft PT3 driver
   3 *
   4 * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License as
   8 * published by the Free Software Foundation version 2.
   9 *
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 */
  16#include <linux/delay.h>
  17#include <linux/device.h>
  18#include <linux/i2c.h>
  19#include <linux/io.h>
  20#include <linux/pci.h>
  21
  22#include "pt3.h"
  23
  24#define PT3_I2C_BASE  2048
  25#define PT3_CMD_ADDR_NORMAL 0
  26#define PT3_CMD_ADDR_INIT_DEMOD  4096
  27#define PT3_CMD_ADDR_INIT_TUNER  (4096 + 2042)
  28
  29/* masks for I2C status register */
  30#define STAT_SEQ_RUNNING 0x1
  31#define STAT_SEQ_ERROR   0x6
  32#define STAT_NO_SEQ      0x8
  33
  34#define PT3_I2C_RUN   (1 << 16)
  35#define PT3_I2C_RESET (1 << 17)
  36
  37enum ctl_cmd {
  38        I_END,
  39        I_ADDRESS,
  40        I_CLOCK_L,
  41        I_CLOCK_H,
  42        I_DATA_L,
  43        I_DATA_H,
  44        I_RESET,
  45        I_SLEEP,
  46        I_DATA_L_NOP  = 0x08,
  47        I_DATA_H_NOP  = 0x0c,
  48        I_DATA_H_READ = 0x0d,
  49        I_DATA_H_ACK0 = 0x0e,
  50        I_DATA_H_ACK1 = 0x0f,
  51};
  52
  53
  54static void cmdbuf_add(struct pt3_i2cbuf *cbuf, enum ctl_cmd cmd)
  55{
  56        int buf_idx;
  57
  58        if ((cbuf->num_cmds % 2) == 0)
  59                cbuf->tmp = cmd;
  60        else {
  61                cbuf->tmp |= cmd << 4;
  62                buf_idx = cbuf->num_cmds / 2;
  63                if (buf_idx < ARRAY_SIZE(cbuf->data))
  64                        cbuf->data[buf_idx] = cbuf->tmp;
  65        }
  66        cbuf->num_cmds++;
  67}
  68
  69static void put_end(struct pt3_i2cbuf *cbuf)
  70{
  71        cmdbuf_add(cbuf, I_END);
  72        if (cbuf->num_cmds % 2)
  73                cmdbuf_add(cbuf, I_END);
  74}
  75
  76static void put_start(struct pt3_i2cbuf *cbuf)
  77{
  78        cmdbuf_add(cbuf, I_DATA_H);
  79        cmdbuf_add(cbuf, I_CLOCK_H);
  80        cmdbuf_add(cbuf, I_DATA_L);
  81        cmdbuf_add(cbuf, I_CLOCK_L);
  82}
  83
  84static void put_byte_write(struct pt3_i2cbuf *cbuf, u8 val)
  85{
  86        u8 mask;
  87
  88        mask = 0x80;
  89        for (mask = 0x80; mask > 0; mask >>= 1)
  90                cmdbuf_add(cbuf, (val & mask) ? I_DATA_H_NOP : I_DATA_L_NOP);
  91        cmdbuf_add(cbuf, I_DATA_H_ACK0);
  92}
  93
  94static void put_byte_read(struct pt3_i2cbuf *cbuf, u32 size)
  95{
  96        int i, j;
  97
  98        for (i = 0; i < size; i++) {
  99                for (j = 0; j < 8; j++)
 100                        cmdbuf_add(cbuf, I_DATA_H_READ);
 101                cmdbuf_add(cbuf, (i == size - 1) ? I_DATA_H_NOP : I_DATA_L_NOP);
 102        }
 103}
 104
 105static void put_stop(struct pt3_i2cbuf *cbuf)
 106{
 107        cmdbuf_add(cbuf, I_DATA_L);
 108        cmdbuf_add(cbuf, I_CLOCK_H);
 109        cmdbuf_add(cbuf, I_DATA_H);
 110}
 111
 112
 113/* translates msgs to internal commands for bit-banging */
 114static void translate(struct pt3_i2cbuf *cbuf, struct i2c_msg *msgs, int num)
 115{
 116        int i, j;
 117        bool rd;
 118
 119        cbuf->num_cmds = 0;
 120        for (i = 0; i < num; i++) {
 121                rd = !!(msgs[i].flags & I2C_M_RD);
 122                put_start(cbuf);
 123                put_byte_write(cbuf, msgs[i].addr << 1 | rd);
 124                if (rd)
 125                        put_byte_read(cbuf, msgs[i].len);
 126                else
 127                        for (j = 0; j < msgs[i].len; j++)
 128                                put_byte_write(cbuf, msgs[i].buf[j]);
 129        }
 130        if (num > 0) {
 131                put_stop(cbuf);
 132                put_end(cbuf);
 133        }
 134}
 135
 136static int wait_i2c_result(struct pt3_board *pt3, u32 *result, int max_wait)
 137{
 138        int i;
 139        u32 v;
 140
 141        for (i = 0; i < max_wait; i++) {
 142                v = ioread32(pt3->regs[0] + REG_I2C_R);
 143                if (!(v & STAT_SEQ_RUNNING))
 144                        break;
 145                usleep_range(500, 750);
 146        }
 147        if (i >= max_wait)
 148                return -EIO;
 149        if (result)
 150                *result = v;
 151        return 0;
 152}
 153
 154/* send [pre-]translated i2c msgs stored at addr */
 155static int send_i2c_cmd(struct pt3_board *pt3, u32 addr)
 156{
 157        u32 ret;
 158
 159        /* make sure that previous transactions had finished */
 160        if (wait_i2c_result(pt3, NULL, 50)) {
 161                dev_warn(&pt3->pdev->dev, "(%s) prev. transaction stalled\n",
 162                                __func__);
 163                return -EIO;
 164        }
 165
 166        iowrite32(PT3_I2C_RUN | addr, pt3->regs[0] + REG_I2C_W);
 167        usleep_range(200, 300);
 168        /* wait for the current transaction to finish */
 169        if (wait_i2c_result(pt3, &ret, 500) || (ret & STAT_SEQ_ERROR)) {
 170                dev_warn(&pt3->pdev->dev, "(%s) failed.\n", __func__);
 171                return -EIO;
 172        }
 173        return 0;
 174}
 175
 176
 177/* init commands for each demod are combined into one transaction
 178 *  and hidden in ROM with the address PT3_CMD_ADDR_INIT_DEMOD.
 179 */
 180int  pt3_init_all_demods(struct pt3_board *pt3)
 181{
 182        ioread32(pt3->regs[0] + REG_I2C_R);
 183        return send_i2c_cmd(pt3, PT3_CMD_ADDR_INIT_DEMOD);
 184}
 185
 186/* init commands for two ISDB-T tuners are hidden in ROM. */
 187int  pt3_init_all_mxl301rf(struct pt3_board *pt3)
 188{
 189        usleep_range(1000, 2000);
 190        return send_i2c_cmd(pt3, PT3_CMD_ADDR_INIT_TUNER);
 191}
 192
 193void pt3_i2c_reset(struct pt3_board *pt3)
 194{
 195        iowrite32(PT3_I2C_RESET, pt3->regs[0] + REG_I2C_W);
 196}
 197
 198/*
 199 * I2C algorithm
 200 */
 201int
 202pt3_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 203{
 204        struct pt3_board *pt3;
 205        struct pt3_i2cbuf *cbuf;
 206        int i;
 207        void __iomem *p;
 208
 209        pt3 = i2c_get_adapdata(adap);
 210        cbuf = pt3->i2c_buf;
 211
 212        for (i = 0; i < num; i++)
 213                if (msgs[i].flags & I2C_M_RECV_LEN) {
 214                        dev_warn(&pt3->pdev->dev,
 215                                "(%s) I2C_M_RECV_LEN not supported.\n",
 216                                __func__);
 217                        return -EINVAL;
 218                }
 219
 220        translate(cbuf, msgs, num);
 221        memcpy_toio(pt3->regs[1] + PT3_I2C_BASE + PT3_CMD_ADDR_NORMAL / 2,
 222                        cbuf->data, cbuf->num_cmds);
 223
 224        if (send_i2c_cmd(pt3, PT3_CMD_ADDR_NORMAL) < 0)
 225                return -EIO;
 226
 227        p = pt3->regs[1] + PT3_I2C_BASE;
 228        for (i = 0; i < num; i++)
 229                if ((msgs[i].flags & I2C_M_RD) && msgs[i].len > 0) {
 230                        memcpy_fromio(msgs[i].buf, p, msgs[i].len);
 231                        p += msgs[i].len;
 232                }
 233
 234        return num;
 235}
 236
 237u32 pt3_i2c_functionality(struct i2c_adapter *adap)
 238{
 239        return I2C_FUNC_I2C;
 240}
 241