13dae3c96SDaniel Scheller // SPDX-License-Identifier: GPL-2.0 20f0b270fSRalph Metzler /* 32dc3e050SDaniel Scheller * cxd2099.c: Driver for the Sony CXD2099AR Common Interface Controller 40f0b270fSRalph Metzler * 5dd3c5d00SRalph Metzler * Copyright (C) 2010-2013 Digital Devices GmbH 60f0b270fSRalph Metzler */ 70f0b270fSRalph Metzler 80f0b270fSRalph Metzler #include <linux/slab.h> 90f0b270fSRalph Metzler #include <linux/kernel.h> 100f0b270fSRalph Metzler #include <linux/module.h> 110f0b270fSRalph Metzler #include <linux/i2c.h> 1281a70591SDaniel Scheller #include <linux/regmap.h> 130f0b270fSRalph Metzler #include <linux/wait.h> 140f0b270fSRalph Metzler #include <linux/delay.h> 150f0b270fSRalph Metzler #include <linux/mutex.h> 160f0b270fSRalph Metzler #include <linux/io.h> 170f0b270fSRalph Metzler 180f0b270fSRalph Metzler #include "cxd2099.h" 190f0b270fSRalph Metzler 202b64e4deSDaniel Scheller static int buffermode; 212b64e4deSDaniel Scheller module_param(buffermode, int, 0444); 226c84bbfeSDaniel Scheller MODULE_PARM_DESC(buffermode, "Enable CXD2099AR buffer mode (default: disabled)"); 23dd3c5d00SRalph Metzler 24dd3c5d00SRalph Metzler static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount); 250f0b270fSRalph Metzler 260f0b270fSRalph Metzler struct cxd { 270f0b270fSRalph Metzler struct dvb_ca_en50221 en; 280f0b270fSRalph Metzler 296eb94193SRalph Metzler struct cxd2099_cfg cfg; 3081a70591SDaniel Scheller struct i2c_client *client; 3181a70591SDaniel Scheller struct regmap *regmap; 326eb94193SRalph Metzler 330f0b270fSRalph Metzler u8 regs[0x23]; 340f0b270fSRalph Metzler u8 lastaddress; 350f0b270fSRalph Metzler u8 clk_reg_f; 360f0b270fSRalph Metzler u8 clk_reg_b; 370f0b270fSRalph Metzler int mode; 380f0b270fSRalph Metzler int ready; 390f0b270fSRalph Metzler int dr; 40dd3c5d00SRalph Metzler int write_busy; 410f0b270fSRalph Metzler int slot_stat; 420f0b270fSRalph Metzler 430f0b270fSRalph Metzler u8 amem[1024]; 440f0b270fSRalph Metzler int amem_read; 450f0b270fSRalph Metzler 460f0b270fSRalph Metzler int cammode; 4765ac8c84SDaniel Scheller struct mutex lock; /* device access lock */ 48dd3c5d00SRalph Metzler 49dd3c5d00SRalph Metzler u8 rbuf[1028]; 50dd3c5d00SRalph Metzler u8 wbuf[1028]; 510f0b270fSRalph Metzler }; 520f0b270fSRalph Metzler 53dd3c5d00SRalph Metzler static int read_block(struct cxd *ci, u8 adr, u8 *data, u16 n) 540f0b270fSRalph Metzler { 55dd3c5d00SRalph Metzler int status = 0; 560f0b270fSRalph Metzler 57dd3c5d00SRalph Metzler if (ci->lastaddress != adr) 5881a70591SDaniel Scheller status = regmap_write(ci->regmap, 0, adr); 590f0b270fSRalph Metzler if (!status) { 600f0b270fSRalph Metzler ci->lastaddress = adr; 61dd3c5d00SRalph Metzler 62dd3c5d00SRalph Metzler while (n) { 63dd3c5d00SRalph Metzler int len = n; 64dd3c5d00SRalph Metzler 6565ac8c84SDaniel Scheller if (ci->cfg.max_i2c && len > ci->cfg.max_i2c) 66dd3c5d00SRalph Metzler len = ci->cfg.max_i2c; 6781a70591SDaniel Scheller status = regmap_raw_read(ci->regmap, 1, data, len); 68dd3c5d00SRalph Metzler if (status) 69dd3c5d00SRalph Metzler return status; 70dd3c5d00SRalph Metzler data += len; 71dd3c5d00SRalph Metzler n -= len; 72dd3c5d00SRalph Metzler } 730f0b270fSRalph Metzler } 740f0b270fSRalph Metzler return status; 750f0b270fSRalph Metzler } 760f0b270fSRalph Metzler 770f0b270fSRalph Metzler static int read_reg(struct cxd *ci, u8 reg, u8 *val) 780f0b270fSRalph Metzler { 790f0b270fSRalph Metzler return read_block(ci, reg, val, 1); 800f0b270fSRalph Metzler } 810f0b270fSRalph Metzler 820f0b270fSRalph Metzler static int read_pccard(struct cxd *ci, u16 address, u8 *data, u8 n) 830f0b270fSRalph Metzler { 840f0b270fSRalph Metzler int status; 8581a70591SDaniel Scheller u8 addr[2] = {address & 0xff, address >> 8}; 860f0b270fSRalph Metzler 8781a70591SDaniel Scheller status = regmap_raw_write(ci->regmap, 2, addr, 2); 880f0b270fSRalph Metzler if (!status) 8981a70591SDaniel Scheller status = regmap_raw_read(ci->regmap, 3, data, n); 900f0b270fSRalph Metzler return status; 910f0b270fSRalph Metzler } 920f0b270fSRalph Metzler 930f0b270fSRalph Metzler static int write_pccard(struct cxd *ci, u16 address, u8 *data, u8 n) 940f0b270fSRalph Metzler { 950f0b270fSRalph Metzler int status; 9681a70591SDaniel Scheller u8 addr[2] = {address & 0xff, address >> 8}; 970f0b270fSRalph Metzler 9881a70591SDaniel Scheller status = regmap_raw_write(ci->regmap, 2, addr, 2); 990f0b270fSRalph Metzler if (!status) { 10081a70591SDaniel Scheller u8 buf[256]; 101fcf1b73dSAybuke Ozdemir 10281a70591SDaniel Scheller memcpy(buf, data, n); 10381a70591SDaniel Scheller status = regmap_raw_write(ci->regmap, 3, buf, n); 1040f0b270fSRalph Metzler } 1050f0b270fSRalph Metzler return status; 1060f0b270fSRalph Metzler } 1070f0b270fSRalph Metzler 10881a70591SDaniel Scheller static int read_io(struct cxd *ci, u16 address, unsigned int *val) 1090f0b270fSRalph Metzler { 1100f0b270fSRalph Metzler int status; 11181a70591SDaniel Scheller u8 addr[2] = {address & 0xff, address >> 8}; 1120f0b270fSRalph Metzler 11381a70591SDaniel Scheller status = regmap_raw_write(ci->regmap, 2, addr, 2); 1140f0b270fSRalph Metzler if (!status) 11581a70591SDaniel Scheller status = regmap_read(ci->regmap, 3, val); 1160f0b270fSRalph Metzler return status; 1170f0b270fSRalph Metzler } 1180f0b270fSRalph Metzler 1190f0b270fSRalph Metzler static int write_io(struct cxd *ci, u16 address, u8 val) 1200f0b270fSRalph Metzler { 1210f0b270fSRalph Metzler int status; 12281a70591SDaniel Scheller u8 addr[2] = {address & 0xff, address >> 8}; 1230f0b270fSRalph Metzler 12481a70591SDaniel Scheller status = regmap_raw_write(ci->regmap, 2, addr, 2); 1250f0b270fSRalph Metzler if (!status) 12681a70591SDaniel Scheller status = regmap_write(ci->regmap, 3, val); 1270f0b270fSRalph Metzler return status; 1280f0b270fSRalph Metzler } 1290f0b270fSRalph Metzler 1300f0b270fSRalph Metzler static int write_regm(struct cxd *ci, u8 reg, u8 val, u8 mask) 1310f0b270fSRalph Metzler { 132dd3c5d00SRalph Metzler int status = 0; 13381a70591SDaniel Scheller unsigned int regval; 1340f0b270fSRalph Metzler 135dd3c5d00SRalph Metzler if (ci->lastaddress != reg) 13681a70591SDaniel Scheller status = regmap_write(ci->regmap, 0, reg); 13781a70591SDaniel Scheller if (!status && reg >= 6 && reg <= 8 && mask != 0xff) { 13881a70591SDaniel Scheller status = regmap_read(ci->regmap, 1, ®val); 13981a70591SDaniel Scheller ci->regs[reg] = regval; 14081a70591SDaniel Scheller } 1410f0b270fSRalph Metzler ci->lastaddress = reg; 142dd3c5d00SRalph Metzler ci->regs[reg] = (ci->regs[reg] & (~mask)) | val; 143dd3c5d00SRalph Metzler if (!status) 14481a70591SDaniel Scheller status = regmap_write(ci->regmap, 1, ci->regs[reg]); 1450f0b270fSRalph Metzler if (reg == 0x20) 1460f0b270fSRalph Metzler ci->regs[reg] &= 0x7f; 1470f0b270fSRalph Metzler return status; 1480f0b270fSRalph Metzler } 1490f0b270fSRalph Metzler 1500f0b270fSRalph Metzler static int write_reg(struct cxd *ci, u8 reg, u8 val) 1510f0b270fSRalph Metzler { 1520f0b270fSRalph Metzler return write_regm(ci, reg, val, 0xff); 1530f0b270fSRalph Metzler } 1540f0b270fSRalph Metzler 155dd3c5d00SRalph Metzler static int write_block(struct cxd *ci, u8 adr, u8 *data, u16 n) 1560f0b270fSRalph Metzler { 157dd3c5d00SRalph Metzler int status = 0; 158dd3c5d00SRalph Metzler u8 *buf = ci->wbuf; 1590f0b270fSRalph Metzler 160dd3c5d00SRalph Metzler if (ci->lastaddress != adr) 16181a70591SDaniel Scheller status = regmap_write(ci->regmap, 0, adr); 162dd3c5d00SRalph Metzler if (status) 163dd3c5d00SRalph Metzler return status; 164dd3c5d00SRalph Metzler 1650f0b270fSRalph Metzler ci->lastaddress = adr; 166dd3c5d00SRalph Metzler while (n) { 167dd3c5d00SRalph Metzler int len = n; 168dd3c5d00SRalph Metzler 169dd3c5d00SRalph Metzler if (ci->cfg.max_i2c && (len + 1 > ci->cfg.max_i2c)) 170dd3c5d00SRalph Metzler len = ci->cfg.max_i2c - 1; 17181a70591SDaniel Scheller memcpy(buf, data, len); 17281a70591SDaniel Scheller status = regmap_raw_write(ci->regmap, 1, buf, len); 173dd3c5d00SRalph Metzler if (status) 174dd3c5d00SRalph Metzler return status; 175dd3c5d00SRalph Metzler n -= len; 176dd3c5d00SRalph Metzler data += len; 1770f0b270fSRalph Metzler } 1780f0b270fSRalph Metzler return status; 1790f0b270fSRalph Metzler } 1800f0b270fSRalph Metzler 1810f0b270fSRalph Metzler static void set_mode(struct cxd *ci, int mode) 1820f0b270fSRalph Metzler { 1830f0b270fSRalph Metzler if (mode == ci->mode) 1840f0b270fSRalph Metzler return; 1850f0b270fSRalph Metzler 1860f0b270fSRalph Metzler switch (mode) { 1870f0b270fSRalph Metzler case 0x00: /* IO mem */ 1880f0b270fSRalph Metzler write_regm(ci, 0x06, 0x00, 0x07); 1890f0b270fSRalph Metzler break; 1900f0b270fSRalph Metzler case 0x01: /* ATT mem */ 1910f0b270fSRalph Metzler write_regm(ci, 0x06, 0x02, 0x07); 1920f0b270fSRalph Metzler break; 1930f0b270fSRalph Metzler default: 1940f0b270fSRalph Metzler break; 1950f0b270fSRalph Metzler } 1960f0b270fSRalph Metzler ci->mode = mode; 1970f0b270fSRalph Metzler } 1980f0b270fSRalph Metzler 1990f0b270fSRalph Metzler static void cam_mode(struct cxd *ci, int mode) 2000f0b270fSRalph Metzler { 201dd3c5d00SRalph Metzler u8 dummy; 202dd3c5d00SRalph Metzler 2030f0b270fSRalph Metzler if (mode == ci->cammode) 2040f0b270fSRalph Metzler return; 2050f0b270fSRalph Metzler 2060f0b270fSRalph Metzler switch (mode) { 2070f0b270fSRalph Metzler case 0x00: 2080f0b270fSRalph Metzler write_regm(ci, 0x20, 0x80, 0x80); 2090f0b270fSRalph Metzler break; 2100f0b270fSRalph Metzler case 0x01: 2116eb94193SRalph Metzler if (!ci->en.read_data) 2126eb94193SRalph Metzler return; 213dd3c5d00SRalph Metzler ci->write_busy = 0; 21481a70591SDaniel Scheller dev_info(&ci->client->dev, "enable cam buffer mode\n"); 215dd3c5d00SRalph Metzler write_reg(ci, 0x0d, 0x00); 216dd3c5d00SRalph Metzler write_reg(ci, 0x0e, 0x01); 2170f0b270fSRalph Metzler write_regm(ci, 0x08, 0x40, 0x40); 218dd3c5d00SRalph Metzler read_reg(ci, 0x12, &dummy); 2190f0b270fSRalph Metzler write_regm(ci, 0x08, 0x80, 0x80); 2200f0b270fSRalph Metzler break; 2210f0b270fSRalph Metzler default: 2220f0b270fSRalph Metzler break; 2230f0b270fSRalph Metzler } 2240f0b270fSRalph Metzler ci->cammode = mode; 2250f0b270fSRalph Metzler } 2260f0b270fSRalph Metzler 2270f0b270fSRalph Metzler static int init(struct cxd *ci) 2280f0b270fSRalph Metzler { 2290f0b270fSRalph Metzler int status; 2300f0b270fSRalph Metzler 2310f0b270fSRalph Metzler mutex_lock(&ci->lock); 2320f0b270fSRalph Metzler ci->mode = -1; 2330f0b270fSRalph Metzler do { 234af070bd6SMauro Carvalho Chehab status = write_reg(ci, 0x00, 0x00); 235af070bd6SMauro Carvalho Chehab if (status < 0) 236af070bd6SMauro Carvalho Chehab break; 237af070bd6SMauro Carvalho Chehab status = write_reg(ci, 0x01, 0x00); 238af070bd6SMauro Carvalho Chehab if (status < 0) 239af070bd6SMauro Carvalho Chehab break; 240af070bd6SMauro Carvalho Chehab status = write_reg(ci, 0x02, 0x10); 241af070bd6SMauro Carvalho Chehab if (status < 0) 242af070bd6SMauro Carvalho Chehab break; 243af070bd6SMauro Carvalho Chehab status = write_reg(ci, 0x03, 0x00); 244af070bd6SMauro Carvalho Chehab if (status < 0) 245af070bd6SMauro Carvalho Chehab break; 246af070bd6SMauro Carvalho Chehab status = write_reg(ci, 0x05, 0xFF); 247af070bd6SMauro Carvalho Chehab if (status < 0) 248af070bd6SMauro Carvalho Chehab break; 249af070bd6SMauro Carvalho Chehab status = write_reg(ci, 0x06, 0x1F); 250af070bd6SMauro Carvalho Chehab if (status < 0) 251af070bd6SMauro Carvalho Chehab break; 252af070bd6SMauro Carvalho Chehab status = write_reg(ci, 0x07, 0x1F); 253af070bd6SMauro Carvalho Chehab if (status < 0) 254af070bd6SMauro Carvalho Chehab break; 255af070bd6SMauro Carvalho Chehab status = write_reg(ci, 0x08, 0x28); 256af070bd6SMauro Carvalho Chehab if (status < 0) 257af070bd6SMauro Carvalho Chehab break; 258af070bd6SMauro Carvalho Chehab status = write_reg(ci, 0x14, 0x20); 259af070bd6SMauro Carvalho Chehab if (status < 0) 260af070bd6SMauro Carvalho Chehab break; 2610f0b270fSRalph Metzler 2624fe130f2SMonam Agarwal /* TOSTRT = 8, Mode B (gated clock), falling Edge, 2630907bb2cSElise Lennion * Serial, POL=HIGH, MSB 2640907bb2cSElise Lennion */ 2654fe130f2SMonam Agarwal status = write_reg(ci, 0x0A, 0xA7); 266af070bd6SMauro Carvalho Chehab if (status < 0) 267af070bd6SMauro Carvalho Chehab break; 2680f0b270fSRalph Metzler 269af070bd6SMauro Carvalho Chehab status = write_reg(ci, 0x0B, 0x33); 270af070bd6SMauro Carvalho Chehab if (status < 0) 271af070bd6SMauro Carvalho Chehab break; 272af070bd6SMauro Carvalho Chehab status = write_reg(ci, 0x0C, 0x33); 273af070bd6SMauro Carvalho Chehab if (status < 0) 274af070bd6SMauro Carvalho Chehab break; 2750f0b270fSRalph Metzler 276af070bd6SMauro Carvalho Chehab status = write_regm(ci, 0x14, 0x00, 0x0F); 277af070bd6SMauro Carvalho Chehab if (status < 0) 278af070bd6SMauro Carvalho Chehab break; 279af070bd6SMauro Carvalho Chehab status = write_reg(ci, 0x15, ci->clk_reg_b); 280af070bd6SMauro Carvalho Chehab if (status < 0) 281af070bd6SMauro Carvalho Chehab break; 282af070bd6SMauro Carvalho Chehab status = write_regm(ci, 0x16, 0x00, 0x0F); 283af070bd6SMauro Carvalho Chehab if (status < 0) 284af070bd6SMauro Carvalho Chehab break; 285af070bd6SMauro Carvalho Chehab status = write_reg(ci, 0x17, ci->clk_reg_f); 286af070bd6SMauro Carvalho Chehab if (status < 0) 287af070bd6SMauro Carvalho Chehab break; 2880f0b270fSRalph Metzler 289dd3c5d00SRalph Metzler if (ci->cfg.clock_mode == 2) { 290dd3c5d00SRalph Metzler /* bitrate*2^13/ 72000 */ 291dd3c5d00SRalph Metzler u32 reg = ((ci->cfg.bitrate << 13) + 71999) / 72000; 292dd3c5d00SRalph Metzler 2936eb94193SRalph Metzler if (ci->cfg.polarity) { 294af070bd6SMauro Carvalho Chehab status = write_reg(ci, 0x09, 0x6f); 295af070bd6SMauro Carvalho Chehab if (status < 0) 296af070bd6SMauro Carvalho Chehab break; 2976eb94193SRalph Metzler } else { 298af070bd6SMauro Carvalho Chehab status = write_reg(ci, 0x09, 0x6d); 299af070bd6SMauro Carvalho Chehab if (status < 0) 300af070bd6SMauro Carvalho Chehab break; 3016eb94193SRalph Metzler } 302dd3c5d00SRalph Metzler status = write_reg(ci, 0x20, 0x08); 303dd3c5d00SRalph Metzler if (status < 0) 304dd3c5d00SRalph Metzler break; 305dd3c5d00SRalph Metzler status = write_reg(ci, 0x21, (reg >> 8) & 0xff); 306dd3c5d00SRalph Metzler if (status < 0) 307dd3c5d00SRalph Metzler break; 308dd3c5d00SRalph Metzler status = write_reg(ci, 0x22, reg & 0xff); 309dd3c5d00SRalph Metzler if (status < 0) 310dd3c5d00SRalph Metzler break; 311dd3c5d00SRalph Metzler } else if (ci->cfg.clock_mode == 1) { 312dd3c5d00SRalph Metzler if (ci->cfg.polarity) { 313dd3c5d00SRalph Metzler status = write_reg(ci, 0x09, 0x6f); /* D */ 314dd3c5d00SRalph Metzler if (status < 0) 315dd3c5d00SRalph Metzler break; 316dd3c5d00SRalph Metzler } else { 317dd3c5d00SRalph Metzler status = write_reg(ci, 0x09, 0x6d); 318dd3c5d00SRalph Metzler if (status < 0) 319dd3c5d00SRalph Metzler break; 320dd3c5d00SRalph Metzler } 321af070bd6SMauro Carvalho Chehab status = write_reg(ci, 0x20, 0x68); 322af070bd6SMauro Carvalho Chehab if (status < 0) 323af070bd6SMauro Carvalho Chehab break; 324af070bd6SMauro Carvalho Chehab status = write_reg(ci, 0x21, 0x00); 325af070bd6SMauro Carvalho Chehab if (status < 0) 326af070bd6SMauro Carvalho Chehab break; 327af070bd6SMauro Carvalho Chehab status = write_reg(ci, 0x22, 0x02); 328af070bd6SMauro Carvalho Chehab if (status < 0) 329af070bd6SMauro Carvalho Chehab break; 3306eb94193SRalph Metzler } else { 3316eb94193SRalph Metzler if (ci->cfg.polarity) { 332dd3c5d00SRalph Metzler status = write_reg(ci, 0x09, 0x4f); /* C */ 333af070bd6SMauro Carvalho Chehab if (status < 0) 334af070bd6SMauro Carvalho Chehab break; 3356eb94193SRalph Metzler } else { 336af070bd6SMauro Carvalho Chehab status = write_reg(ci, 0x09, 0x4d); 337af070bd6SMauro Carvalho Chehab if (status < 0) 338af070bd6SMauro Carvalho Chehab break; 3396eb94193SRalph Metzler } 340af070bd6SMauro Carvalho Chehab status = write_reg(ci, 0x20, 0x28); 341af070bd6SMauro Carvalho Chehab if (status < 0) 342af070bd6SMauro Carvalho Chehab break; 343af070bd6SMauro Carvalho Chehab status = write_reg(ci, 0x21, 0x00); 344af070bd6SMauro Carvalho Chehab if (status < 0) 345af070bd6SMauro Carvalho Chehab break; 346af070bd6SMauro Carvalho Chehab status = write_reg(ci, 0x22, 0x07); 347af070bd6SMauro Carvalho Chehab if (status < 0) 348af070bd6SMauro Carvalho Chehab break; 3496eb94193SRalph Metzler } 3500f0b270fSRalph Metzler 351af070bd6SMauro Carvalho Chehab status = write_regm(ci, 0x20, 0x80, 0x80); 352af070bd6SMauro Carvalho Chehab if (status < 0) 353af070bd6SMauro Carvalho Chehab break; 354af070bd6SMauro Carvalho Chehab status = write_regm(ci, 0x03, 0x02, 0x02); 355af070bd6SMauro Carvalho Chehab if (status < 0) 356af070bd6SMauro Carvalho Chehab break; 357af070bd6SMauro Carvalho Chehab status = write_reg(ci, 0x01, 0x04); 358af070bd6SMauro Carvalho Chehab if (status < 0) 359af070bd6SMauro Carvalho Chehab break; 360af070bd6SMauro Carvalho Chehab status = write_reg(ci, 0x00, 0x31); 361af070bd6SMauro Carvalho Chehab if (status < 0) 362af070bd6SMauro Carvalho Chehab break; 3630f0b270fSRalph Metzler 3646eb94193SRalph Metzler /* Put TS in bypass */ 365af070bd6SMauro Carvalho Chehab status = write_regm(ci, 0x09, 0x08, 0x08); 366af070bd6SMauro Carvalho Chehab if (status < 0) 367af070bd6SMauro Carvalho Chehab break; 3680f0b270fSRalph Metzler ci->cammode = -1; 3690f0b270fSRalph Metzler cam_mode(ci, 0); 3700f0b270fSRalph Metzler } while (0); 3710f0b270fSRalph Metzler mutex_unlock(&ci->lock); 3720f0b270fSRalph Metzler 3730f0b270fSRalph Metzler return 0; 3740f0b270fSRalph Metzler } 3750f0b270fSRalph Metzler 3760f0b270fSRalph Metzler static int read_attribute_mem(struct dvb_ca_en50221 *ca, 3770f0b270fSRalph Metzler int slot, int address) 3780f0b270fSRalph Metzler { 3790f0b270fSRalph Metzler struct cxd *ci = ca->data; 3800f0b270fSRalph Metzler u8 val; 381fcf1b73dSAybuke Ozdemir 3820f0b270fSRalph Metzler mutex_lock(&ci->lock); 3830f0b270fSRalph Metzler set_mode(ci, 1); 3840f0b270fSRalph Metzler read_pccard(ci, address, &val, 1); 3850f0b270fSRalph Metzler mutex_unlock(&ci->lock); 3860f0b270fSRalph Metzler return val; 3870f0b270fSRalph Metzler } 3880f0b270fSRalph Metzler 3890f0b270fSRalph Metzler static int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, 3900f0b270fSRalph Metzler int address, u8 value) 3910f0b270fSRalph Metzler { 3920f0b270fSRalph Metzler struct cxd *ci = ca->data; 3930f0b270fSRalph Metzler 3940f0b270fSRalph Metzler mutex_lock(&ci->lock); 3950f0b270fSRalph Metzler set_mode(ci, 1); 3960f0b270fSRalph Metzler write_pccard(ci, address, &value, 1); 3970f0b270fSRalph Metzler mutex_unlock(&ci->lock); 3980f0b270fSRalph Metzler return 0; 3990f0b270fSRalph Metzler } 4000f0b270fSRalph Metzler 4010f0b270fSRalph Metzler static int read_cam_control(struct dvb_ca_en50221 *ca, 4020f0b270fSRalph Metzler int slot, u8 address) 4030f0b270fSRalph Metzler { 4040f0b270fSRalph Metzler struct cxd *ci = ca->data; 40581a70591SDaniel Scheller unsigned int val; 4060f0b270fSRalph Metzler 4070f0b270fSRalph Metzler mutex_lock(&ci->lock); 4080f0b270fSRalph Metzler set_mode(ci, 0); 4090f0b270fSRalph Metzler read_io(ci, address, &val); 4100f0b270fSRalph Metzler mutex_unlock(&ci->lock); 4110f0b270fSRalph Metzler return val; 4120f0b270fSRalph Metzler } 4130f0b270fSRalph Metzler 4140f0b270fSRalph Metzler static int write_cam_control(struct dvb_ca_en50221 *ca, int slot, 4150f0b270fSRalph Metzler u8 address, u8 value) 4160f0b270fSRalph Metzler { 4170f0b270fSRalph Metzler struct cxd *ci = ca->data; 4180f0b270fSRalph Metzler 4190f0b270fSRalph Metzler mutex_lock(&ci->lock); 4200f0b270fSRalph Metzler set_mode(ci, 0); 4210f0b270fSRalph Metzler write_io(ci, address, value); 4220f0b270fSRalph Metzler mutex_unlock(&ci->lock); 4230f0b270fSRalph Metzler return 0; 4240f0b270fSRalph Metzler } 4250f0b270fSRalph Metzler 4260f0b270fSRalph Metzler static int slot_reset(struct dvb_ca_en50221 *ca, int slot) 4270f0b270fSRalph Metzler { 4280f0b270fSRalph Metzler struct cxd *ci = ca->data; 4290f0b270fSRalph Metzler 430dd3c5d00SRalph Metzler if (ci->cammode) 431dd3c5d00SRalph Metzler read_data(ca, slot, ci->rbuf, 0); 432dd3c5d00SRalph Metzler 4330f0b270fSRalph Metzler mutex_lock(&ci->lock); 4340f0b270fSRalph Metzler cam_mode(ci, 0); 4350f0b270fSRalph Metzler write_reg(ci, 0x00, 0x21); 4360f0b270fSRalph Metzler write_reg(ci, 0x06, 0x1F); 4370f0b270fSRalph Metzler write_reg(ci, 0x00, 0x31); 4380f0b270fSRalph Metzler write_regm(ci, 0x20, 0x80, 0x80); 4390f0b270fSRalph Metzler write_reg(ci, 0x03, 0x02); 4400f0b270fSRalph Metzler ci->ready = 0; 4410f0b270fSRalph Metzler ci->mode = -1; 4420f0b270fSRalph Metzler { 4430f0b270fSRalph Metzler int i; 4441f9f72f4STamara Diaconita 4450f0b270fSRalph Metzler for (i = 0; i < 100; i++) { 446c3cefd3cSTapasweni Pathak usleep_range(10000, 11000); 4470f0b270fSRalph Metzler if (ci->ready) 4480f0b270fSRalph Metzler break; 4490f0b270fSRalph Metzler } 4500f0b270fSRalph Metzler } 4510f0b270fSRalph Metzler mutex_unlock(&ci->lock); 4520f0b270fSRalph Metzler return 0; 4530f0b270fSRalph Metzler } 4540f0b270fSRalph Metzler 4550f0b270fSRalph Metzler static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot) 4560f0b270fSRalph Metzler { 4570f0b270fSRalph Metzler struct cxd *ci = ca->data; 4580f0b270fSRalph Metzler 45981a70591SDaniel Scheller dev_dbg(&ci->client->dev, "%s\n", __func__); 460dd3c5d00SRalph Metzler if (ci->cammode) 461dd3c5d00SRalph Metzler read_data(ca, slot, ci->rbuf, 0); 4620f0b270fSRalph Metzler mutex_lock(&ci->lock); 463dd3c5d00SRalph Metzler write_reg(ci, 0x00, 0x21); 464dd3c5d00SRalph Metzler write_reg(ci, 0x06, 0x1F); 465dd3c5d00SRalph Metzler msleep(300); 466dd3c5d00SRalph Metzler 4676eb94193SRalph Metzler write_regm(ci, 0x09, 0x08, 0x08); 4686eb94193SRalph Metzler write_regm(ci, 0x20, 0x80, 0x80); /* Reset CAM Mode */ 4696eb94193SRalph Metzler write_regm(ci, 0x06, 0x07, 0x07); /* Clear IO Mode */ 470dd3c5d00SRalph Metzler 4710f0b270fSRalph Metzler ci->mode = -1; 472dd3c5d00SRalph Metzler ci->write_busy = 0; 4730f0b270fSRalph Metzler mutex_unlock(&ci->lock); 4746eb94193SRalph Metzler return 0; 4750f0b270fSRalph Metzler } 4760f0b270fSRalph Metzler 4770f0b270fSRalph Metzler static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) 4780f0b270fSRalph Metzler { 4790f0b270fSRalph Metzler struct cxd *ci = ca->data; 4800f0b270fSRalph Metzler 4810f0b270fSRalph Metzler mutex_lock(&ci->lock); 4820f0b270fSRalph Metzler write_regm(ci, 0x09, 0x00, 0x08); 4830f0b270fSRalph Metzler set_mode(ci, 0); 4840f0b270fSRalph Metzler cam_mode(ci, 1); 4850f0b270fSRalph Metzler mutex_unlock(&ci->lock); 4860f0b270fSRalph Metzler return 0; 4870f0b270fSRalph Metzler } 4880f0b270fSRalph Metzler 4890f0b270fSRalph Metzler static int campoll(struct cxd *ci) 4900f0b270fSRalph Metzler { 4910f0b270fSRalph Metzler u8 istat; 4920f0b270fSRalph Metzler 4930f0b270fSRalph Metzler read_reg(ci, 0x04, &istat); 4940f0b270fSRalph Metzler if (!istat) 4950f0b270fSRalph Metzler return 0; 4960f0b270fSRalph Metzler write_reg(ci, 0x05, istat); 4970f0b270fSRalph Metzler 49864754837SRalph Metzler if (istat & 0x40) 4990f0b270fSRalph Metzler ci->dr = 1; 50064754837SRalph Metzler if (istat & 0x20) 501dd3c5d00SRalph Metzler ci->write_busy = 0; 5020f0b270fSRalph Metzler 5030f0b270fSRalph Metzler if (istat & 2) { 5040f0b270fSRalph Metzler u8 slotstat; 5050f0b270fSRalph Metzler 5060f0b270fSRalph Metzler read_reg(ci, 0x01, &slotstat); 5070f0b270fSRalph Metzler if (!(2 & slotstat)) { 5080f0b270fSRalph Metzler if (!ci->slot_stat) { 509dd3c5d00SRalph Metzler ci->slot_stat |= 510dd3c5d00SRalph Metzler DVB_CA_EN50221_POLL_CAM_PRESENT; 5110f0b270fSRalph Metzler write_regm(ci, 0x03, 0x08, 0x08); 5120f0b270fSRalph Metzler } 5130f0b270fSRalph Metzler 5140f0b270fSRalph Metzler } else { 5150f0b270fSRalph Metzler if (ci->slot_stat) { 5160f0b270fSRalph Metzler ci->slot_stat = 0; 5170f0b270fSRalph Metzler write_regm(ci, 0x03, 0x00, 0x08); 51881a70591SDaniel Scheller dev_info(&ci->client->dev, "NO CAM\n"); 5190f0b270fSRalph Metzler ci->ready = 0; 5200f0b270fSRalph Metzler } 5210f0b270fSRalph Metzler } 522dd3c5d00SRalph Metzler if ((istat & 8) && 52365ac8c84SDaniel Scheller ci->slot_stat == DVB_CA_EN50221_POLL_CAM_PRESENT) { 5240f0b270fSRalph Metzler ci->ready = 1; 5250f0b270fSRalph Metzler ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_READY; 5260f0b270fSRalph Metzler } 5270f0b270fSRalph Metzler } 5280f0b270fSRalph Metzler return 0; 5290f0b270fSRalph Metzler } 5300f0b270fSRalph Metzler 5310f0b270fSRalph Metzler static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) 5320f0b270fSRalph Metzler { 5330f0b270fSRalph Metzler struct cxd *ci = ca->data; 5340f0b270fSRalph Metzler u8 slotstat; 5350f0b270fSRalph Metzler 5360f0b270fSRalph Metzler mutex_lock(&ci->lock); 5370f0b270fSRalph Metzler campoll(ci); 5380f0b270fSRalph Metzler read_reg(ci, 0x01, &slotstat); 5390f0b270fSRalph Metzler mutex_unlock(&ci->lock); 5400f0b270fSRalph Metzler 5410f0b270fSRalph Metzler return ci->slot_stat; 5420f0b270fSRalph Metzler } 5430f0b270fSRalph Metzler 5440f0b270fSRalph Metzler static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount) 5450f0b270fSRalph Metzler { 5460f0b270fSRalph Metzler struct cxd *ci = ca->data; 5470f0b270fSRalph Metzler u8 msb, lsb; 5480f0b270fSRalph Metzler u16 len; 5490f0b270fSRalph Metzler 5500f0b270fSRalph Metzler mutex_lock(&ci->lock); 5510f0b270fSRalph Metzler campoll(ci); 5520f0b270fSRalph Metzler mutex_unlock(&ci->lock); 5530f0b270fSRalph Metzler 5540f0b270fSRalph Metzler if (!ci->dr) 5550f0b270fSRalph Metzler return 0; 5560f0b270fSRalph Metzler 5570f0b270fSRalph Metzler mutex_lock(&ci->lock); 5580f0b270fSRalph Metzler read_reg(ci, 0x0f, &msb); 5590f0b270fSRalph Metzler read_reg(ci, 0x10, &lsb); 560dd3c5d00SRalph Metzler len = ((u16)msb << 8) | lsb; 561dd3c5d00SRalph Metzler if (len > ecount || len < 2) { 562dd3c5d00SRalph Metzler /* read it anyway or cxd may hang */ 563dd3c5d00SRalph Metzler read_block(ci, 0x12, ci->rbuf, len); 564dd3c5d00SRalph Metzler mutex_unlock(&ci->lock); 565dd3c5d00SRalph Metzler return -EIO; 566dd3c5d00SRalph Metzler } 5670f0b270fSRalph Metzler read_block(ci, 0x12, ebuf, len); 5680f0b270fSRalph Metzler ci->dr = 0; 5690f0b270fSRalph Metzler mutex_unlock(&ci->lock); 5700f0b270fSRalph Metzler return len; 5710f0b270fSRalph Metzler } 5720f0b270fSRalph Metzler 5730f0b270fSRalph Metzler static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount) 5740f0b270fSRalph Metzler { 5750f0b270fSRalph Metzler struct cxd *ci = ca->data; 5760f0b270fSRalph Metzler 577dd3c5d00SRalph Metzler if (ci->write_busy) 578dd3c5d00SRalph Metzler return -EAGAIN; 5790f0b270fSRalph Metzler mutex_lock(&ci->lock); 5800f0b270fSRalph Metzler write_reg(ci, 0x0d, ecount >> 8); 5810f0b270fSRalph Metzler write_reg(ci, 0x0e, ecount & 0xff); 5820f0b270fSRalph Metzler write_block(ci, 0x11, ebuf, ecount); 583dd3c5d00SRalph Metzler ci->write_busy = 1; 5840f0b270fSRalph Metzler mutex_unlock(&ci->lock); 5850f0b270fSRalph Metzler return ecount; 5860f0b270fSRalph Metzler } 5870f0b270fSRalph Metzler 588*6f005abbSNishka Dasgupta static const struct dvb_ca_en50221 en_templ = { 5890f0b270fSRalph Metzler .read_attribute_mem = read_attribute_mem, 5900f0b270fSRalph Metzler .write_attribute_mem = write_attribute_mem, 5910f0b270fSRalph Metzler .read_cam_control = read_cam_control, 5920f0b270fSRalph Metzler .write_cam_control = write_cam_control, 5930f0b270fSRalph Metzler .slot_reset = slot_reset, 5940f0b270fSRalph Metzler .slot_shutdown = slot_shutdown, 5950f0b270fSRalph Metzler .slot_ts_enable = slot_ts_enable, 5960f0b270fSRalph Metzler .poll_slot_status = poll_slot_status, 5970f0b270fSRalph Metzler .read_data = read_data, 5980f0b270fSRalph Metzler .write_data = write_data, 5990f0b270fSRalph Metzler }; 6000f0b270fSRalph Metzler 60181a70591SDaniel Scheller static int cxd2099_probe(struct i2c_client *client, 60281a70591SDaniel Scheller const struct i2c_device_id *id) 6030f0b270fSRalph Metzler { 6044aff355cSDevendra Naga struct cxd *ci; 60581a70591SDaniel Scheller struct cxd2099_cfg *cfg = client->dev.platform_data; 60681a70591SDaniel Scheller static const struct regmap_config rm_cfg = { 60781a70591SDaniel Scheller .reg_bits = 8, 60881a70591SDaniel Scheller .val_bits = 8, 60981a70591SDaniel Scheller }; 61081a70591SDaniel Scheller unsigned int val; 61181a70591SDaniel Scheller int ret; 6120f0b270fSRalph Metzler 613783dd92bSTamara Diaconita ci = kzalloc(sizeof(*ci), GFP_KERNEL); 61481a70591SDaniel Scheller if (!ci) { 61581a70591SDaniel Scheller ret = -ENOMEM; 61681a70591SDaniel Scheller goto err; 61781a70591SDaniel Scheller } 61881a70591SDaniel Scheller 61981a70591SDaniel Scheller ci->client = client; 62081a70591SDaniel Scheller memcpy(&ci->cfg, cfg, sizeof(ci->cfg)); 62181a70591SDaniel Scheller 62281a70591SDaniel Scheller ci->regmap = regmap_init_i2c(client, &rm_cfg); 62381a70591SDaniel Scheller if (IS_ERR(ci->regmap)) { 62481a70591SDaniel Scheller ret = PTR_ERR(ci->regmap); 62581a70591SDaniel Scheller goto err_kfree; 62681a70591SDaniel Scheller } 62781a70591SDaniel Scheller 62881a70591SDaniel Scheller ret = regmap_read(ci->regmap, 0x00, &val); 62981a70591SDaniel Scheller if (ret < 0) { 63081a70591SDaniel Scheller dev_info(&client->dev, "No CXD2099AR detected at 0x%02x\n", 63181a70591SDaniel Scheller client->addr); 63281a70591SDaniel Scheller goto err_rmexit; 63381a70591SDaniel Scheller } 6340f0b270fSRalph Metzler 6350f0b270fSRalph Metzler mutex_init(&ci->lock); 6360f0b270fSRalph Metzler ci->lastaddress = 0xff; 6370f0b270fSRalph Metzler ci->clk_reg_b = 0x4a; 6380f0b270fSRalph Metzler ci->clk_reg_f = 0x1b; 6390f0b270fSRalph Metzler 6408d9b2584SDevendra Naga ci->en = en_templ; 6410f0b270fSRalph Metzler ci->en.data = ci; 6420f0b270fSRalph Metzler init(ci); 64381a70591SDaniel Scheller dev_info(&client->dev, "Attached CXD2099AR at 0x%02x\n", client->addr); 64481a70591SDaniel Scheller 64581a70591SDaniel Scheller *cfg->en = &ci->en; 6462b64e4deSDaniel Scheller 6472b64e4deSDaniel Scheller if (!buffermode) { 6482b64e4deSDaniel Scheller ci->en.read_data = NULL; 6492b64e4deSDaniel Scheller ci->en.write_data = NULL; 6502b64e4deSDaniel Scheller } else { 65181a70591SDaniel Scheller dev_info(&client->dev, "Using CXD2099AR buffer mode"); 6522b64e4deSDaniel Scheller } 6532b64e4deSDaniel Scheller 65481a70591SDaniel Scheller i2c_set_clientdata(client, ci); 65581a70591SDaniel Scheller 65681a70591SDaniel Scheller return 0; 65781a70591SDaniel Scheller 65881a70591SDaniel Scheller err_rmexit: 65981a70591SDaniel Scheller regmap_exit(ci->regmap); 66081a70591SDaniel Scheller err_kfree: 66181a70591SDaniel Scheller kfree(ci); 66281a70591SDaniel Scheller err: 66381a70591SDaniel Scheller 66481a70591SDaniel Scheller return ret; 6650f0b270fSRalph Metzler } 66681a70591SDaniel Scheller 66781a70591SDaniel Scheller static int cxd2099_remove(struct i2c_client *client) 66881a70591SDaniel Scheller { 66981a70591SDaniel Scheller struct cxd *ci = i2c_get_clientdata(client); 67081a70591SDaniel Scheller 67181a70591SDaniel Scheller regmap_exit(ci->regmap); 67281a70591SDaniel Scheller kfree(ci); 67381a70591SDaniel Scheller 67481a70591SDaniel Scheller return 0; 67581a70591SDaniel Scheller } 67681a70591SDaniel Scheller 67781a70591SDaniel Scheller static const struct i2c_device_id cxd2099_id[] = { 67881a70591SDaniel Scheller {"cxd2099", 0}, 67981a70591SDaniel Scheller {} 68081a70591SDaniel Scheller }; 68181a70591SDaniel Scheller MODULE_DEVICE_TABLE(i2c, cxd2099_id); 68281a70591SDaniel Scheller 68381a70591SDaniel Scheller static struct i2c_driver cxd2099_driver = { 68481a70591SDaniel Scheller .driver = { 68581a70591SDaniel Scheller .name = "cxd2099", 68681a70591SDaniel Scheller }, 68781a70591SDaniel Scheller .probe = cxd2099_probe, 68881a70591SDaniel Scheller .remove = cxd2099_remove, 68981a70591SDaniel Scheller .id_table = cxd2099_id, 69081a70591SDaniel Scheller }; 69181a70591SDaniel Scheller 69281a70591SDaniel Scheller module_i2c_driver(cxd2099_driver); 6930f0b270fSRalph Metzler 6942dc3e050SDaniel Scheller MODULE_DESCRIPTION("Sony CXD2099AR Common Interface controller driver"); 6956eb94193SRalph Metzler MODULE_AUTHOR("Ralph Metzler"); 696579856feSDaniel Scheller MODULE_LICENSE("GPL v2"); 697