Commit dd3c5d00 authored by Ralph Metzler's avatar Ralph Metzler Committed by Mauro Carvalho Chehab

media: staging: cxd2099: Fixed buffer mode

The buffer mode was already implemented in this driver, but it did not work
as expected. This has been fixed now, but it is still deactivated and can
be activated by removing a comment at the begin of the file.

Original code change by Ralph Metzler, modified by Jasmin Jessich and
Daniel Scheller to match Kernel code style.
Signed-off-by: default avatarRalph Metzler <rjkm@metzlerbros.de>
Signed-off-by: default avatarDaniel Scheller <d.scheller@gmx.net>
Signed-off-by: default avatarJasmin Jessich <jasmin@anw.at>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
parent f894165c
......@@ -1305,6 +1305,7 @@ static struct cxd2099_cfg cxd_cfg = {
.adr = 0x40,
.polarity = 1,
.clock_mode = 1,
.max_i2c = 512,
};
static int ddb_ci_attach(struct ddb_port *port)
......
/*
* cxd2099.c: Driver for the CXD2099AR Common Interface Controller
*
* Copyright (C) 2010-2011 Digital Devices GmbH
* Copyright (C) 2010-2013 Digital Devices GmbH
*
*
* This program is free software; you can redistribute it and/or
......@@ -33,7 +33,9 @@
#include "cxd2099.h"
#define MAX_BUFFER_SIZE 248
/* #define BUFFER_MODE 1 */
static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount);
struct cxd {
struct dvb_ca_en50221 en;
......@@ -48,6 +50,7 @@ struct cxd {
int mode;
int ready;
int dr;
int write_busy;
int slot_stat;
u8 amem[1024];
......@@ -55,6 +58,9 @@ struct cxd {
int cammode;
struct mutex lock;
u8 rbuf[1028];
u8 wbuf[1028];
};
static int i2c_write_reg(struct i2c_adapter *adapter, u8 adr,
......@@ -73,7 +79,7 @@ static int i2c_write_reg(struct i2c_adapter *adapter, u8 adr,
}
static int i2c_write(struct i2c_adapter *adapter, u8 adr,
u8 *data, u8 len)
u8 *data, u16 len)
{
struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = data, .len = len};
......@@ -100,12 +106,12 @@ static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr,
}
static int i2c_read(struct i2c_adapter *adapter, u8 adr,
u8 reg, u8 *data, u8 n)
u8 reg, u8 *data, u16 n)
{
struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
.buf = &reg, .len = 1},
{.addr = adr, .flags = I2C_M_RD,
.buf = data, .len = n} };
.buf = &reg, .len = 1},
{.addr = adr, .flags = I2C_M_RD,
.buf = data, .len = n} };
if (i2c_transfer(adapter, msgs, 2) != 2) {
dev_err(&adapter->dev, "error in i2c_read\n");
......@@ -114,14 +120,26 @@ static int i2c_read(struct i2c_adapter *adapter, u8 adr,
return 0;
}
static int read_block(struct cxd *ci, u8 adr, u8 *data, u8 n)
static int read_block(struct cxd *ci, u8 adr, u8 *data, u16 n)
{
int status;
int status = 0;
status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
if (ci->lastaddress != adr)
status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
if (!status) {
ci->lastaddress = adr;
status = i2c_read(ci->i2c, ci->cfg.adr, 1, data, n);
while (n) {
int len = n;
if (ci->cfg.max_i2c && (len > ci->cfg.max_i2c))
len = ci->cfg.max_i2c;
status = i2c_read(ci->i2c, ci->cfg.adr, 1, data, len);
if (status)
return status;
data += len;
n -= len;
}
}
return status;
}
......@@ -182,16 +200,16 @@ static int write_io(struct cxd *ci, u16 address, u8 val)
static int write_regm(struct cxd *ci, u8 reg, u8 val, u8 mask)
{
int status;
int status = 0;
status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, reg);
if (ci->lastaddress != reg)
status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, reg);
if (!status && reg >= 6 && reg <= 8 && mask != 0xff)
status = i2c_read_reg(ci->i2c, ci->cfg.adr, 1, &ci->regs[reg]);
ci->lastaddress = reg;
ci->regs[reg] = (ci->regs[reg] & (~mask)) | val;
if (!status) {
ci->lastaddress = reg;
if (!status)
status = i2c_write_reg(ci->i2c, ci->cfg.adr, 1, ci->regs[reg]);
}
if (reg == 0x20)
ci->regs[reg] &= 0x7f;
return status;
......@@ -203,16 +221,31 @@ static int write_reg(struct cxd *ci, u8 reg, u8 val)
}
#ifdef BUFFER_MODE
static int write_block(struct cxd *ci, u8 adr, u8 *data, int n)
static int write_block(struct cxd *ci, u8 adr, u8 *data, u16 n)
{
int status;
u8 buf[256] = {1};
status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
if (!status) {
ci->lastaddress = adr;
memcpy(buf + 1, data, n);
status = i2c_write(ci->i2c, ci->cfg.adr, buf, n + 1);
int status = 0;
u8 *buf = ci->wbuf;
if (ci->lastaddress != adr)
status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
if (status)
return status;
dev_info(&ci->i2c->dev, "write_block %d\n", n);
ci->lastaddress = adr;
buf[0] = 1;
while (n) {
int len = n;
if (ci->cfg.max_i2c && (len + 1 > ci->cfg.max_i2c))
len = ci->cfg.max_i2c - 1;
dev_info(&ci->i2c->dev, "write %d\n", len);
memcpy(buf + 1, data, len);
status = i2c_write(ci->i2c, ci->cfg.adr, buf, len + 1);
if (status)
return status;
n -= len;
data += len;
}
return status;
}
......@@ -238,6 +271,8 @@ static void set_mode(struct cxd *ci, int mode)
static void cam_mode(struct cxd *ci, int mode)
{
u8 dummy;
if (mode == ci->cammode)
return;
......@@ -246,16 +281,15 @@ static void cam_mode(struct cxd *ci, int mode)
write_regm(ci, 0x20, 0x80, 0x80);
break;
case 0x01:
#ifdef BUFFER_MODE
if (!ci->en.read_data)
return;
ci->write_busy = 0;
dev_info(&ci->i2c->dev, "enable cam buffer mode\n");
/* write_reg(ci, 0x0d, 0x00); */
/* write_reg(ci, 0x0e, 0x01); */
write_reg(ci, 0x0d, 0x00);
write_reg(ci, 0x0e, 0x01);
write_regm(ci, 0x08, 0x40, 0x40);
/* read_reg(ci, 0x12, &dummy); */
read_reg(ci, 0x12, &dummy);
write_regm(ci, 0x08, 0x80, 0x80);
#endif
break;
default:
break;
......@@ -325,7 +359,10 @@ static int init(struct cxd *ci)
if (status < 0)
break;
if (ci->cfg.clock_mode) {
if (ci->cfg.clock_mode == 2) {
/* bitrate*2^13/ 72000 */
u32 reg = ((ci->cfg.bitrate << 13) + 71999) / 72000;
if (ci->cfg.polarity) {
status = write_reg(ci, 0x09, 0x6f);
if (status < 0)
......@@ -335,6 +372,25 @@ static int init(struct cxd *ci)
if (status < 0)
break;
}
status = write_reg(ci, 0x20, 0x08);
if (status < 0)
break;
status = write_reg(ci, 0x21, (reg >> 8) & 0xff);
if (status < 0)
break;
status = write_reg(ci, 0x22, reg & 0xff);
if (status < 0)
break;
} else if (ci->cfg.clock_mode == 1) {
if (ci->cfg.polarity) {
status = write_reg(ci, 0x09, 0x6f); /* D */
if (status < 0)
break;
} else {
status = write_reg(ci, 0x09, 0x6d);
if (status < 0)
break;
}
status = write_reg(ci, 0x20, 0x68);
if (status < 0)
break;
......@@ -346,7 +402,7 @@ static int init(struct cxd *ci)
break;
} else {
if (ci->cfg.polarity) {
status = write_reg(ci, 0x09, 0x4f);
status = write_reg(ci, 0x09, 0x4f); /* C */
if (status < 0)
break;
} else {
......@@ -354,7 +410,6 @@ static int init(struct cxd *ci)
if (status < 0)
break;
}
status = write_reg(ci, 0x20, 0x28);
if (status < 0)
break;
......@@ -401,7 +456,6 @@ static int read_attribute_mem(struct dvb_ca_en50221 *ca,
set_mode(ci, 1);
read_pccard(ci, address, &val, 1);
mutex_unlock(&ci->lock);
/* printk(KERN_INFO "%02x:%02x\n", address,val); */
return val;
}
......@@ -446,6 +500,9 @@ static int slot_reset(struct dvb_ca_en50221 *ca, int slot)
{
struct cxd *ci = ca->data;
if (ci->cammode)
read_data(ca, slot, ci->rbuf, 0);
mutex_lock(&ci->lock);
cam_mode(ci, 0);
write_reg(ci, 0x00, 0x21);
......@@ -465,7 +522,6 @@ static int slot_reset(struct dvb_ca_en50221 *ca, int slot)
}
}
mutex_unlock(&ci->lock);
/* msleep(500); */
return 0;
}
......@@ -474,11 +530,19 @@ static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
struct cxd *ci = ca->data;
dev_info(&ci->i2c->dev, "%s\n", __func__);
if (ci->cammode)
read_data(ca, slot, ci->rbuf, 0);
mutex_lock(&ci->lock);
write_reg(ci, 0x00, 0x21);
write_reg(ci, 0x06, 0x1F);
msleep(300);
write_regm(ci, 0x09, 0x08, 0x08);
write_regm(ci, 0x20, 0x80, 0x80); /* Reset CAM Mode */
write_regm(ci, 0x06, 0x07, 0x07); /* Clear IO Mode */
ci->mode = -1;
ci->write_busy = 0;
mutex_unlock(&ci->lock);
return 0;
}
......@@ -490,9 +554,7 @@ static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
mutex_lock(&ci->lock);
write_regm(ci, 0x09, 0x00, 0x08);
set_mode(ci, 0);
#ifdef BUFFER_MODE
cam_mode(ci, 1);
#endif
mutex_unlock(&ci->lock);
return 0;
}
......@@ -510,8 +572,10 @@ static int campoll(struct cxd *ci)
ci->dr = 1;
dev_info(&ci->i2c->dev, "DR\n");
}
if (istat & 0x20)
if (istat & 0x20) {
ci->write_busy = 0;
dev_info(&ci->i2c->dev, "WC\n");
}
if (istat & 2) {
u8 slotstat;
......@@ -519,7 +583,8 @@ static int campoll(struct cxd *ci)
read_reg(ci, 0x01, &slotstat);
if (!(2 & slotstat)) {
if (!ci->slot_stat) {
ci->slot_stat = DVB_CA_EN50221_POLL_CAM_PRESENT;
ci->slot_stat |=
DVB_CA_EN50221_POLL_CAM_PRESENT;
write_regm(ci, 0x03, 0x08, 0x08);
}
......@@ -531,8 +596,8 @@ static int campoll(struct cxd *ci)
ci->ready = 0;
}
}
if (istat & 8 &&
ci->slot_stat == DVB_CA_EN50221_POLL_CAM_PRESENT) {
if ((istat & 8) &&
(ci->slot_stat == DVB_CA_EN50221_POLL_CAM_PRESENT)) {
ci->ready = 1;
ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_READY;
}
......@@ -553,7 +618,6 @@ static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
return ci->slot_stat;
}
#ifdef BUFFER_MODE
static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
{
struct cxd *ci = ca->data;
......@@ -571,23 +635,33 @@ static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
mutex_lock(&ci->lock);
read_reg(ci, 0x0f, &msb);
read_reg(ci, 0x10, &lsb);
len = (msb << 8) | lsb;
len = ((u16)msb << 8) | lsb;
if (len > ecount || len < 2) {
/* read it anyway or cxd may hang */
read_block(ci, 0x12, ci->rbuf, len);
mutex_unlock(&ci->lock);
return -EIO;
}
read_block(ci, 0x12, ebuf, len);
ci->dr = 0;
mutex_unlock(&ci->lock);
return len;
}
#ifdef BUFFER_MODE
static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
{
struct cxd *ci = ca->data;
if (ci->write_busy)
return -EAGAIN;
mutex_lock(&ci->lock);
dev_info(&ci->i2c->dev, "%s %d\n", __func__, ecount);
write_reg(ci, 0x0d, ecount >> 8);
write_reg(ci, 0x0e, ecount & 0xff);
write_block(ci, 0x11, ebuf, ecount);
ci->write_busy = 1;
mutex_unlock(&ci->lock);
return ecount;
}
......
......@@ -30,8 +30,10 @@
struct cxd2099_cfg {
u32 bitrate;
u8 adr;
u8 polarity:1;
u8 clock_mode:1;
u8 polarity;
u8 clock_mode;
u32 max_i2c;
};
#if defined(CONFIG_DVB_CXD2099) || \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment