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