brintos

brintos / linux-shallow public Read only

0
0
Text · 13.8 KiB · 5e6e188 Raw
694 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * cxd2099.c: Driver for the Sony CXD2099AR Common Interface Controller4 *5 * Copyright (C) 2010-2013 Digital Devices GmbH6 */7 8#include <linux/slab.h>9#include <linux/kernel.h>10#include <linux/module.h>11#include <linux/i2c.h>12#include <linux/regmap.h>13#include <linux/wait.h>14#include <linux/delay.h>15#include <linux/mutex.h>16#include <linux/io.h>17 18#include "cxd2099.h"19 20static int buffermode;21module_param(buffermode, int, 0444);22MODULE_PARM_DESC(buffermode, "Enable CXD2099AR buffer mode (default: disabled)");23 24static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount);25 26struct cxd {27	struct dvb_ca_en50221 en;28 29	struct cxd2099_cfg cfg;30	struct i2c_client *client;31	struct regmap *regmap;32 33	u8     regs[0x23];34	u8     lastaddress;35	u8     clk_reg_f;36	u8     clk_reg_b;37	int    mode;38	int    ready;39	int    dr;40	int    write_busy;41	int    slot_stat;42 43	u8     amem[1024];44	int    amem_read;45 46	int    cammode;47	struct mutex lock; /* device access lock */48 49	u8     rbuf[1028];50	u8     wbuf[1028];51};52 53static int read_block(struct cxd *ci, u8 adr, u8 *data, u16 n)54{55	int status = 0;56 57	if (ci->lastaddress != adr)58		status = regmap_write(ci->regmap, 0, adr);59	if (!status) {60		ci->lastaddress = adr;61 62		while (n) {63			int len = n;64 65			if (ci->cfg.max_i2c && len > ci->cfg.max_i2c)66				len = ci->cfg.max_i2c;67			status = regmap_raw_read(ci->regmap, 1, data, len);68			if (status)69				return status;70			data += len;71			n -= len;72		}73	}74	return status;75}76 77static int read_reg(struct cxd *ci, u8 reg, u8 *val)78{79	return read_block(ci, reg, val, 1);80}81 82static int read_pccard(struct cxd *ci, u16 address, u8 *data, u8 n)83{84	int status;85	u8 addr[2] = {address & 0xff, address >> 8};86 87	status = regmap_raw_write(ci->regmap, 2, addr, 2);88	if (!status)89		status = regmap_raw_read(ci->regmap, 3, data, n);90	return status;91}92 93static int write_pccard(struct cxd *ci, u16 address, u8 *data, u8 n)94{95	int status;96	u8 addr[2] = {address & 0xff, address >> 8};97 98	status = regmap_raw_write(ci->regmap, 2, addr, 2);99	if (!status) {100		u8 buf[256];101 102		memcpy(buf, data, n);103		status = regmap_raw_write(ci->regmap, 3, buf, n);104	}105	return status;106}107 108static int read_io(struct cxd *ci, u16 address, unsigned int *val)109{110	int status;111	u8 addr[2] = {address & 0xff, address >> 8};112 113	status = regmap_raw_write(ci->regmap, 2, addr, 2);114	if (!status)115		status = regmap_read(ci->regmap, 3, val);116	return status;117}118 119static int write_io(struct cxd *ci, u16 address, u8 val)120{121	int status;122	u8 addr[2] = {address & 0xff, address >> 8};123 124	status = regmap_raw_write(ci->regmap, 2, addr, 2);125	if (!status)126		status = regmap_write(ci->regmap, 3, val);127	return status;128}129 130static int write_regm(struct cxd *ci, u8 reg, u8 val, u8 mask)131{132	int status = 0;133	unsigned int regval;134 135	if (ci->lastaddress != reg)136		status = regmap_write(ci->regmap, 0, reg);137	if (!status && reg >= 6 && reg <= 8 && mask != 0xff) {138		status = regmap_read(ci->regmap, 1, &regval);139		ci->regs[reg] = regval;140	}141	ci->lastaddress = reg;142	ci->regs[reg] = (ci->regs[reg] & (~mask)) | val;143	if (!status)144		status = regmap_write(ci->regmap, 1, ci->regs[reg]);145	if (reg == 0x20)146		ci->regs[reg] &= 0x7f;147	return status;148}149 150static int write_reg(struct cxd *ci, u8 reg, u8 val)151{152	return write_regm(ci, reg, val, 0xff);153}154 155static int write_block(struct cxd *ci, u8 adr, u8 *data, u16 n)156{157	int status = 0;158	u8 *buf = ci->wbuf;159 160	if (ci->lastaddress != adr)161		status = regmap_write(ci->regmap, 0, adr);162	if (status)163		return status;164 165	ci->lastaddress = adr;166	while (n) {167		int len = n;168 169		if (ci->cfg.max_i2c && (len + 1 > ci->cfg.max_i2c))170			len = ci->cfg.max_i2c - 1;171		memcpy(buf, data, len);172		status = regmap_raw_write(ci->regmap, 1, buf, len);173		if (status)174			return status;175		n -= len;176		data += len;177	}178	return status;179}180 181static void set_mode(struct cxd *ci, int mode)182{183	if (mode == ci->mode)184		return;185 186	switch (mode) {187	case 0x00: /* IO mem */188		write_regm(ci, 0x06, 0x00, 0x07);189		break;190	case 0x01: /* ATT mem */191		write_regm(ci, 0x06, 0x02, 0x07);192		break;193	default:194		break;195	}196	ci->mode = mode;197}198 199static void cam_mode(struct cxd *ci, int mode)200{201	u8 dummy;202 203	if (mode == ci->cammode)204		return;205 206	switch (mode) {207	case 0x00:208		write_regm(ci, 0x20, 0x80, 0x80);209		break;210	case 0x01:211		if (!ci->en.read_data)212			return;213		ci->write_busy = 0;214		dev_info(&ci->client->dev, "enable cam buffer mode\n");215		write_reg(ci, 0x0d, 0x00);216		write_reg(ci, 0x0e, 0x01);217		write_regm(ci, 0x08, 0x40, 0x40);218		read_reg(ci, 0x12, &dummy);219		write_regm(ci, 0x08, 0x80, 0x80);220		break;221	default:222		break;223	}224	ci->cammode = mode;225}226 227static int init(struct cxd *ci)228{229	int status;230 231	mutex_lock(&ci->lock);232	ci->mode = -1;233	do {234		status = write_reg(ci, 0x00, 0x00);235		if (status < 0)236			break;237		status = write_reg(ci, 0x01, 0x00);238		if (status < 0)239			break;240		status = write_reg(ci, 0x02, 0x10);241		if (status < 0)242			break;243		status = write_reg(ci, 0x03, 0x00);244		if (status < 0)245			break;246		status = write_reg(ci, 0x05, 0xFF);247		if (status < 0)248			break;249		status = write_reg(ci, 0x06, 0x1F);250		if (status < 0)251			break;252		status = write_reg(ci, 0x07, 0x1F);253		if (status < 0)254			break;255		status = write_reg(ci, 0x08, 0x28);256		if (status < 0)257			break;258		status = write_reg(ci, 0x14, 0x20);259		if (status < 0)260			break;261 262		/* TOSTRT = 8, Mode B (gated clock), falling Edge,263		 * Serial, POL=HIGH, MSB264		 */265		status = write_reg(ci, 0x0A, 0xA7);266		if (status < 0)267			break;268 269		status = write_reg(ci, 0x0B, 0x33);270		if (status < 0)271			break;272		status = write_reg(ci, 0x0C, 0x33);273		if (status < 0)274			break;275 276		status = write_regm(ci, 0x14, 0x00, 0x0F);277		if (status < 0)278			break;279		status = write_reg(ci, 0x15, ci->clk_reg_b);280		if (status < 0)281			break;282		status = write_regm(ci, 0x16, 0x00, 0x0F);283		if (status < 0)284			break;285		status = write_reg(ci, 0x17, ci->clk_reg_f);286		if (status < 0)287			break;288 289		if (ci->cfg.clock_mode == 2) {290			/* bitrate*2^13/ 72000 */291			u32 reg = ((ci->cfg.bitrate << 13) + 71999) / 72000;292 293			if (ci->cfg.polarity) {294				status = write_reg(ci, 0x09, 0x6f);295				if (status < 0)296					break;297			} else {298				status = write_reg(ci, 0x09, 0x6d);299				if (status < 0)300					break;301			}302			status = write_reg(ci, 0x20, 0x08);303			if (status < 0)304				break;305			status = write_reg(ci, 0x21, (reg >> 8) & 0xff);306			if (status < 0)307				break;308			status = write_reg(ci, 0x22, reg & 0xff);309			if (status < 0)310				break;311		} else if (ci->cfg.clock_mode == 1) {312			if (ci->cfg.polarity) {313				status = write_reg(ci, 0x09, 0x6f); /* D */314				if (status < 0)315					break;316			} else {317				status = write_reg(ci, 0x09, 0x6d);318				if (status < 0)319					break;320			}321			status = write_reg(ci, 0x20, 0x68);322			if (status < 0)323				break;324			status = write_reg(ci, 0x21, 0x00);325			if (status < 0)326				break;327			status = write_reg(ci, 0x22, 0x02);328			if (status < 0)329				break;330		} else {331			if (ci->cfg.polarity) {332				status = write_reg(ci, 0x09, 0x4f); /* C */333				if (status < 0)334					break;335			} else {336				status = write_reg(ci, 0x09, 0x4d);337				if (status < 0)338					break;339			}340			status = write_reg(ci, 0x20, 0x28);341			if (status < 0)342				break;343			status = write_reg(ci, 0x21, 0x00);344			if (status < 0)345				break;346			status = write_reg(ci, 0x22, 0x07);347			if (status < 0)348				break;349		}350 351		status = write_regm(ci, 0x20, 0x80, 0x80);352		if (status < 0)353			break;354		status = write_regm(ci, 0x03, 0x02, 0x02);355		if (status < 0)356			break;357		status = write_reg(ci, 0x01, 0x04);358		if (status < 0)359			break;360		status = write_reg(ci, 0x00, 0x31);361		if (status < 0)362			break;363 364		/* Put TS in bypass */365		status = write_regm(ci, 0x09, 0x08, 0x08);366		if (status < 0)367			break;368		ci->cammode = -1;369		cam_mode(ci, 0);370	} while (0);371	mutex_unlock(&ci->lock);372 373	return 0;374}375 376static int read_attribute_mem(struct dvb_ca_en50221 *ca,377			      int slot, int address)378{379	struct cxd *ci = ca->data;380	u8 val;381 382	mutex_lock(&ci->lock);383	set_mode(ci, 1);384	read_pccard(ci, address, &val, 1);385	mutex_unlock(&ci->lock);386	return val;387}388 389static int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot,390			       int address, u8 value)391{392	struct cxd *ci = ca->data;393 394	mutex_lock(&ci->lock);395	set_mode(ci, 1);396	write_pccard(ci, address, &value, 1);397	mutex_unlock(&ci->lock);398	return 0;399}400 401static int read_cam_control(struct dvb_ca_en50221 *ca,402			    int slot, u8 address)403{404	struct cxd *ci = ca->data;405	unsigned int val;406 407	mutex_lock(&ci->lock);408	set_mode(ci, 0);409	read_io(ci, address, &val);410	mutex_unlock(&ci->lock);411	return val;412}413 414static int write_cam_control(struct dvb_ca_en50221 *ca, int slot,415			     u8 address, u8 value)416{417	struct cxd *ci = ca->data;418 419	mutex_lock(&ci->lock);420	set_mode(ci, 0);421	write_io(ci, address, value);422	mutex_unlock(&ci->lock);423	return 0;424}425 426static int slot_reset(struct dvb_ca_en50221 *ca, int slot)427{428	struct cxd *ci = ca->data;429 430	if (ci->cammode)431		read_data(ca, slot, ci->rbuf, 0);432 433	mutex_lock(&ci->lock);434	cam_mode(ci, 0);435	write_reg(ci, 0x00, 0x21);436	write_reg(ci, 0x06, 0x1F);437	write_reg(ci, 0x00, 0x31);438	write_regm(ci, 0x20, 0x80, 0x80);439	write_reg(ci, 0x03, 0x02);440	ci->ready = 0;441	ci->mode = -1;442	{443		int i;444 445		for (i = 0; i < 100; i++) {446			usleep_range(10000, 11000);447			if (ci->ready)448				break;449		}450	}451	mutex_unlock(&ci->lock);452	return 0;453}454 455static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot)456{457	struct cxd *ci = ca->data;458 459	dev_dbg(&ci->client->dev, "%s\n", __func__);460	if (ci->cammode)461		read_data(ca, slot, ci->rbuf, 0);462	mutex_lock(&ci->lock);463	write_reg(ci, 0x00, 0x21);464	write_reg(ci, 0x06, 0x1F);465	msleep(300);466 467	write_regm(ci, 0x09, 0x08, 0x08);468	write_regm(ci, 0x20, 0x80, 0x80); /* Reset CAM Mode */469	write_regm(ci, 0x06, 0x07, 0x07); /* Clear IO Mode */470 471	ci->mode = -1;472	ci->write_busy = 0;473	mutex_unlock(&ci->lock);474	return 0;475}476 477static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)478{479	struct cxd *ci = ca->data;480 481	mutex_lock(&ci->lock);482	write_regm(ci, 0x09, 0x00, 0x08);483	set_mode(ci, 0);484	cam_mode(ci, 1);485	mutex_unlock(&ci->lock);486	return 0;487}488 489static int campoll(struct cxd *ci)490{491	u8 istat;492 493	read_reg(ci, 0x04, &istat);494	if (!istat)495		return 0;496	write_reg(ci, 0x05, istat);497 498	if (istat & 0x40)499		ci->dr = 1;500	if (istat & 0x20)501		ci->write_busy = 0;502 503	if (istat & 2) {504		u8 slotstat;505 506		read_reg(ci, 0x01, &slotstat);507		if (!(2 & slotstat)) {508			if (!ci->slot_stat) {509				ci->slot_stat |=510					      DVB_CA_EN50221_POLL_CAM_PRESENT;511				write_regm(ci, 0x03, 0x08, 0x08);512			}513 514		} else {515			if (ci->slot_stat) {516				ci->slot_stat = 0;517				write_regm(ci, 0x03, 0x00, 0x08);518				dev_info(&ci->client->dev, "NO CAM\n");519				ci->ready = 0;520			}521		}522		if ((istat & 8) &&523		    ci->slot_stat == DVB_CA_EN50221_POLL_CAM_PRESENT) {524			ci->ready = 1;525			ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_READY;526		}527	}528	return 0;529}530 531static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)532{533	struct cxd *ci = ca->data;534	u8 slotstat;535 536	mutex_lock(&ci->lock);537	campoll(ci);538	read_reg(ci, 0x01, &slotstat);539	mutex_unlock(&ci->lock);540 541	return ci->slot_stat;542}543 544static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)545{546	struct cxd *ci = ca->data;547	u8 msb, lsb;548	u16 len;549 550	mutex_lock(&ci->lock);551	campoll(ci);552	mutex_unlock(&ci->lock);553 554	if (!ci->dr)555		return 0;556 557	mutex_lock(&ci->lock);558	read_reg(ci, 0x0f, &msb);559	read_reg(ci, 0x10, &lsb);560	len = ((u16)msb << 8) | lsb;561	if (len > ecount || len < 2) {562		/* read it anyway or cxd may hang */563		read_block(ci, 0x12, ci->rbuf, len);564		mutex_unlock(&ci->lock);565		return -EIO;566	}567	read_block(ci, 0x12, ebuf, len);568	ci->dr = 0;569	mutex_unlock(&ci->lock);570	return len;571}572 573static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)574{575	struct cxd *ci = ca->data;576 577	if (ci->write_busy)578		return -EAGAIN;579	mutex_lock(&ci->lock);580	write_reg(ci, 0x0d, ecount >> 8);581	write_reg(ci, 0x0e, ecount & 0xff);582	write_block(ci, 0x11, ebuf, ecount);583	ci->write_busy = 1;584	mutex_unlock(&ci->lock);585	return ecount;586}587 588static const struct dvb_ca_en50221 en_templ = {589	.read_attribute_mem  = read_attribute_mem,590	.write_attribute_mem = write_attribute_mem,591	.read_cam_control    = read_cam_control,592	.write_cam_control   = write_cam_control,593	.slot_reset          = slot_reset,594	.slot_shutdown       = slot_shutdown,595	.slot_ts_enable      = slot_ts_enable,596	.poll_slot_status    = poll_slot_status,597	.read_data           = read_data,598	.write_data          = write_data,599};600 601static int cxd2099_probe(struct i2c_client *client)602{603	struct cxd *ci;604	struct cxd2099_cfg *cfg = client->dev.platform_data;605	static const struct regmap_config rm_cfg = {606		.reg_bits = 8,607		.val_bits = 8,608	};609	unsigned int val;610	int ret;611 612	ci = kzalloc(sizeof(*ci), GFP_KERNEL);613	if (!ci) {614		ret = -ENOMEM;615		goto err;616	}617 618	ci->client = client;619	memcpy(&ci->cfg, cfg, sizeof(ci->cfg));620 621	ci->regmap = regmap_init_i2c(client, &rm_cfg);622	if (IS_ERR(ci->regmap)) {623		ret = PTR_ERR(ci->regmap);624		goto err_kfree;625	}626 627	ret = regmap_read(ci->regmap, 0x00, &val);628	if (ret < 0) {629		dev_info(&client->dev, "No CXD2099AR detected at 0x%02x\n",630			 client->addr);631		goto err_rmexit;632	}633 634	mutex_init(&ci->lock);635	ci->lastaddress = 0xff;636	ci->clk_reg_b = 0x4a;637	ci->clk_reg_f = 0x1b;638 639	ci->en = en_templ;640	ci->en.data = ci;641	init(ci);642	dev_info(&client->dev, "Attached CXD2099AR at 0x%02x\n", client->addr);643 644	*cfg->en = &ci->en;645 646	if (!buffermode) {647		ci->en.read_data = NULL;648		ci->en.write_data = NULL;649	} else {650		dev_info(&client->dev, "Using CXD2099AR buffer mode");651	}652 653	i2c_set_clientdata(client, ci);654 655	return 0;656 657err_rmexit:658	regmap_exit(ci->regmap);659err_kfree:660	kfree(ci);661err:662 663	return ret;664}665 666static void cxd2099_remove(struct i2c_client *client)667{668	struct cxd *ci = i2c_get_clientdata(client);669 670	regmap_exit(ci->regmap);671	kfree(ci);672}673 674static const struct i2c_device_id cxd2099_id[] = {675	{ "cxd2099" },676	{}677};678MODULE_DEVICE_TABLE(i2c, cxd2099_id);679 680static struct i2c_driver cxd2099_driver = {681	.driver = {682		.name	= "cxd2099",683	},684	.probe		= cxd2099_probe,685	.remove		= cxd2099_remove,686	.id_table	= cxd2099_id,687};688 689module_i2c_driver(cxd2099_driver);690 691MODULE_DESCRIPTION("Sony CXD2099AR Common Interface controller driver");692MODULE_AUTHOR("Ralph Metzler");693MODULE_LICENSE("GPL v2");694