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