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