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