aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/pvrusb2/pvrusb2-i2c-core.c')
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-core.c417
1 files changed, 4 insertions, 413 deletions
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index d6a35401fef..9464862745f 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -18,6 +18,7 @@
*
*/
+#include <linux/i2c.h>
#include "pvrusb2-i2c-core.h"
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-debug.h"
@@ -29,8 +30,7 @@
/*
This module attempts to implement a compliant I2C adapter for the pvrusb2
- device. By doing this we can then make use of existing functionality in
- V4L (e.g. tuner.c) rather than rolling our own.
+ device.
*/
@@ -42,10 +42,6 @@ static int ir_mode[PVR_NUM] = { [0 ... PVR_NUM-1] = 1 };
module_param_array(ir_mode, int, NULL, 0444);
MODULE_PARM_DESC(ir_mode,"specify: 0=disable IR reception, 1=normal IR");
-static unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp,
- unsigned int detail,
- char *buf,unsigned int maxlen);
-
static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */
u8 i2c_addr, /* I2C address we're talking to */
u8 *data, /* Data to write */
@@ -524,414 +520,13 @@ static u32 pvr2_i2c_functionality(struct i2c_adapter *adap)
return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
}
-static int pvr2_i2c_core_singleton(struct i2c_client *cp,
- unsigned int cmd,void *arg)
-{
- int stat;
- if (!cp) return -EINVAL;
- if (!(cp->driver)) return -EINVAL;
- if (!(cp->driver->command)) return -EINVAL;
- if (!try_module_get(cp->driver->driver.owner)) return -EAGAIN;
- stat = cp->driver->command(cp,cmd,arg);
- module_put(cp->driver->driver.owner);
- return stat;
-}
-
-int pvr2_i2c_client_cmd(struct pvr2_i2c_client *cp,unsigned int cmd,void *arg)
-{
- int stat;
- if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) {
- char buf[100];
- unsigned int cnt;
- cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG,
- buf,sizeof(buf));
- pvr2_trace(PVR2_TRACE_I2C_CMD,
- "i2c COMMAND (code=%u 0x%x) to %.*s",
- cmd,cmd,cnt,buf);
- }
- stat = pvr2_i2c_core_singleton(cp->client,cmd,arg);
- if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) {
- char buf[100];
- unsigned int cnt;
- cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG,
- buf,sizeof(buf));
- pvr2_trace(PVR2_TRACE_I2C_CMD,
- "i2c COMMAND to %.*s (ret=%d)",cnt,buf,stat);
- }
- return stat;
-}
-
-int pvr2_i2c_core_cmd(struct pvr2_hdw *hdw,unsigned int cmd,void *arg)
-{
- struct pvr2_i2c_client *cp, *ncp;
- int stat = -EINVAL;
-
- if (!hdw) return stat;
-
- mutex_lock(&hdw->i2c_list_lock);
- list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
- if (!cp->recv_enable) continue;
- mutex_unlock(&hdw->i2c_list_lock);
- stat = pvr2_i2c_client_cmd(cp,cmd,arg);
- mutex_lock(&hdw->i2c_list_lock);
- }
- mutex_unlock(&hdw->i2c_list_lock);
- return stat;
-}
-
-
-static int handler_check(struct pvr2_i2c_client *cp)
-{
- struct pvr2_i2c_handler *hp = cp->handler;
- if (!hp) return 0;
- if (!hp->func_table->check) return 0;
- return hp->func_table->check(hp->func_data) != 0;
-}
-
-#define BUFSIZE 500
-
-
-void pvr2_i2c_core_status_poll(struct pvr2_hdw *hdw)
-{
- struct pvr2_i2c_client *cp;
- mutex_lock(&hdw->i2c_list_lock); do {
- struct v4l2_tuner *vtp = &hdw->tuner_signal_info;
- memset(vtp,0,sizeof(*vtp));
- list_for_each_entry(cp, &hdw->i2c_clients, list) {
- if (!cp->detected_flag) continue;
- if (!cp->status_poll) continue;
- cp->status_poll(cp);
- }
- hdw->tuner_signal_stale = 0;
- pvr2_trace(PVR2_TRACE_CHIPS,"i2c status poll"
- " type=%u strength=%u audio=0x%x cap=0x%x"
- " low=%u hi=%u",
- vtp->type,
- vtp->signal,vtp->rxsubchans,vtp->capability,
- vtp->rangelow,vtp->rangehigh);
- } while (0); mutex_unlock(&hdw->i2c_list_lock);
-}
-
-
-/* Issue various I2C operations to bring chip-level drivers into sync with
- state stored in this driver. */
-void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
-{
- unsigned long msk;
- unsigned int idx;
- struct pvr2_i2c_client *cp, *ncp;
-
- if (!hdw->i2c_linked) return;
- if (!(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL)) {
- return;
- }
- mutex_lock(&hdw->i2c_list_lock); do {
- pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync BEGIN");
- if (hdw->i2c_pend_types & PVR2_I2C_PEND_DETECT) {
- /* One or more I2C clients have attached since we
- last synced. So scan the list and identify the
- new clients. */
- char *buf;
- unsigned int cnt;
- unsigned long amask = 0;
- buf = kmalloc(BUFSIZE,GFP_KERNEL);
- pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_DETECT");
- hdw->i2c_pend_types &= ~PVR2_I2C_PEND_DETECT;
- list_for_each_entry(cp, &hdw->i2c_clients, list) {
- if (!cp->detected_flag) {
- cp->ctl_mask = 0;
- pvr2_i2c_probe(hdw,cp);
- cp->detected_flag = !0;
- msk = cp->ctl_mask;
- cnt = 0;
- if (buf) {
- cnt = pvr2_i2c_client_describe(
- cp,
- PVR2_I2C_DETAIL_ALL,
- buf,BUFSIZE);
- }
- trace_i2c("Probed: %.*s",cnt,buf);
- if (handler_check(cp)) {
- hdw->i2c_pend_types |=
- PVR2_I2C_PEND_CLIENT;
- }
- cp->pend_mask = msk;
- hdw->i2c_pend_mask |= msk;
- hdw->i2c_pend_types |=
- PVR2_I2C_PEND_REFRESH;
- }
- amask |= cp->ctl_mask;
- }
- hdw->i2c_active_mask = amask;
- if (buf) kfree(buf);
- }
- if (hdw->i2c_pend_types & PVR2_I2C_PEND_STALE) {
- /* Need to do one or more global updates. Arrange
- for this to happen. */
- unsigned long m2;
- pvr2_trace(PVR2_TRACE_I2C_CORE,
- "i2c: PEND_STALE (0x%lx)",
- hdw->i2c_stale_mask);
- hdw->i2c_pend_types &= ~PVR2_I2C_PEND_STALE;
- list_for_each_entry(cp, &hdw->i2c_clients, list) {
- m2 = hdw->i2c_stale_mask;
- m2 &= cp->ctl_mask;
- m2 &= ~cp->pend_mask;
- if (m2) {
- pvr2_trace(PVR2_TRACE_I2C_CORE,
- "i2c: cp=%p setting 0x%lx",
- cp,m2);
- cp->pend_mask |= m2;
- }
- }
- hdw->i2c_pend_mask |= hdw->i2c_stale_mask;
- hdw->i2c_stale_mask = 0;
- hdw->i2c_pend_types |= PVR2_I2C_PEND_REFRESH;
- }
- if (hdw->i2c_pend_types & PVR2_I2C_PEND_CLIENT) {
- /* One or more client handlers are asking for an
- update. Run through the list of known clients
- and update each one. */
- pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_CLIENT");
- hdw->i2c_pend_types &= ~PVR2_I2C_PEND_CLIENT;
- list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients,
- list) {
- if (!cp->handler) continue;
- if (!cp->handler->func_table->update) continue;
- pvr2_trace(PVR2_TRACE_I2C_CORE,
- "i2c: cp=%p update",cp);
- mutex_unlock(&hdw->i2c_list_lock);
- cp->handler->func_table->update(
- cp->handler->func_data);
- mutex_lock(&hdw->i2c_list_lock);
- /* If client's update function set some
- additional pending bits, account for that
- here. */
- if (cp->pend_mask & ~hdw->i2c_pend_mask) {
- hdw->i2c_pend_mask |= cp->pend_mask;
- hdw->i2c_pend_types |=
- PVR2_I2C_PEND_REFRESH;
- }
- }
- }
- if (hdw->i2c_pend_types & PVR2_I2C_PEND_REFRESH) {
- const struct pvr2_i2c_op *opf;
- unsigned long pm;
- /* Some actual updates are pending. Walk through
- each update type and perform it. */
- pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_REFRESH"
- " (0x%lx)",hdw->i2c_pend_mask);
- hdw->i2c_pend_types &= ~PVR2_I2C_PEND_REFRESH;
- pm = hdw->i2c_pend_mask;
- hdw->i2c_pend_mask = 0;
- for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
- if (!(pm & msk)) continue;
- pm &= ~msk;
- list_for_each_entry(cp, &hdw->i2c_clients,
- list) {
- if (cp->pend_mask & msk) {
- cp->pend_mask &= ~msk;
- cp->recv_enable = !0;
- } else {
- cp->recv_enable = 0;
- }
- }
- opf = pvr2_i2c_get_op(idx);
- if (!opf) continue;
- mutex_unlock(&hdw->i2c_list_lock);
- opf->update(hdw);
- mutex_lock(&hdw->i2c_list_lock);
- }
- }
- pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync END");
- } while (0); mutex_unlock(&hdw->i2c_list_lock);
-}
-
-int pvr2_i2c_core_check_stale(struct pvr2_hdw *hdw)
-{
- unsigned long msk,sm,pm;
- unsigned int idx;
- const struct pvr2_i2c_op *opf;
- struct pvr2_i2c_client *cp;
- unsigned int pt = 0;
-
- pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale BEGIN");
-
- pm = hdw->i2c_active_mask;
- sm = 0;
- for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
- if (!(msk & pm)) continue;
- pm &= ~msk;
- opf = pvr2_i2c_get_op(idx);
- if (!opf) continue;
- if (opf->check(hdw)) {
- sm |= msk;
- }
- }
- if (sm) pt |= PVR2_I2C_PEND_STALE;
-
- list_for_each_entry(cp, &hdw->i2c_clients, list)
- if (handler_check(cp))
- pt |= PVR2_I2C_PEND_CLIENT;
-
- if (pt) {
- mutex_lock(&hdw->i2c_list_lock); do {
- hdw->i2c_pend_types |= pt;
- hdw->i2c_stale_mask |= sm;
- hdw->i2c_pend_mask |= hdw->i2c_stale_mask;
- } while (0); mutex_unlock(&hdw->i2c_list_lock);
- }
-
- pvr2_trace(PVR2_TRACE_I2C_CORE,
- "i2c: types=0x%x stale=0x%lx pend=0x%lx",
- hdw->i2c_pend_types,
- hdw->i2c_stale_mask,
- hdw->i2c_pend_mask);
- pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale END");
-
- return (hdw->i2c_pend_types & PVR2_I2C_PEND_ALL) != 0;
-}
-
-static unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp,
- unsigned int detail,
- char *buf,unsigned int maxlen)
-{
- unsigned int ccnt,bcnt;
- int spcfl = 0;
- const struct pvr2_i2c_op *opf;
-
- ccnt = 0;
- if (detail & PVR2_I2C_DETAIL_DEBUG) {
- bcnt = scnprintf(buf,maxlen,
- "ctxt=%p ctl_mask=0x%lx",
- cp,cp->ctl_mask);
- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
- spcfl = !0;
- }
- bcnt = scnprintf(buf,maxlen,
- "%s%s @ 0x%x",
- (spcfl ? " " : ""),
- cp->client->name,
- cp->client->addr);
- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
- if ((detail & PVR2_I2C_DETAIL_HANDLER) &&
- cp->handler && cp->handler->func_table->describe) {
- bcnt = scnprintf(buf,maxlen," (");
- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
- bcnt = cp->handler->func_table->describe(
- cp->handler->func_data,buf,maxlen);
- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
- bcnt = scnprintf(buf,maxlen,")");
- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
- }
- if ((detail & PVR2_I2C_DETAIL_CTLMASK) && cp->ctl_mask) {
- unsigned int idx;
- unsigned long msk,sm;
-
- bcnt = scnprintf(buf,maxlen," [");
- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
- sm = 0;
- spcfl = 0;
- for (idx = 0, msk = 1; msk; idx++, msk <<= 1) {
- if (!(cp->ctl_mask & msk)) continue;
- opf = pvr2_i2c_get_op(idx);
- if (opf) {
- bcnt = scnprintf(buf,maxlen,"%s%s",
- spcfl ? " " : "",
- opf->name);
- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
- spcfl = !0;
- } else {
- sm |= msk;
- }
- }
- if (sm) {
- bcnt = scnprintf(buf,maxlen,"%s%lx",
- idx != 0 ? " " : "",sm);
- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
- }
- bcnt = scnprintf(buf,maxlen,"]");
- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
- }
- return ccnt;
-}
-
-unsigned int pvr2_i2c_report(struct pvr2_hdw *hdw,
- char *buf,unsigned int maxlen)
-{
- unsigned int ccnt,bcnt;
- struct pvr2_i2c_client *cp;
- ccnt = 0;
- mutex_lock(&hdw->i2c_list_lock); do {
- list_for_each_entry(cp, &hdw->i2c_clients, list) {
- bcnt = pvr2_i2c_client_describe(
- cp,
- (PVR2_I2C_DETAIL_HANDLER|
- PVR2_I2C_DETAIL_CTLMASK),
- buf,maxlen);
- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
- bcnt = scnprintf(buf,maxlen,"\n");
- ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
- }
- } while (0); mutex_unlock(&hdw->i2c_list_lock);
- return ccnt;
-}
-
static int pvr2_i2c_attach_inform(struct i2c_client *client)
{
- struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
- struct pvr2_i2c_client *cp;
- int fl = !(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL);
- cp = kzalloc(sizeof(*cp),GFP_KERNEL);
- trace_i2c("i2c_attach [client=%s @ 0x%x ctxt=%p]",
- client->name,
- client->addr,cp);
- if (!cp) return -ENOMEM;
- cp->hdw = hdw;
- INIT_LIST_HEAD(&cp->list);
- cp->client = client;
- mutex_lock(&hdw->i2c_list_lock); do {
- hdw->cropcap_stale = !0;
- list_add_tail(&cp->list,&hdw->i2c_clients);
- hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT;
- } while (0); mutex_unlock(&hdw->i2c_list_lock);
- if (fl) queue_work(hdw->workqueue,&hdw->worki2csync);
return 0;
}
static int pvr2_i2c_detach_inform(struct i2c_client *client)
{
- struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
- struct pvr2_i2c_client *cp, *ncp;
- unsigned long amask = 0;
- int foundfl = 0;
- mutex_lock(&hdw->i2c_list_lock); do {
- hdw->cropcap_stale = !0;
- list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
- if (cp->client == client) {
- trace_i2c("pvr2_i2c_detach"
- " [client=%s @ 0x%x ctxt=%p]",
- client->name,
- client->addr,cp);
- if (cp->handler &&
- cp->handler->func_table->detach) {
- cp->handler->func_table->detach(
- cp->handler->func_data);
- }
- list_del(&cp->list);
- kfree(cp);
- foundfl = !0;
- continue;
- }
- amask |= cp->ctl_mask;
- }
- hdw->i2c_active_mask = amask;
- } while (0); mutex_unlock(&hdw->i2c_list_lock);
- if (!foundfl) {
- trace_i2c("pvr2_i2c_detach [client=%s @ 0x%x ctxt=<unknown>]",
- client->name,
- client->addr);
- }
return 0;
}
@@ -942,7 +537,7 @@ static struct i2c_algorithm pvr2_i2c_algo_template = {
static struct i2c_adapter pvr2_i2c_adap_template = {
.owner = THIS_MODULE,
- .class = I2C_CLASS_TV_ANALOG,
+ .class = 0,
.id = I2C_HW_B_BT848,
.client_register = pvr2_i2c_attach_inform,
.client_unregister = pvr2_i2c_detach_inform,
@@ -1009,12 +604,8 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
hdw->i2c_adap.dev.parent = &hdw->usb_dev->dev;
hdw->i2c_adap.algo = &hdw->i2c_algo;
hdw->i2c_adap.algo_data = hdw;
- hdw->i2c_pend_mask = 0;
- hdw->i2c_stale_mask = 0;
- hdw->i2c_active_mask = 0;
- INIT_LIST_HEAD(&hdw->i2c_clients);
- mutex_init(&hdw->i2c_list_lock);
hdw->i2c_linked = !0;
+ i2c_set_adapdata(&hdw->i2c_adap, &hdw->v4l2_dev);
i2c_add_adapter(&hdw->i2c_adap);
if (hdw->i2c_func[0x18] == i2c_24xxx_ir) {
/* Probe for a different type of IR receiver on this