brintos

brintos / linux-shallow public Read only

0
0
Text · 8.7 KiB · ee20813 Raw
378 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * ddbridge-ci.c: Digital Devices bridge CI (DuoFlex, CI Bridge) support4 *5 * Copyright (C) 2010-2017 Digital Devices GmbH6 *                         Marcus Metzler <mocm@metzlerbros.de>7 *                         Ralph Metzler <rjkm@metzlerbros.de>8 */9 10#include "ddbridge.h"11#include "ddbridge-regs.h"12#include "ddbridge-ci.h"13#include "ddbridge-io.h"14#include "ddbridge-i2c.h"15 16#include "cxd2099.h"17 18/* Octopus CI internal CI interface */19 20static int wait_ci_ready(struct ddb_ci *ci)21{22	u32 count = 10;23 24	ndelay(500);25	do {26		if (ddbreadl(ci->port->dev,27			     CI_CONTROL(ci->nr)) & CI_READY)28			break;29		usleep_range(1, 2);30		if ((--count) == 0)31			return -1;32	} while (1);33	return 0;34}35 36static int read_attribute_mem(struct dvb_ca_en50221 *ca,37			      int slot, int address)38{39	struct ddb_ci *ci = ca->data;40	u32 val, off = (address >> 1) & (CI_BUFFER_SIZE - 1);41 42	if (address > CI_BUFFER_SIZE)43		return -1;44	ddbwritel(ci->port->dev, CI_READ_CMD | (1 << 16) | address,45		  CI_DO_READ_ATTRIBUTES(ci->nr));46	wait_ci_ready(ci);47	val = 0xff & ddbreadl(ci->port->dev, CI_BUFFER(ci->nr) + off);48	return val;49}50 51static int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot,52			       int address, u8 value)53{54	struct ddb_ci *ci = ca->data;55 56	ddbwritel(ci->port->dev, CI_WRITE_CMD | (value << 16) | address,57		  CI_DO_ATTRIBUTE_RW(ci->nr));58	wait_ci_ready(ci);59	return 0;60}61 62static int read_cam_control(struct dvb_ca_en50221 *ca,63			    int slot, u8 address)64{65	u32 count = 100;66	struct ddb_ci *ci = ca->data;67	u32 res;68 69	ddbwritel(ci->port->dev, CI_READ_CMD | address,70		  CI_DO_IO_RW(ci->nr));71	ndelay(500);72	do {73		res = ddbreadl(ci->port->dev, CI_READDATA(ci->nr));74		if (res & CI_READY)75			break;76		usleep_range(1, 2);77		if ((--count) == 0)78			return -1;79	} while (1);80	return 0xff & res;81}82 83static int write_cam_control(struct dvb_ca_en50221 *ca, int slot,84			     u8 address, u8 value)85{86	struct ddb_ci *ci = ca->data;87 88	ddbwritel(ci->port->dev, CI_WRITE_CMD | (value << 16) | address,89		  CI_DO_IO_RW(ci->nr));90	wait_ci_ready(ci);91	return 0;92}93 94static int slot_reset(struct dvb_ca_en50221 *ca, int slot)95{96	struct ddb_ci *ci = ca->data;97 98	ddbwritel(ci->port->dev, CI_POWER_ON,99		  CI_CONTROL(ci->nr));100	msleep(100);101	ddbwritel(ci->port->dev, CI_POWER_ON | CI_RESET_CAM,102		  CI_CONTROL(ci->nr));103	ddbwritel(ci->port->dev, CI_ENABLE | CI_POWER_ON | CI_RESET_CAM,104		  CI_CONTROL(ci->nr));105	usleep_range(20, 25);106	ddbwritel(ci->port->dev, CI_ENABLE | CI_POWER_ON,107		  CI_CONTROL(ci->nr));108	return 0;109}110 111static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot)112{113	struct ddb_ci *ci = ca->data;114 115	ddbwritel(ci->port->dev, 0, CI_CONTROL(ci->nr));116	msleep(300);117	return 0;118}119 120static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)121{122	struct ddb_ci *ci = ca->data;123	u32 val = ddbreadl(ci->port->dev, CI_CONTROL(ci->nr));124 125	ddbwritel(ci->port->dev, val | CI_BYPASS_DISABLE,126		  CI_CONTROL(ci->nr));127	return 0;128}129 130static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)131{132	struct ddb_ci *ci = ca->data;133	u32 val = ddbreadl(ci->port->dev, CI_CONTROL(ci->nr));134	int stat = 0;135 136	if (val & CI_CAM_DETECT)137		stat |= DVB_CA_EN50221_POLL_CAM_PRESENT;138	if (val & CI_CAM_READY)139		stat |= DVB_CA_EN50221_POLL_CAM_READY;140	return stat;141}142 143static struct dvb_ca_en50221 en_templ = {144	.read_attribute_mem  = read_attribute_mem,145	.write_attribute_mem = write_attribute_mem,146	.read_cam_control    = read_cam_control,147	.write_cam_control   = write_cam_control,148	.slot_reset          = slot_reset,149	.slot_shutdown       = slot_shutdown,150	.slot_ts_enable      = slot_ts_enable,151	.poll_slot_status    = poll_slot_status,152};153 154static void ci_attach(struct ddb_port *port)155{156	struct ddb_ci *ci;157 158	ci = kzalloc(sizeof(*ci), GFP_KERNEL);159	if (!ci)160		return;161	memcpy(&ci->en, &en_templ, sizeof(en_templ));162	ci->en.data = ci;163	port->en = &ci->en;164	port->en_freedata = 1;165	ci->port = port;166	ci->nr = port->nr - 2;167}168 169/* DuoFlex Dual CI support */170 171static int write_creg(struct ddb_ci *ci, u8 data, u8 mask)172{173	struct i2c_adapter *i2c = &ci->port->i2c->adap;174	u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;175 176	ci->port->creg = (ci->port->creg & ~mask) | data;177	return i2c_write_reg(i2c, adr, 0x02, ci->port->creg);178}179 180static int read_attribute_mem_xo2(struct dvb_ca_en50221 *ca,181				  int slot, int address)182{183	struct ddb_ci *ci = ca->data;184	struct i2c_adapter *i2c = &ci->port->i2c->adap;185	u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;186	int res;187	u8 val;188 189	res = i2c_read_reg16(i2c, adr, 0x8000 | address, &val);190	return res ? res : val;191}192 193static int write_attribute_mem_xo2(struct dvb_ca_en50221 *ca, int slot,194				   int address, u8 value)195{196	struct ddb_ci *ci = ca->data;197	struct i2c_adapter *i2c = &ci->port->i2c->adap;198	u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;199 200	return i2c_write_reg16(i2c, adr, 0x8000 | address, value);201}202 203static int read_cam_control_xo2(struct dvb_ca_en50221 *ca,204				int slot, u8 address)205{206	struct ddb_ci *ci = ca->data;207	struct i2c_adapter *i2c = &ci->port->i2c->adap;208	u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;209	u8 val;210	int res;211 212	res = i2c_read_reg(i2c, adr, 0x20 | (address & 3), &val);213	return res ? res : val;214}215 216static int write_cam_control_xo2(struct dvb_ca_en50221 *ca, int slot,217				 u8 address, u8 value)218{219	struct ddb_ci *ci = ca->data;220	struct i2c_adapter *i2c = &ci->port->i2c->adap;221	u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;222 223	return i2c_write_reg(i2c, adr, 0x20 | (address & 3), value);224}225 226static int slot_reset_xo2(struct dvb_ca_en50221 *ca, int slot)227{228	struct ddb_ci *ci = ca->data;229 230	dev_dbg(ci->port->dev->dev, "%s\n", __func__);231	write_creg(ci, 0x01, 0x01);232	write_creg(ci, 0x04, 0x04);233	msleep(20);234	write_creg(ci, 0x02, 0x02);235	write_creg(ci, 0x00, 0x04);236	write_creg(ci, 0x18, 0x18);237	return 0;238}239 240static int slot_shutdown_xo2(struct dvb_ca_en50221 *ca, int slot)241{242	struct ddb_ci *ci = ca->data;243 244	dev_dbg(ci->port->dev->dev, "%s\n", __func__);245	write_creg(ci, 0x10, 0xff);246	write_creg(ci, 0x08, 0x08);247	return 0;248}249 250static int slot_ts_enable_xo2(struct dvb_ca_en50221 *ca, int slot)251{252	struct ddb_ci *ci = ca->data;253 254	dev_dbg(ci->port->dev->dev, "%s\n", __func__);255	write_creg(ci, 0x00, 0x10);256	return 0;257}258 259static int poll_slot_status_xo2(struct dvb_ca_en50221 *ca, int slot, int open)260{261	struct ddb_ci *ci = ca->data;262	struct i2c_adapter *i2c = &ci->port->i2c->adap;263	u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;264	u8 val = 0;265	int stat = 0;266 267	i2c_read_reg(i2c, adr, 0x01, &val);268 269	if (val & 2)270		stat |= DVB_CA_EN50221_POLL_CAM_PRESENT;271	if (val & 1)272		stat |= DVB_CA_EN50221_POLL_CAM_READY;273	return stat;274}275 276static struct dvb_ca_en50221 en_xo2_templ = {277	.read_attribute_mem  = read_attribute_mem_xo2,278	.write_attribute_mem = write_attribute_mem_xo2,279	.read_cam_control    = read_cam_control_xo2,280	.write_cam_control   = write_cam_control_xo2,281	.slot_reset          = slot_reset_xo2,282	.slot_shutdown       = slot_shutdown_xo2,283	.slot_ts_enable      = slot_ts_enable_xo2,284	.poll_slot_status    = poll_slot_status_xo2,285};286 287static void ci_xo2_attach(struct ddb_port *port)288{289	struct ddb_ci *ci;290 291	ci = kzalloc(sizeof(*ci), GFP_KERNEL);292	if (!ci)293		return;294	memcpy(&ci->en, &en_xo2_templ, sizeof(en_xo2_templ));295	ci->en.data = ci;296	port->en = &ci->en;297	port->en_freedata = 1;298	ci->port = port;299	ci->nr = port->nr - 2;300	ci->port->creg = 0;301	write_creg(ci, 0x10, 0xff);302	write_creg(ci, 0x08, 0x08);303}304 305static const struct cxd2099_cfg cxd_cfgtmpl = {306	.bitrate =  72000,307	.polarity = 1,308	.clock_mode = 1,309	.max_i2c = 512,310};311 312static int ci_cxd2099_attach(struct ddb_port *port, u32 bitrate)313{314	struct cxd2099_cfg cxd_cfg = cxd_cfgtmpl;315	struct i2c_client *client;316 317	cxd_cfg.bitrate = bitrate;318	cxd_cfg.en = &port->en;319 320	client = dvb_module_probe("cxd2099", NULL, &port->i2c->adap,321				  0x40, &cxd_cfg);322	if (!client)323		goto err;324 325	port->dvb[0].i2c_client[0] = client;326	port->en_freedata = 0;327	return 0;328 329err:330	dev_err(port->dev->dev, "CXD2099AR attach failed\n");331	return -ENODEV;332}333 334int ddb_ci_attach(struct ddb_port *port, u32 bitrate)335{336	int ret;337 338	switch (port->type) {339	case DDB_CI_EXTERNAL_SONY:340		ret = ci_cxd2099_attach(port, bitrate);341		if (ret)342			return -ENODEV;343		break;344	case DDB_CI_EXTERNAL_XO2:345	case DDB_CI_EXTERNAL_XO2_B:346		ci_xo2_attach(port);347		break;348	case DDB_CI_INTERNAL:349		ci_attach(port);350		break;351	default:352		return -ENODEV;353	}354 355	if (!port->en)356		return -ENODEV;357	dvb_ca_en50221_init(port->dvb[0].adap, port->en, 0, 1);358	return 0;359}360 361void ddb_ci_detach(struct ddb_port *port)362{363	if (port->dvb[0].dev)364		dvb_unregister_device(port->dvb[0].dev);365	if (port->en) {366		dvb_ca_en50221_release(port->en);367 368		dvb_module_release(port->dvb[0].i2c_client[0]);369		port->dvb[0].i2c_client[0] = NULL;370 371		/* free alloc'ed memory if needed */372		if (port->en_freedata)373			kfree(port->en->data);374 375		port->en = NULL;376	}377}378