linux/drivers/media/pci/ddbridge/ddbridge-ci.c
<<
>>
Prefs
   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
  29static 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
  45static 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
  60static 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
  71static 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
  92static 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
 103static 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
 120static 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
 129static 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
 139static 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
 152static 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
 163static 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
 180static 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
 189static 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
 202static 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
 212static 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
 225static 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
 235static 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
 249static 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
 259static 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
 268static 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
 285static 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
 296static 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
 314static const struct cxd2099_cfg cxd_cfgtmpl = {
 315        .bitrate =  72000,
 316        .polarity = 1,
 317        .clock_mode = 1,
 318        .max_i2c = 512,
 319};
 320
 321static 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
 338err:
 339        dev_err(port->dev->dev, "CXD2099AR attach failed\n");
 340        return -ENODEV;
 341}
 342
 343int 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
 370void 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