18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ddbridge-ci.c: Digital Devices bridge CI (DuoFlex, CI Bridge) support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2010-2017 Digital Devices GmbH 68c2ecf20Sopenharmony_ci * Marcus Metzler <mocm@metzlerbros.de> 78c2ecf20Sopenharmony_ci * Ralph Metzler <rjkm@metzlerbros.de> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or 108c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License 118c2ecf20Sopenharmony_ci * version 2 only, as published by the Free Software Foundation. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, 148c2ecf20Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 158c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 168c2ecf20Sopenharmony_ci * GNU General Public License for more details. 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "ddbridge.h" 208c2ecf20Sopenharmony_ci#include "ddbridge-regs.h" 218c2ecf20Sopenharmony_ci#include "ddbridge-ci.h" 228c2ecf20Sopenharmony_ci#include "ddbridge-io.h" 238c2ecf20Sopenharmony_ci#include "ddbridge-i2c.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "cxd2099.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* Octopus CI internal CI interface */ 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic int wait_ci_ready(struct ddb_ci *ci) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci u32 count = 10; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci ndelay(500); 348c2ecf20Sopenharmony_ci do { 358c2ecf20Sopenharmony_ci if (ddbreadl(ci->port->dev, 368c2ecf20Sopenharmony_ci CI_CONTROL(ci->nr)) & CI_READY) 378c2ecf20Sopenharmony_ci break; 388c2ecf20Sopenharmony_ci usleep_range(1, 2); 398c2ecf20Sopenharmony_ci if ((--count) == 0) 408c2ecf20Sopenharmony_ci return -1; 418c2ecf20Sopenharmony_ci } while (1); 428c2ecf20Sopenharmony_ci return 0; 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic int read_attribute_mem(struct dvb_ca_en50221 *ca, 468c2ecf20Sopenharmony_ci int slot, int address) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci struct ddb_ci *ci = ca->data; 498c2ecf20Sopenharmony_ci u32 val, off = (address >> 1) & (CI_BUFFER_SIZE - 1); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if (address > CI_BUFFER_SIZE) 528c2ecf20Sopenharmony_ci return -1; 538c2ecf20Sopenharmony_ci ddbwritel(ci->port->dev, CI_READ_CMD | (1 << 16) | address, 548c2ecf20Sopenharmony_ci CI_DO_READ_ATTRIBUTES(ci->nr)); 558c2ecf20Sopenharmony_ci wait_ci_ready(ci); 568c2ecf20Sopenharmony_ci val = 0xff & ddbreadl(ci->port->dev, CI_BUFFER(ci->nr) + off); 578c2ecf20Sopenharmony_ci return val; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, 618c2ecf20Sopenharmony_ci int address, u8 value) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci struct ddb_ci *ci = ca->data; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci ddbwritel(ci->port->dev, CI_WRITE_CMD | (value << 16) | address, 668c2ecf20Sopenharmony_ci CI_DO_ATTRIBUTE_RW(ci->nr)); 678c2ecf20Sopenharmony_ci wait_ci_ready(ci); 688c2ecf20Sopenharmony_ci return 0; 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic int read_cam_control(struct dvb_ca_en50221 *ca, 728c2ecf20Sopenharmony_ci int slot, u8 address) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci u32 count = 100; 758c2ecf20Sopenharmony_ci struct ddb_ci *ci = ca->data; 768c2ecf20Sopenharmony_ci u32 res; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci ddbwritel(ci->port->dev, CI_READ_CMD | address, 798c2ecf20Sopenharmony_ci CI_DO_IO_RW(ci->nr)); 808c2ecf20Sopenharmony_ci ndelay(500); 818c2ecf20Sopenharmony_ci do { 828c2ecf20Sopenharmony_ci res = ddbreadl(ci->port->dev, CI_READDATA(ci->nr)); 838c2ecf20Sopenharmony_ci if (res & CI_READY) 848c2ecf20Sopenharmony_ci break; 858c2ecf20Sopenharmony_ci usleep_range(1, 2); 868c2ecf20Sopenharmony_ci if ((--count) == 0) 878c2ecf20Sopenharmony_ci return -1; 888c2ecf20Sopenharmony_ci } while (1); 898c2ecf20Sopenharmony_ci return 0xff & res; 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic int write_cam_control(struct dvb_ca_en50221 *ca, int slot, 938c2ecf20Sopenharmony_ci u8 address, u8 value) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct ddb_ci *ci = ca->data; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci ddbwritel(ci->port->dev, CI_WRITE_CMD | (value << 16) | address, 988c2ecf20Sopenharmony_ci CI_DO_IO_RW(ci->nr)); 998c2ecf20Sopenharmony_ci wait_ci_ready(ci); 1008c2ecf20Sopenharmony_ci return 0; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic int slot_reset(struct dvb_ca_en50221 *ca, int slot) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci struct ddb_ci *ci = ca->data; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci ddbwritel(ci->port->dev, CI_POWER_ON, 1088c2ecf20Sopenharmony_ci CI_CONTROL(ci->nr)); 1098c2ecf20Sopenharmony_ci msleep(100); 1108c2ecf20Sopenharmony_ci ddbwritel(ci->port->dev, CI_POWER_ON | CI_RESET_CAM, 1118c2ecf20Sopenharmony_ci CI_CONTROL(ci->nr)); 1128c2ecf20Sopenharmony_ci ddbwritel(ci->port->dev, CI_ENABLE | CI_POWER_ON | CI_RESET_CAM, 1138c2ecf20Sopenharmony_ci CI_CONTROL(ci->nr)); 1148c2ecf20Sopenharmony_ci usleep_range(20, 25); 1158c2ecf20Sopenharmony_ci ddbwritel(ci->port->dev, CI_ENABLE | CI_POWER_ON, 1168c2ecf20Sopenharmony_ci CI_CONTROL(ci->nr)); 1178c2ecf20Sopenharmony_ci return 0; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic int slot_shutdown(struct dvb_ca_en50221 *ca, int slot) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci struct ddb_ci *ci = ca->data; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci ddbwritel(ci->port->dev, 0, CI_CONTROL(ci->nr)); 1258c2ecf20Sopenharmony_ci msleep(300); 1268c2ecf20Sopenharmony_ci return 0; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci struct ddb_ci *ci = ca->data; 1328c2ecf20Sopenharmony_ci u32 val = ddbreadl(ci->port->dev, CI_CONTROL(ci->nr)); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci ddbwritel(ci->port->dev, val | CI_BYPASS_DISABLE, 1358c2ecf20Sopenharmony_ci CI_CONTROL(ci->nr)); 1368c2ecf20Sopenharmony_ci return 0; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci struct ddb_ci *ci = ca->data; 1428c2ecf20Sopenharmony_ci u32 val = ddbreadl(ci->port->dev, CI_CONTROL(ci->nr)); 1438c2ecf20Sopenharmony_ci int stat = 0; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (val & CI_CAM_DETECT) 1468c2ecf20Sopenharmony_ci stat |= DVB_CA_EN50221_POLL_CAM_PRESENT; 1478c2ecf20Sopenharmony_ci if (val & CI_CAM_READY) 1488c2ecf20Sopenharmony_ci stat |= DVB_CA_EN50221_POLL_CAM_READY; 1498c2ecf20Sopenharmony_ci return stat; 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic struct dvb_ca_en50221 en_templ = { 1538c2ecf20Sopenharmony_ci .read_attribute_mem = read_attribute_mem, 1548c2ecf20Sopenharmony_ci .write_attribute_mem = write_attribute_mem, 1558c2ecf20Sopenharmony_ci .read_cam_control = read_cam_control, 1568c2ecf20Sopenharmony_ci .write_cam_control = write_cam_control, 1578c2ecf20Sopenharmony_ci .slot_reset = slot_reset, 1588c2ecf20Sopenharmony_ci .slot_shutdown = slot_shutdown, 1598c2ecf20Sopenharmony_ci .slot_ts_enable = slot_ts_enable, 1608c2ecf20Sopenharmony_ci .poll_slot_status = poll_slot_status, 1618c2ecf20Sopenharmony_ci}; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic void ci_attach(struct ddb_port *port) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci struct ddb_ci *ci; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci ci = kzalloc(sizeof(*ci), GFP_KERNEL); 1688c2ecf20Sopenharmony_ci if (!ci) 1698c2ecf20Sopenharmony_ci return; 1708c2ecf20Sopenharmony_ci memcpy(&ci->en, &en_templ, sizeof(en_templ)); 1718c2ecf20Sopenharmony_ci ci->en.data = ci; 1728c2ecf20Sopenharmony_ci port->en = &ci->en; 1738c2ecf20Sopenharmony_ci port->en_freedata = 1; 1748c2ecf20Sopenharmony_ci ci->port = port; 1758c2ecf20Sopenharmony_ci ci->nr = port->nr - 2; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci/* DuoFlex Dual CI support */ 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic int write_creg(struct ddb_ci *ci, u8 data, u8 mask) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci struct i2c_adapter *i2c = &ci->port->i2c->adap; 1838c2ecf20Sopenharmony_ci u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci ci->port->creg = (ci->port->creg & ~mask) | data; 1868c2ecf20Sopenharmony_ci return i2c_write_reg(i2c, adr, 0x02, ci->port->creg); 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic int read_attribute_mem_xo2(struct dvb_ca_en50221 *ca, 1908c2ecf20Sopenharmony_ci int slot, int address) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci struct ddb_ci *ci = ca->data; 1938c2ecf20Sopenharmony_ci struct i2c_adapter *i2c = &ci->port->i2c->adap; 1948c2ecf20Sopenharmony_ci u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13; 1958c2ecf20Sopenharmony_ci int res; 1968c2ecf20Sopenharmony_ci u8 val; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci res = i2c_read_reg16(i2c, adr, 0x8000 | address, &val); 1998c2ecf20Sopenharmony_ci return res ? res : val; 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic int write_attribute_mem_xo2(struct dvb_ca_en50221 *ca, int slot, 2038c2ecf20Sopenharmony_ci int address, u8 value) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci struct ddb_ci *ci = ca->data; 2068c2ecf20Sopenharmony_ci struct i2c_adapter *i2c = &ci->port->i2c->adap; 2078c2ecf20Sopenharmony_ci u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci return i2c_write_reg16(i2c, adr, 0x8000 | address, value); 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic int read_cam_control_xo2(struct dvb_ca_en50221 *ca, 2138c2ecf20Sopenharmony_ci int slot, u8 address) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci struct ddb_ci *ci = ca->data; 2168c2ecf20Sopenharmony_ci struct i2c_adapter *i2c = &ci->port->i2c->adap; 2178c2ecf20Sopenharmony_ci u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13; 2188c2ecf20Sopenharmony_ci u8 val; 2198c2ecf20Sopenharmony_ci int res; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci res = i2c_read_reg(i2c, adr, 0x20 | (address & 3), &val); 2228c2ecf20Sopenharmony_ci return res ? res : val; 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic int write_cam_control_xo2(struct dvb_ca_en50221 *ca, int slot, 2268c2ecf20Sopenharmony_ci u8 address, u8 value) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci struct ddb_ci *ci = ca->data; 2298c2ecf20Sopenharmony_ci struct i2c_adapter *i2c = &ci->port->i2c->adap; 2308c2ecf20Sopenharmony_ci u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci return i2c_write_reg(i2c, adr, 0x20 | (address & 3), value); 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic int slot_reset_xo2(struct dvb_ca_en50221 *ca, int slot) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct ddb_ci *ci = ca->data; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci dev_dbg(ci->port->dev->dev, "%s\n", __func__); 2408c2ecf20Sopenharmony_ci write_creg(ci, 0x01, 0x01); 2418c2ecf20Sopenharmony_ci write_creg(ci, 0x04, 0x04); 2428c2ecf20Sopenharmony_ci msleep(20); 2438c2ecf20Sopenharmony_ci write_creg(ci, 0x02, 0x02); 2448c2ecf20Sopenharmony_ci write_creg(ci, 0x00, 0x04); 2458c2ecf20Sopenharmony_ci write_creg(ci, 0x18, 0x18); 2468c2ecf20Sopenharmony_ci return 0; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic int slot_shutdown_xo2(struct dvb_ca_en50221 *ca, int slot) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci struct ddb_ci *ci = ca->data; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci dev_dbg(ci->port->dev->dev, "%s\n", __func__); 2548c2ecf20Sopenharmony_ci write_creg(ci, 0x10, 0xff); 2558c2ecf20Sopenharmony_ci write_creg(ci, 0x08, 0x08); 2568c2ecf20Sopenharmony_ci return 0; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic int slot_ts_enable_xo2(struct dvb_ca_en50221 *ca, int slot) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci struct ddb_ci *ci = ca->data; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci dev_dbg(ci->port->dev->dev, "%s\n", __func__); 2648c2ecf20Sopenharmony_ci write_creg(ci, 0x00, 0x10); 2658c2ecf20Sopenharmony_ci return 0; 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic int poll_slot_status_xo2(struct dvb_ca_en50221 *ca, int slot, int open) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci struct ddb_ci *ci = ca->data; 2718c2ecf20Sopenharmony_ci struct i2c_adapter *i2c = &ci->port->i2c->adap; 2728c2ecf20Sopenharmony_ci u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13; 2738c2ecf20Sopenharmony_ci u8 val = 0; 2748c2ecf20Sopenharmony_ci int stat = 0; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci i2c_read_reg(i2c, adr, 0x01, &val); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (val & 2) 2798c2ecf20Sopenharmony_ci stat |= DVB_CA_EN50221_POLL_CAM_PRESENT; 2808c2ecf20Sopenharmony_ci if (val & 1) 2818c2ecf20Sopenharmony_ci stat |= DVB_CA_EN50221_POLL_CAM_READY; 2828c2ecf20Sopenharmony_ci return stat; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic struct dvb_ca_en50221 en_xo2_templ = { 2868c2ecf20Sopenharmony_ci .read_attribute_mem = read_attribute_mem_xo2, 2878c2ecf20Sopenharmony_ci .write_attribute_mem = write_attribute_mem_xo2, 2888c2ecf20Sopenharmony_ci .read_cam_control = read_cam_control_xo2, 2898c2ecf20Sopenharmony_ci .write_cam_control = write_cam_control_xo2, 2908c2ecf20Sopenharmony_ci .slot_reset = slot_reset_xo2, 2918c2ecf20Sopenharmony_ci .slot_shutdown = slot_shutdown_xo2, 2928c2ecf20Sopenharmony_ci .slot_ts_enable = slot_ts_enable_xo2, 2938c2ecf20Sopenharmony_ci .poll_slot_status = poll_slot_status_xo2, 2948c2ecf20Sopenharmony_ci}; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic void ci_xo2_attach(struct ddb_port *port) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci struct ddb_ci *ci; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci ci = kzalloc(sizeof(*ci), GFP_KERNEL); 3018c2ecf20Sopenharmony_ci if (!ci) 3028c2ecf20Sopenharmony_ci return; 3038c2ecf20Sopenharmony_ci memcpy(&ci->en, &en_xo2_templ, sizeof(en_xo2_templ)); 3048c2ecf20Sopenharmony_ci ci->en.data = ci; 3058c2ecf20Sopenharmony_ci port->en = &ci->en; 3068c2ecf20Sopenharmony_ci port->en_freedata = 1; 3078c2ecf20Sopenharmony_ci ci->port = port; 3088c2ecf20Sopenharmony_ci ci->nr = port->nr - 2; 3098c2ecf20Sopenharmony_ci ci->port->creg = 0; 3108c2ecf20Sopenharmony_ci write_creg(ci, 0x10, 0xff); 3118c2ecf20Sopenharmony_ci write_creg(ci, 0x08, 0x08); 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic const struct cxd2099_cfg cxd_cfgtmpl = { 3158c2ecf20Sopenharmony_ci .bitrate = 72000, 3168c2ecf20Sopenharmony_ci .polarity = 1, 3178c2ecf20Sopenharmony_ci .clock_mode = 1, 3188c2ecf20Sopenharmony_ci .max_i2c = 512, 3198c2ecf20Sopenharmony_ci}; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic int ci_cxd2099_attach(struct ddb_port *port, u32 bitrate) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci struct cxd2099_cfg cxd_cfg = cxd_cfgtmpl; 3248c2ecf20Sopenharmony_ci struct i2c_client *client; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci cxd_cfg.bitrate = bitrate; 3278c2ecf20Sopenharmony_ci cxd_cfg.en = &port->en; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci client = dvb_module_probe("cxd2099", NULL, &port->i2c->adap, 3308c2ecf20Sopenharmony_ci 0x40, &cxd_cfg); 3318c2ecf20Sopenharmony_ci if (!client) 3328c2ecf20Sopenharmony_ci goto err; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci port->dvb[0].i2c_client[0] = client; 3358c2ecf20Sopenharmony_ci port->en_freedata = 0; 3368c2ecf20Sopenharmony_ci return 0; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cierr: 3398c2ecf20Sopenharmony_ci dev_err(port->dev->dev, "CXD2099AR attach failed\n"); 3408c2ecf20Sopenharmony_ci return -ENODEV; 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ciint ddb_ci_attach(struct ddb_port *port, u32 bitrate) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci int ret; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci switch (port->type) { 3488c2ecf20Sopenharmony_ci case DDB_CI_EXTERNAL_SONY: 3498c2ecf20Sopenharmony_ci ret = ci_cxd2099_attach(port, bitrate); 3508c2ecf20Sopenharmony_ci if (ret) 3518c2ecf20Sopenharmony_ci return -ENODEV; 3528c2ecf20Sopenharmony_ci break; 3538c2ecf20Sopenharmony_ci case DDB_CI_EXTERNAL_XO2: 3548c2ecf20Sopenharmony_ci case DDB_CI_EXTERNAL_XO2_B: 3558c2ecf20Sopenharmony_ci ci_xo2_attach(port); 3568c2ecf20Sopenharmony_ci break; 3578c2ecf20Sopenharmony_ci case DDB_CI_INTERNAL: 3588c2ecf20Sopenharmony_ci ci_attach(port); 3598c2ecf20Sopenharmony_ci break; 3608c2ecf20Sopenharmony_ci default: 3618c2ecf20Sopenharmony_ci return -ENODEV; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci if (!port->en) 3658c2ecf20Sopenharmony_ci return -ENODEV; 3668c2ecf20Sopenharmony_ci dvb_ca_en50221_init(port->dvb[0].adap, port->en, 0, 1); 3678c2ecf20Sopenharmony_ci return 0; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_civoid ddb_ci_detach(struct ddb_port *port) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci if (port->dvb[0].dev) 3738c2ecf20Sopenharmony_ci dvb_unregister_device(port->dvb[0].dev); 3748c2ecf20Sopenharmony_ci if (port->en) { 3758c2ecf20Sopenharmony_ci dvb_ca_en50221_release(port->en); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci dvb_module_release(port->dvb[0].i2c_client[0]); 3788c2ecf20Sopenharmony_ci port->dvb[0].i2c_client[0] = NULL; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci /* free alloc'ed memory if needed */ 3818c2ecf20Sopenharmony_ci if (port->en_freedata) 3828c2ecf20Sopenharmony_ci kfree(port->en->data); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci port->en = NULL; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci} 387