13dae3c96SDaniel Scheller // SPDX-License-Identifier: GPL-2.0 215f757bbSDaniel Scheller /* 32dc3e050SDaniel Scheller * cxd2099.c: Driver for the Sony CXD2099AR Common Interface Controller 415f757bbSDaniel Scheller * 515f757bbSDaniel Scheller * Copyright (C) 2010-2013 Digital Devices GmbH 615f757bbSDaniel Scheller */ 715f757bbSDaniel Scheller 815f757bbSDaniel Scheller #include <linux/slab.h> 915f757bbSDaniel Scheller #include <linux/kernel.h> 1015f757bbSDaniel Scheller #include <linux/module.h> 1115f757bbSDaniel Scheller #include <linux/i2c.h> 1215f757bbSDaniel Scheller #include <linux/regmap.h> 1315f757bbSDaniel Scheller #include <linux/wait.h> 1415f757bbSDaniel Scheller #include <linux/delay.h> 1515f757bbSDaniel Scheller #include <linux/mutex.h> 1615f757bbSDaniel Scheller #include <linux/io.h> 1715f757bbSDaniel Scheller 1815f757bbSDaniel Scheller #include "cxd2099.h" 1915f757bbSDaniel Scheller 2015f757bbSDaniel Scheller static int buffermode; 2115f757bbSDaniel Scheller module_param(buffermode, int, 0444); 2215f757bbSDaniel Scheller MODULE_PARM_DESC(buffermode, "Enable CXD2099AR buffer mode (default: disabled)"); 2315f757bbSDaniel Scheller 2415f757bbSDaniel Scheller static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount); 2515f757bbSDaniel Scheller 2615f757bbSDaniel Scheller struct cxd { 2715f757bbSDaniel Scheller struct dvb_ca_en50221 en; 2815f757bbSDaniel Scheller 2915f757bbSDaniel Scheller struct cxd2099_cfg cfg; 3015f757bbSDaniel Scheller struct i2c_client *client; 3115f757bbSDaniel Scheller struct regmap *regmap; 3215f757bbSDaniel Scheller 3315f757bbSDaniel Scheller u8 regs[0x23]; 3415f757bbSDaniel Scheller u8 lastaddress; 3515f757bbSDaniel Scheller u8 clk_reg_f; 3615f757bbSDaniel Scheller u8 clk_reg_b; 3715f757bbSDaniel Scheller int mode; 3815f757bbSDaniel Scheller int ready; 3915f757bbSDaniel Scheller int dr; 4015f757bbSDaniel Scheller int write_busy; 4115f757bbSDaniel Scheller int slot_stat; 4215f757bbSDaniel Scheller 4315f757bbSDaniel Scheller u8 amem[1024]; 4415f757bbSDaniel Scheller int amem_read; 4515f757bbSDaniel Scheller 4615f757bbSDaniel Scheller int cammode; 4715f757bbSDaniel Scheller struct mutex lock; /* device access lock */ 4815f757bbSDaniel Scheller 4915f757bbSDaniel Scheller u8 rbuf[1028]; 5015f757bbSDaniel Scheller u8 wbuf[1028]; 5115f757bbSDaniel Scheller }; 5215f757bbSDaniel Scheller 5315f757bbSDaniel Scheller static int read_block(struct cxd *ci, u8 adr, u8 *data, u16 n) 5415f757bbSDaniel Scheller { 5515f757bbSDaniel Scheller int status = 0; 5615f757bbSDaniel Scheller 5715f757bbSDaniel Scheller if (ci->lastaddress != adr) 5815f757bbSDaniel Scheller status = regmap_write(ci->regmap, 0, adr); 5915f757bbSDaniel Scheller if (!status) { 6015f757bbSDaniel Scheller ci->lastaddress = adr; 6115f757bbSDaniel Scheller 6215f757bbSDaniel Scheller while (n) { 6315f757bbSDaniel Scheller int len = n; 6415f757bbSDaniel Scheller 6515f757bbSDaniel Scheller if (ci->cfg.max_i2c && len > ci->cfg.max_i2c) 6615f757bbSDaniel Scheller len = ci->cfg.max_i2c; 6715f757bbSDaniel Scheller status = regmap_raw_read(ci->regmap, 1, data, len); 6815f757bbSDaniel Scheller if (status) 6915f757bbSDaniel Scheller return status; 7015f757bbSDaniel Scheller data += len; 7115f757bbSDaniel Scheller n -= len; 7215f757bbSDaniel Scheller } 7315f757bbSDaniel Scheller } 7415f757bbSDaniel Scheller return status; 7515f757bbSDaniel Scheller } 7615f757bbSDaniel Scheller 7715f757bbSDaniel Scheller static int read_reg(struct cxd *ci, u8 reg, u8 *val) 7815f757bbSDaniel Scheller { 7915f757bbSDaniel Scheller return read_block(ci, reg, val, 1); 8015f757bbSDaniel Scheller } 8115f757bbSDaniel Scheller 8215f757bbSDaniel Scheller static int read_pccard(struct cxd *ci, u16 address, u8 *data, u8 n) 8315f757bbSDaniel Scheller { 8415f757bbSDaniel Scheller int status; 8515f757bbSDaniel Scheller u8 addr[2] = {address & 0xff, address >> 8}; 8615f757bbSDaniel Scheller 8715f757bbSDaniel Scheller status = regmap_raw_write(ci->regmap, 2, addr, 2); 8815f757bbSDaniel Scheller if (!status) 8915f757bbSDaniel Scheller status = regmap_raw_read(ci->regmap, 3, data, n); 9015f757bbSDaniel Scheller return status; 9115f757bbSDaniel Scheller } 9215f757bbSDaniel Scheller 9315f757bbSDaniel Scheller static int write_pccard(struct cxd *ci, u16 address, u8 *data, u8 n) 9415f757bbSDaniel Scheller { 9515f757bbSDaniel Scheller int status; 9615f757bbSDaniel Scheller u8 addr[2] = {address & 0xff, address >> 8}; 9715f757bbSDaniel Scheller 9815f757bbSDaniel Scheller status = regmap_raw_write(ci->regmap, 2, addr, 2); 9915f757bbSDaniel Scheller if (!status) { 10015f757bbSDaniel Scheller u8 buf[256]; 10115f757bbSDaniel Scheller 10215f757bbSDaniel Scheller memcpy(buf, data, n); 10315f757bbSDaniel Scheller status = regmap_raw_write(ci->regmap, 3, buf, n); 10415f757bbSDaniel Scheller } 10515f757bbSDaniel Scheller return status; 10615f757bbSDaniel Scheller } 10715f757bbSDaniel Scheller 10815f757bbSDaniel Scheller static int read_io(struct cxd *ci, u16 address, unsigned int *val) 10915f757bbSDaniel Scheller { 11015f757bbSDaniel Scheller int status; 11115f757bbSDaniel Scheller u8 addr[2] = {address & 0xff, address >> 8}; 11215f757bbSDaniel Scheller 11315f757bbSDaniel Scheller status = regmap_raw_write(ci->regmap, 2, addr, 2); 11415f757bbSDaniel Scheller if (!status) 11515f757bbSDaniel Scheller status = regmap_read(ci->regmap, 3, val); 11615f757bbSDaniel Scheller return status; 11715f757bbSDaniel Scheller } 11815f757bbSDaniel Scheller 11915f757bbSDaniel Scheller static int write_io(struct cxd *ci, u16 address, u8 val) 12015f757bbSDaniel Scheller { 12115f757bbSDaniel Scheller int status; 12215f757bbSDaniel Scheller u8 addr[2] = {address & 0xff, address >> 8}; 12315f757bbSDaniel Scheller 12415f757bbSDaniel Scheller status = regmap_raw_write(ci->regmap, 2, addr, 2); 12515f757bbSDaniel Scheller if (!status) 12615f757bbSDaniel Scheller status = regmap_write(ci->regmap, 3, val); 12715f757bbSDaniel Scheller return status; 12815f757bbSDaniel Scheller } 12915f757bbSDaniel Scheller 13015f757bbSDaniel Scheller static int write_regm(struct cxd *ci, u8 reg, u8 val, u8 mask) 13115f757bbSDaniel Scheller { 13215f757bbSDaniel Scheller int status = 0; 13315f757bbSDaniel Scheller unsigned int regval; 13415f757bbSDaniel Scheller 13515f757bbSDaniel Scheller if (ci->lastaddress != reg) 13615f757bbSDaniel Scheller status = regmap_write(ci->regmap, 0, reg); 13715f757bbSDaniel Scheller if (!status && reg >= 6 && reg <= 8 && mask != 0xff) { 13815f757bbSDaniel Scheller status = regmap_read(ci->regmap, 1, ®val); 13915f757bbSDaniel Scheller ci->regs[reg] = regval; 14015f757bbSDaniel Scheller } 14115f757bbSDaniel Scheller ci->lastaddress = reg; 14215f757bbSDaniel Scheller ci->regs[reg] = (ci->regs[reg] & (~mask)) | val; 14315f757bbSDaniel Scheller if (!status) 14415f757bbSDaniel Scheller status = regmap_write(ci->regmap, 1, ci->regs[reg]); 14515f757bbSDaniel Scheller if (reg == 0x20) 14615f757bbSDaniel Scheller ci->regs[reg] &= 0x7f; 14715f757bbSDaniel Scheller return status; 14815f757bbSDaniel Scheller } 14915f757bbSDaniel Scheller 15015f757bbSDaniel Scheller static int write_reg(struct cxd *ci, u8 reg, u8 val) 15115f757bbSDaniel Scheller { 15215f757bbSDaniel Scheller return write_regm(ci, reg, val, 0xff); 15315f757bbSDaniel Scheller } 15415f757bbSDaniel Scheller 15515f757bbSDaniel Scheller static int write_block(struct cxd *ci, u8 adr, u8 *data, u16 n) 15615f757bbSDaniel Scheller { 15715f757bbSDaniel Scheller int status = 0; 15815f757bbSDaniel Scheller u8 *buf = ci->wbuf; 15915f757bbSDaniel Scheller 16015f757bbSDaniel Scheller if (ci->lastaddress != adr) 16115f757bbSDaniel Scheller status = regmap_write(ci->regmap, 0, adr); 16215f757bbSDaniel Scheller if (status) 16315f757bbSDaniel Scheller return status; 16415f757bbSDaniel Scheller 16515f757bbSDaniel Scheller ci->lastaddress = adr; 16615f757bbSDaniel Scheller while (n) { 16715f757bbSDaniel Scheller int len = n; 16815f757bbSDaniel Scheller 16915f757bbSDaniel Scheller if (ci->cfg.max_i2c && (len + 1 > ci->cfg.max_i2c)) 17015f757bbSDaniel Scheller len = ci->cfg.max_i2c - 1; 17115f757bbSDaniel Scheller memcpy(buf, data, len); 17215f757bbSDaniel Scheller status = regmap_raw_write(ci->regmap, 1, buf, len); 17315f757bbSDaniel Scheller if (status) 17415f757bbSDaniel Scheller return status; 17515f757bbSDaniel Scheller n -= len; 17615f757bbSDaniel Scheller data += len; 17715f757bbSDaniel Scheller } 17815f757bbSDaniel Scheller return status; 17915f757bbSDaniel Scheller } 18015f757bbSDaniel Scheller 18115f757bbSDaniel Scheller static void set_mode(struct cxd *ci, int mode) 18215f757bbSDaniel Scheller { 18315f757bbSDaniel Scheller if (mode == ci->mode) 18415f757bbSDaniel Scheller return; 18515f757bbSDaniel Scheller 18615f757bbSDaniel Scheller switch (mode) { 18715f757bbSDaniel Scheller case 0x00: /* IO mem */ 18815f757bbSDaniel Scheller write_regm(ci, 0x06, 0x00, 0x07); 18915f757bbSDaniel Scheller break; 19015f757bbSDaniel Scheller case 0x01: /* ATT mem */ 19115f757bbSDaniel Scheller write_regm(ci, 0x06, 0x02, 0x07); 19215f757bbSDaniel Scheller break; 19315f757bbSDaniel Scheller default: 19415f757bbSDaniel Scheller break; 19515f757bbSDaniel Scheller } 19615f757bbSDaniel Scheller ci->mode = mode; 19715f757bbSDaniel Scheller } 19815f757bbSDaniel Scheller 19915f757bbSDaniel Scheller static void cam_mode(struct cxd *ci, int mode) 20015f757bbSDaniel Scheller { 20115f757bbSDaniel Scheller u8 dummy; 20215f757bbSDaniel Scheller 20315f757bbSDaniel Scheller if (mode == ci->cammode) 20415f757bbSDaniel Scheller return; 20515f757bbSDaniel Scheller 20615f757bbSDaniel Scheller switch (mode) { 20715f757bbSDaniel Scheller case 0x00: 20815f757bbSDaniel Scheller write_regm(ci, 0x20, 0x80, 0x80); 20915f757bbSDaniel Scheller break; 21015f757bbSDaniel Scheller case 0x01: 21115f757bbSDaniel Scheller if (!ci->en.read_data) 21215f757bbSDaniel Scheller return; 21315f757bbSDaniel Scheller ci->write_busy = 0; 21415f757bbSDaniel Scheller dev_info(&ci->client->dev, "enable cam buffer mode\n"); 21515f757bbSDaniel Scheller write_reg(ci, 0x0d, 0x00); 21615f757bbSDaniel Scheller write_reg(ci, 0x0e, 0x01); 21715f757bbSDaniel Scheller write_regm(ci, 0x08, 0x40, 0x40); 21815f757bbSDaniel Scheller read_reg(ci, 0x12, &dummy); 21915f757bbSDaniel Scheller write_regm(ci, 0x08, 0x80, 0x80); 22015f757bbSDaniel Scheller break; 22115f757bbSDaniel Scheller default: 22215f757bbSDaniel Scheller break; 22315f757bbSDaniel Scheller } 22415f757bbSDaniel Scheller ci->cammode = mode; 22515f757bbSDaniel Scheller } 22615f757bbSDaniel Scheller 22715f757bbSDaniel Scheller static int init(struct cxd *ci) 22815f757bbSDaniel Scheller { 22915f757bbSDaniel Scheller int status; 23015f757bbSDaniel Scheller 23115f757bbSDaniel Scheller mutex_lock(&ci->lock); 23215f757bbSDaniel Scheller ci->mode = -1; 23315f757bbSDaniel Scheller do { 23415f757bbSDaniel Scheller status = write_reg(ci, 0x00, 0x00); 23515f757bbSDaniel Scheller if (status < 0) 23615f757bbSDaniel Scheller break; 23715f757bbSDaniel Scheller status = write_reg(ci, 0x01, 0x00); 23815f757bbSDaniel Scheller if (status < 0) 23915f757bbSDaniel Scheller break; 24015f757bbSDaniel Scheller status = write_reg(ci, 0x02, 0x10); 24115f757bbSDaniel Scheller if (status < 0) 24215f757bbSDaniel Scheller break; 24315f757bbSDaniel Scheller status = write_reg(ci, 0x03, 0x00); 24415f757bbSDaniel Scheller if (status < 0) 24515f757bbSDaniel Scheller break; 24615f757bbSDaniel Scheller status = write_reg(ci, 0x05, 0xFF); 24715f757bbSDaniel Scheller if (status < 0) 24815f757bbSDaniel Scheller break; 24915f757bbSDaniel Scheller status = write_reg(ci, 0x06, 0x1F); 25015f757bbSDaniel Scheller if (status < 0) 25115f757bbSDaniel Scheller break; 25215f757bbSDaniel Scheller status = write_reg(ci, 0x07, 0x1F); 25315f757bbSDaniel Scheller if (status < 0) 25415f757bbSDaniel Scheller break; 25515f757bbSDaniel Scheller status = write_reg(ci, 0x08, 0x28); 25615f757bbSDaniel Scheller if (status < 0) 25715f757bbSDaniel Scheller break; 25815f757bbSDaniel Scheller status = write_reg(ci, 0x14, 0x20); 25915f757bbSDaniel Scheller if (status < 0) 26015f757bbSDaniel Scheller break; 26115f757bbSDaniel Scheller 26215f757bbSDaniel Scheller /* TOSTRT = 8, Mode B (gated clock), falling Edge, 26315f757bbSDaniel Scheller * Serial, POL=HIGH, MSB 26415f757bbSDaniel Scheller */ 26515f757bbSDaniel Scheller status = write_reg(ci, 0x0A, 0xA7); 26615f757bbSDaniel Scheller if (status < 0) 26715f757bbSDaniel Scheller break; 26815f757bbSDaniel Scheller 26915f757bbSDaniel Scheller status = write_reg(ci, 0x0B, 0x33); 27015f757bbSDaniel Scheller if (status < 0) 27115f757bbSDaniel Scheller break; 27215f757bbSDaniel Scheller status = write_reg(ci, 0x0C, 0x33); 27315f757bbSDaniel Scheller if (status < 0) 27415f757bbSDaniel Scheller break; 27515f757bbSDaniel Scheller 27615f757bbSDaniel Scheller status = write_regm(ci, 0x14, 0x00, 0x0F); 27715f757bbSDaniel Scheller if (status < 0) 27815f757bbSDaniel Scheller break; 27915f757bbSDaniel Scheller status = write_reg(ci, 0x15, ci->clk_reg_b); 28015f757bbSDaniel Scheller if (status < 0) 28115f757bbSDaniel Scheller break; 28215f757bbSDaniel Scheller status = write_regm(ci, 0x16, 0x00, 0x0F); 28315f757bbSDaniel Scheller if (status < 0) 28415f757bbSDaniel Scheller break; 28515f757bbSDaniel Scheller status = write_reg(ci, 0x17, ci->clk_reg_f); 28615f757bbSDaniel Scheller if (status < 0) 28715f757bbSDaniel Scheller break; 28815f757bbSDaniel Scheller 28915f757bbSDaniel Scheller if (ci->cfg.clock_mode == 2) { 29015f757bbSDaniel Scheller /* bitrate*2^13/ 72000 */ 29115f757bbSDaniel Scheller u32 reg = ((ci->cfg.bitrate << 13) + 71999) / 72000; 29215f757bbSDaniel Scheller 29315f757bbSDaniel Scheller if (ci->cfg.polarity) { 29415f757bbSDaniel Scheller status = write_reg(ci, 0x09, 0x6f); 29515f757bbSDaniel Scheller if (status < 0) 29615f757bbSDaniel Scheller break; 29715f757bbSDaniel Scheller } else { 29815f757bbSDaniel Scheller status = write_reg(ci, 0x09, 0x6d); 29915f757bbSDaniel Scheller if (status < 0) 30015f757bbSDaniel Scheller break; 30115f757bbSDaniel Scheller } 30215f757bbSDaniel Scheller status = write_reg(ci, 0x20, 0x08); 30315f757bbSDaniel Scheller if (status < 0) 30415f757bbSDaniel Scheller break; 30515f757bbSDaniel Scheller status = write_reg(ci, 0x21, (reg >> 8) & 0xff); 30615f757bbSDaniel Scheller if (status < 0) 30715f757bbSDaniel Scheller break; 30815f757bbSDaniel Scheller status = write_reg(ci, 0x22, reg & 0xff); 30915f757bbSDaniel Scheller if (status < 0) 31015f757bbSDaniel Scheller break; 31115f757bbSDaniel Scheller } else if (ci->cfg.clock_mode == 1) { 31215f757bbSDaniel Scheller if (ci->cfg.polarity) { 31315f757bbSDaniel Scheller status = write_reg(ci, 0x09, 0x6f); /* D */ 31415f757bbSDaniel Scheller if (status < 0) 31515f757bbSDaniel Scheller break; 31615f757bbSDaniel Scheller } else { 31715f757bbSDaniel Scheller status = write_reg(ci, 0x09, 0x6d); 31815f757bbSDaniel Scheller if (status < 0) 31915f757bbSDaniel Scheller break; 32015f757bbSDaniel Scheller } 32115f757bbSDaniel Scheller status = write_reg(ci, 0x20, 0x68); 32215f757bbSDaniel Scheller if (status < 0) 32315f757bbSDaniel Scheller break; 32415f757bbSDaniel Scheller status = write_reg(ci, 0x21, 0x00); 32515f757bbSDaniel Scheller if (status < 0) 32615f757bbSDaniel Scheller break; 32715f757bbSDaniel Scheller status = write_reg(ci, 0x22, 0x02); 32815f757bbSDaniel Scheller if (status < 0) 32915f757bbSDaniel Scheller break; 33015f757bbSDaniel Scheller } else { 33115f757bbSDaniel Scheller if (ci->cfg.polarity) { 33215f757bbSDaniel Scheller status = write_reg(ci, 0x09, 0x4f); /* C */ 33315f757bbSDaniel Scheller if (status < 0) 33415f757bbSDaniel Scheller break; 33515f757bbSDaniel Scheller } else { 33615f757bbSDaniel Scheller status = write_reg(ci, 0x09, 0x4d); 33715f757bbSDaniel Scheller if (status < 0) 33815f757bbSDaniel Scheller break; 33915f757bbSDaniel Scheller } 34015f757bbSDaniel Scheller status = write_reg(ci, 0x20, 0x28); 34115f757bbSDaniel Scheller if (status < 0) 34215f757bbSDaniel Scheller break; 34315f757bbSDaniel Scheller status = write_reg(ci, 0x21, 0x00); 34415f757bbSDaniel Scheller if (status < 0) 34515f757bbSDaniel Scheller break; 34615f757bbSDaniel Scheller status = write_reg(ci, 0x22, 0x07); 34715f757bbSDaniel Scheller if (status < 0) 34815f757bbSDaniel Scheller break; 34915f757bbSDaniel Scheller } 35015f757bbSDaniel Scheller 35115f757bbSDaniel Scheller status = write_regm(ci, 0x20, 0x80, 0x80); 35215f757bbSDaniel Scheller if (status < 0) 35315f757bbSDaniel Scheller break; 35415f757bbSDaniel Scheller status = write_regm(ci, 0x03, 0x02, 0x02); 35515f757bbSDaniel Scheller if (status < 0) 35615f757bbSDaniel Scheller break; 35715f757bbSDaniel Scheller status = write_reg(ci, 0x01, 0x04); 35815f757bbSDaniel Scheller if (status < 0) 35915f757bbSDaniel Scheller break; 36015f757bbSDaniel Scheller status = write_reg(ci, 0x00, 0x31); 36115f757bbSDaniel Scheller if (status < 0) 36215f757bbSDaniel Scheller break; 36315f757bbSDaniel Scheller 36415f757bbSDaniel Scheller /* Put TS in bypass */ 36515f757bbSDaniel Scheller status = write_regm(ci, 0x09, 0x08, 0x08); 36615f757bbSDaniel Scheller if (status < 0) 36715f757bbSDaniel Scheller break; 36815f757bbSDaniel Scheller ci->cammode = -1; 36915f757bbSDaniel Scheller cam_mode(ci, 0); 37015f757bbSDaniel Scheller } while (0); 37115f757bbSDaniel Scheller mutex_unlock(&ci->lock); 37215f757bbSDaniel Scheller 37315f757bbSDaniel Scheller return 0; 37415f757bbSDaniel Scheller } 37515f757bbSDaniel Scheller 37615f757bbSDaniel Scheller static int read_attribute_mem(struct dvb_ca_en50221 *ca, 37715f757bbSDaniel Scheller int slot, int address) 37815f757bbSDaniel Scheller { 37915f757bbSDaniel Scheller struct cxd *ci = ca->data; 38015f757bbSDaniel Scheller u8 val; 38115f757bbSDaniel Scheller 38215f757bbSDaniel Scheller mutex_lock(&ci->lock); 38315f757bbSDaniel Scheller set_mode(ci, 1); 38415f757bbSDaniel Scheller read_pccard(ci, address, &val, 1); 38515f757bbSDaniel Scheller mutex_unlock(&ci->lock); 38615f757bbSDaniel Scheller return val; 38715f757bbSDaniel Scheller } 38815f757bbSDaniel Scheller 38915f757bbSDaniel Scheller static int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, 39015f757bbSDaniel Scheller int address, u8 value) 39115f757bbSDaniel Scheller { 39215f757bbSDaniel Scheller struct cxd *ci = ca->data; 39315f757bbSDaniel Scheller 39415f757bbSDaniel Scheller mutex_lock(&ci->lock); 39515f757bbSDaniel Scheller set_mode(ci, 1); 39615f757bbSDaniel Scheller write_pccard(ci, address, &value, 1); 39715f757bbSDaniel Scheller mutex_unlock(&ci->lock); 39815f757bbSDaniel Scheller return 0; 39915f757bbSDaniel Scheller } 40015f757bbSDaniel Scheller 40115f757bbSDaniel Scheller static int read_cam_control(struct dvb_ca_en50221 *ca, 40215f757bbSDaniel Scheller int slot, u8 address) 40315f757bbSDaniel Scheller { 40415f757bbSDaniel Scheller struct cxd *ci = ca->data; 40515f757bbSDaniel Scheller unsigned int val; 40615f757bbSDaniel Scheller 40715f757bbSDaniel Scheller mutex_lock(&ci->lock); 40815f757bbSDaniel Scheller set_mode(ci, 0); 40915f757bbSDaniel Scheller read_io(ci, address, &val); 41015f757bbSDaniel Scheller mutex_unlock(&ci->lock); 41115f757bbSDaniel Scheller return val; 41215f757bbSDaniel Scheller } 41315f757bbSDaniel Scheller 41415f757bbSDaniel Scheller static int write_cam_control(struct dvb_ca_en50221 *ca, int slot, 41515f757bbSDaniel Scheller u8 address, u8 value) 41615f757bbSDaniel Scheller { 41715f757bbSDaniel Scheller struct cxd *ci = ca->data; 41815f757bbSDaniel Scheller 41915f757bbSDaniel Scheller mutex_lock(&ci->lock); 42015f757bbSDaniel Scheller set_mode(ci, 0); 42115f757bbSDaniel Scheller write_io(ci, address, value); 42215f757bbSDaniel Scheller mutex_unlock(&ci->lock); 42315f757bbSDaniel Scheller return 0; 42415f757bbSDaniel Scheller } 42515f757bbSDaniel Scheller 42615f757bbSDaniel Scheller static int slot_reset(struct dvb_ca_en50221 *ca, int slot) 42715f757bbSDaniel Scheller { 42815f757bbSDaniel Scheller struct cxd *ci = ca->data; 42915f757bbSDaniel Scheller 43015f757bbSDaniel Scheller if (ci->cammode) 43115f757bbSDaniel Scheller read_data(ca, slot, ci->rbuf, 0); 43215f757bbSDaniel Scheller 43315f757bbSDaniel Scheller mutex_lock(&ci->lock); 43415f757bbSDaniel Scheller cam_mode(ci, 0); 43515f757bbSDaniel Scheller write_reg(ci, 0x00, 0x21); 43615f757bbSDaniel Scheller write_reg(ci, 0x06, 0x1F); 43715f757bbSDaniel Scheller write_reg(ci, 0x00, 0x31); 43815f757bbSDaniel Scheller write_regm(ci, 0x20, 0x80, 0x80); 43915f757bbSDaniel Scheller write_reg(ci, 0x03, 0x02); 44015f757bbSDaniel Scheller ci->ready = 0; 44115f757bbSDaniel Scheller ci->mode = -1; 44215f757bbSDaniel Scheller { 44315f757bbSDaniel Scheller int i; 44415f757bbSDaniel Scheller 44515f757bbSDaniel Scheller for (i = 0; i < 100; i++) { 44615f757bbSDaniel Scheller usleep_range(10000, 11000); 44715f757bbSDaniel Scheller if (ci->ready) 44815f757bbSDaniel Scheller break; 44915f757bbSDaniel Scheller } 45015f757bbSDaniel Scheller } 45115f757bbSDaniel Scheller mutex_unlock(&ci->lock); 45215f757bbSDaniel Scheller return 0; 45315f757bbSDaniel Scheller } 45415f757bbSDaniel Scheller 45515f757bbSDaniel Scheller static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot) 45615f757bbSDaniel Scheller { 45715f757bbSDaniel Scheller struct cxd *ci = ca->data; 45815f757bbSDaniel Scheller 45915f757bbSDaniel Scheller dev_dbg(&ci->client->dev, "%s\n", __func__); 46015f757bbSDaniel Scheller if (ci->cammode) 46115f757bbSDaniel Scheller read_data(ca, slot, ci->rbuf, 0); 46215f757bbSDaniel Scheller mutex_lock(&ci->lock); 46315f757bbSDaniel Scheller write_reg(ci, 0x00, 0x21); 46415f757bbSDaniel Scheller write_reg(ci, 0x06, 0x1F); 46515f757bbSDaniel Scheller msleep(300); 46615f757bbSDaniel Scheller 46715f757bbSDaniel Scheller write_regm(ci, 0x09, 0x08, 0x08); 46815f757bbSDaniel Scheller write_regm(ci, 0x20, 0x80, 0x80); /* Reset CAM Mode */ 46915f757bbSDaniel Scheller write_regm(ci, 0x06, 0x07, 0x07); /* Clear IO Mode */ 47015f757bbSDaniel Scheller 47115f757bbSDaniel Scheller ci->mode = -1; 47215f757bbSDaniel Scheller ci->write_busy = 0; 47315f757bbSDaniel Scheller mutex_unlock(&ci->lock); 47415f757bbSDaniel Scheller return 0; 47515f757bbSDaniel Scheller } 47615f757bbSDaniel Scheller 47715f757bbSDaniel Scheller static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) 47815f757bbSDaniel Scheller { 47915f757bbSDaniel Scheller struct cxd *ci = ca->data; 48015f757bbSDaniel Scheller 48115f757bbSDaniel Scheller mutex_lock(&ci->lock); 48215f757bbSDaniel Scheller write_regm(ci, 0x09, 0x00, 0x08); 48315f757bbSDaniel Scheller set_mode(ci, 0); 48415f757bbSDaniel Scheller cam_mode(ci, 1); 48515f757bbSDaniel Scheller mutex_unlock(&ci->lock); 48615f757bbSDaniel Scheller return 0; 48715f757bbSDaniel Scheller } 48815f757bbSDaniel Scheller 48915f757bbSDaniel Scheller static int campoll(struct cxd *ci) 49015f757bbSDaniel Scheller { 49115f757bbSDaniel Scheller u8 istat; 49215f757bbSDaniel Scheller 49315f757bbSDaniel Scheller read_reg(ci, 0x04, &istat); 49415f757bbSDaniel Scheller if (!istat) 49515f757bbSDaniel Scheller return 0; 49615f757bbSDaniel Scheller write_reg(ci, 0x05, istat); 49715f757bbSDaniel Scheller 49815f757bbSDaniel Scheller if (istat & 0x40) 49915f757bbSDaniel Scheller ci->dr = 1; 50015f757bbSDaniel Scheller if (istat & 0x20) 50115f757bbSDaniel Scheller ci->write_busy = 0; 50215f757bbSDaniel Scheller 50315f757bbSDaniel Scheller if (istat & 2) { 50415f757bbSDaniel Scheller u8 slotstat; 50515f757bbSDaniel Scheller 50615f757bbSDaniel Scheller read_reg(ci, 0x01, &slotstat); 50715f757bbSDaniel Scheller if (!(2 & slotstat)) { 50815f757bbSDaniel Scheller if (!ci->slot_stat) { 50915f757bbSDaniel Scheller ci->slot_stat |= 51015f757bbSDaniel Scheller DVB_CA_EN50221_POLL_CAM_PRESENT; 51115f757bbSDaniel Scheller write_regm(ci, 0x03, 0x08, 0x08); 51215f757bbSDaniel Scheller } 51315f757bbSDaniel Scheller 51415f757bbSDaniel Scheller } else { 51515f757bbSDaniel Scheller if (ci->slot_stat) { 51615f757bbSDaniel Scheller ci->slot_stat = 0; 51715f757bbSDaniel Scheller write_regm(ci, 0x03, 0x00, 0x08); 51815f757bbSDaniel Scheller dev_info(&ci->client->dev, "NO CAM\n"); 51915f757bbSDaniel Scheller ci->ready = 0; 52015f757bbSDaniel Scheller } 52115f757bbSDaniel Scheller } 52215f757bbSDaniel Scheller if ((istat & 8) && 52315f757bbSDaniel Scheller ci->slot_stat == DVB_CA_EN50221_POLL_CAM_PRESENT) { 52415f757bbSDaniel Scheller ci->ready = 1; 52515f757bbSDaniel Scheller ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_READY; 52615f757bbSDaniel Scheller } 52715f757bbSDaniel Scheller } 52815f757bbSDaniel Scheller return 0; 52915f757bbSDaniel Scheller } 53015f757bbSDaniel Scheller 53115f757bbSDaniel Scheller static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) 53215f757bbSDaniel Scheller { 53315f757bbSDaniel Scheller struct cxd *ci = ca->data; 53415f757bbSDaniel Scheller u8 slotstat; 53515f757bbSDaniel Scheller 53615f757bbSDaniel Scheller mutex_lock(&ci->lock); 53715f757bbSDaniel Scheller campoll(ci); 53815f757bbSDaniel Scheller read_reg(ci, 0x01, &slotstat); 53915f757bbSDaniel Scheller mutex_unlock(&ci->lock); 54015f757bbSDaniel Scheller 54115f757bbSDaniel Scheller return ci->slot_stat; 54215f757bbSDaniel Scheller } 54315f757bbSDaniel Scheller 54415f757bbSDaniel Scheller static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount) 54515f757bbSDaniel Scheller { 54615f757bbSDaniel Scheller struct cxd *ci = ca->data; 54715f757bbSDaniel Scheller u8 msb, lsb; 54815f757bbSDaniel Scheller u16 len; 54915f757bbSDaniel Scheller 55015f757bbSDaniel Scheller mutex_lock(&ci->lock); 55115f757bbSDaniel Scheller campoll(ci); 55215f757bbSDaniel Scheller mutex_unlock(&ci->lock); 55315f757bbSDaniel Scheller 55415f757bbSDaniel Scheller if (!ci->dr) 55515f757bbSDaniel Scheller return 0; 55615f757bbSDaniel Scheller 55715f757bbSDaniel Scheller mutex_lock(&ci->lock); 55815f757bbSDaniel Scheller read_reg(ci, 0x0f, &msb); 55915f757bbSDaniel Scheller read_reg(ci, 0x10, &lsb); 56015f757bbSDaniel Scheller len = ((u16)msb << 8) | lsb; 56115f757bbSDaniel Scheller if (len > ecount || len < 2) { 56215f757bbSDaniel Scheller /* read it anyway or cxd may hang */ 56315f757bbSDaniel Scheller read_block(ci, 0x12, ci->rbuf, len); 56415f757bbSDaniel Scheller mutex_unlock(&ci->lock); 56515f757bbSDaniel Scheller return -EIO; 56615f757bbSDaniel Scheller } 56715f757bbSDaniel Scheller read_block(ci, 0x12, ebuf, len); 56815f757bbSDaniel Scheller ci->dr = 0; 56915f757bbSDaniel Scheller mutex_unlock(&ci->lock); 57015f757bbSDaniel Scheller return len; 57115f757bbSDaniel Scheller } 57215f757bbSDaniel Scheller 57315f757bbSDaniel Scheller static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount) 57415f757bbSDaniel Scheller { 57515f757bbSDaniel Scheller struct cxd *ci = ca->data; 57615f757bbSDaniel Scheller 57715f757bbSDaniel Scheller if (ci->write_busy) 57815f757bbSDaniel Scheller return -EAGAIN; 57915f757bbSDaniel Scheller mutex_lock(&ci->lock); 58015f757bbSDaniel Scheller write_reg(ci, 0x0d, ecount >> 8); 58115f757bbSDaniel Scheller write_reg(ci, 0x0e, ecount & 0xff); 58215f757bbSDaniel Scheller write_block(ci, 0x11, ebuf, ecount); 58315f757bbSDaniel Scheller ci->write_busy = 1; 58415f757bbSDaniel Scheller mutex_unlock(&ci->lock); 58515f757bbSDaniel Scheller return ecount; 58615f757bbSDaniel Scheller } 58715f757bbSDaniel Scheller 5886f005abbSNishka Dasgupta static const struct dvb_ca_en50221 en_templ = { 58915f757bbSDaniel Scheller .read_attribute_mem = read_attribute_mem, 59015f757bbSDaniel Scheller .write_attribute_mem = write_attribute_mem, 59115f757bbSDaniel Scheller .read_cam_control = read_cam_control, 59215f757bbSDaniel Scheller .write_cam_control = write_cam_control, 59315f757bbSDaniel Scheller .slot_reset = slot_reset, 59415f757bbSDaniel Scheller .slot_shutdown = slot_shutdown, 59515f757bbSDaniel Scheller .slot_ts_enable = slot_ts_enable, 59615f757bbSDaniel Scheller .poll_slot_status = poll_slot_status, 59715f757bbSDaniel Scheller .read_data = read_data, 59815f757bbSDaniel Scheller .write_data = write_data, 59915f757bbSDaniel Scheller }; 60015f757bbSDaniel Scheller 60115f757bbSDaniel Scheller static int cxd2099_probe(struct i2c_client *client, 60215f757bbSDaniel Scheller const struct i2c_device_id *id) 60315f757bbSDaniel Scheller { 60415f757bbSDaniel Scheller struct cxd *ci; 60515f757bbSDaniel Scheller struct cxd2099_cfg *cfg = client->dev.platform_data; 60615f757bbSDaniel Scheller static const struct regmap_config rm_cfg = { 60715f757bbSDaniel Scheller .reg_bits = 8, 60815f757bbSDaniel Scheller .val_bits = 8, 60915f757bbSDaniel Scheller }; 61015f757bbSDaniel Scheller unsigned int val; 61115f757bbSDaniel Scheller int ret; 61215f757bbSDaniel Scheller 61315f757bbSDaniel Scheller ci = kzalloc(sizeof(*ci), GFP_KERNEL); 61415f757bbSDaniel Scheller if (!ci) { 61515f757bbSDaniel Scheller ret = -ENOMEM; 61615f757bbSDaniel Scheller goto err; 61715f757bbSDaniel Scheller } 61815f757bbSDaniel Scheller 61915f757bbSDaniel Scheller ci->client = client; 62015f757bbSDaniel Scheller memcpy(&ci->cfg, cfg, sizeof(ci->cfg)); 62115f757bbSDaniel Scheller 62215f757bbSDaniel Scheller ci->regmap = regmap_init_i2c(client, &rm_cfg); 62315f757bbSDaniel Scheller if (IS_ERR(ci->regmap)) { 62415f757bbSDaniel Scheller ret = PTR_ERR(ci->regmap); 62515f757bbSDaniel Scheller goto err_kfree; 62615f757bbSDaniel Scheller } 62715f757bbSDaniel Scheller 62815f757bbSDaniel Scheller ret = regmap_read(ci->regmap, 0x00, &val); 62915f757bbSDaniel Scheller if (ret < 0) { 63015f757bbSDaniel Scheller dev_info(&client->dev, "No CXD2099AR detected at 0x%02x\n", 63115f757bbSDaniel Scheller client->addr); 63215f757bbSDaniel Scheller goto err_rmexit; 63315f757bbSDaniel Scheller } 63415f757bbSDaniel Scheller 63515f757bbSDaniel Scheller mutex_init(&ci->lock); 63615f757bbSDaniel Scheller ci->lastaddress = 0xff; 63715f757bbSDaniel Scheller ci->clk_reg_b = 0x4a; 63815f757bbSDaniel Scheller ci->clk_reg_f = 0x1b; 63915f757bbSDaniel Scheller 64015f757bbSDaniel Scheller ci->en = en_templ; 64115f757bbSDaniel Scheller ci->en.data = ci; 64215f757bbSDaniel Scheller init(ci); 64315f757bbSDaniel Scheller dev_info(&client->dev, "Attached CXD2099AR at 0x%02x\n", client->addr); 64415f757bbSDaniel Scheller 64515f757bbSDaniel Scheller *cfg->en = &ci->en; 64615f757bbSDaniel Scheller 64715f757bbSDaniel Scheller if (!buffermode) { 64815f757bbSDaniel Scheller ci->en.read_data = NULL; 64915f757bbSDaniel Scheller ci->en.write_data = NULL; 65015f757bbSDaniel Scheller } else { 65115f757bbSDaniel Scheller dev_info(&client->dev, "Using CXD2099AR buffer mode"); 65215f757bbSDaniel Scheller } 65315f757bbSDaniel Scheller 65415f757bbSDaniel Scheller i2c_set_clientdata(client, ci); 65515f757bbSDaniel Scheller 65615f757bbSDaniel Scheller return 0; 65715f757bbSDaniel Scheller 65815f757bbSDaniel Scheller err_rmexit: 65915f757bbSDaniel Scheller regmap_exit(ci->regmap); 66015f757bbSDaniel Scheller err_kfree: 66115f757bbSDaniel Scheller kfree(ci); 66215f757bbSDaniel Scheller err: 66315f757bbSDaniel Scheller 66415f757bbSDaniel Scheller return ret; 66515f757bbSDaniel Scheller } 66615f757bbSDaniel Scheller 667*ed5c2f5fSUwe Kleine-König static void cxd2099_remove(struct i2c_client *client) 66815f757bbSDaniel Scheller { 66915f757bbSDaniel Scheller struct cxd *ci = i2c_get_clientdata(client); 67015f757bbSDaniel Scheller 67115f757bbSDaniel Scheller regmap_exit(ci->regmap); 67215f757bbSDaniel Scheller kfree(ci); 67315f757bbSDaniel Scheller } 67415f757bbSDaniel Scheller 67515f757bbSDaniel Scheller static const struct i2c_device_id cxd2099_id[] = { 67615f757bbSDaniel Scheller {"cxd2099", 0}, 67715f757bbSDaniel Scheller {} 67815f757bbSDaniel Scheller }; 67915f757bbSDaniel Scheller MODULE_DEVICE_TABLE(i2c, cxd2099_id); 68015f757bbSDaniel Scheller 68115f757bbSDaniel Scheller static struct i2c_driver cxd2099_driver = { 68215f757bbSDaniel Scheller .driver = { 68315f757bbSDaniel Scheller .name = "cxd2099", 68415f757bbSDaniel Scheller }, 68515f757bbSDaniel Scheller .probe = cxd2099_probe, 68615f757bbSDaniel Scheller .remove = cxd2099_remove, 68715f757bbSDaniel Scheller .id_table = cxd2099_id, 68815f757bbSDaniel Scheller }; 68915f757bbSDaniel Scheller 69015f757bbSDaniel Scheller module_i2c_driver(cxd2099_driver); 69115f757bbSDaniel Scheller 6922dc3e050SDaniel Scheller MODULE_DESCRIPTION("Sony CXD2099AR Common Interface controller driver"); 69315f757bbSDaniel Scheller MODULE_AUTHOR("Ralph Metzler"); 694579856feSDaniel Scheller MODULE_LICENSE("GPL v2"); 695