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