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