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, &regval);
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