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