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