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