12504ba9fSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
20c0d06caSMauro Carvalho Chehab /*
30c0d06caSMauro Carvalho Chehab *
40c0d06caSMauro Carvalho Chehab * Copyright (C) 2005 Mike Isely <isely@pobox.com>
50c0d06caSMauro Carvalho Chehab */
60c0d06caSMauro Carvalho Chehab
70c0d06caSMauro Carvalho Chehab #include <linux/i2c.h>
80c0d06caSMauro Carvalho Chehab #include <linux/module.h>
9b5dcee22SMauro Carvalho Chehab #include <media/i2c/ir-kbd-i2c.h>
100c0d06caSMauro Carvalho Chehab #include "pvrusb2-i2c-core.h"
110c0d06caSMauro Carvalho Chehab #include "pvrusb2-hdw-internal.h"
120c0d06caSMauro Carvalho Chehab #include "pvrusb2-debug.h"
130c0d06caSMauro Carvalho Chehab #include "pvrusb2-fx2-cmd.h"
140c0d06caSMauro Carvalho Chehab #include "pvrusb2.h"
150c0d06caSMauro Carvalho Chehab
160c0d06caSMauro Carvalho Chehab #define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
170c0d06caSMauro Carvalho Chehab
180c0d06caSMauro Carvalho Chehab /*
190c0d06caSMauro Carvalho Chehab
200c0d06caSMauro Carvalho Chehab This module attempts to implement a compliant I2C adapter for the pvrusb2
210c0d06caSMauro Carvalho Chehab device.
220c0d06caSMauro Carvalho Chehab
230c0d06caSMauro Carvalho Chehab */
240c0d06caSMauro Carvalho Chehab
250c0d06caSMauro Carvalho Chehab static unsigned int i2c_scan;
260c0d06caSMauro Carvalho Chehab module_param(i2c_scan, int, S_IRUGO|S_IWUSR);
270c0d06caSMauro Carvalho Chehab MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
280c0d06caSMauro Carvalho Chehab
290c0d06caSMauro Carvalho Chehab static int ir_mode[PVR_NUM] = { [0 ... PVR_NUM-1] = 1 };
300c0d06caSMauro Carvalho Chehab module_param_array(ir_mode, int, NULL, 0444);
310c0d06caSMauro Carvalho Chehab MODULE_PARM_DESC(ir_mode,"specify: 0=disable IR reception, 1=normal IR");
320c0d06caSMauro Carvalho Chehab
330c0d06caSMauro Carvalho Chehab static int pvr2_disable_ir_video;
340c0d06caSMauro Carvalho Chehab module_param_named(disable_autoload_ir_video, pvr2_disable_ir_video,
350c0d06caSMauro Carvalho Chehab int, S_IRUGO|S_IWUSR);
360c0d06caSMauro Carvalho Chehab MODULE_PARM_DESC(disable_autoload_ir_video,
370c0d06caSMauro Carvalho Chehab "1=do not try to autoload ir_video IR receiver");
380c0d06caSMauro Carvalho Chehab
pvr2_i2c_write(struct pvr2_hdw * hdw,u8 i2c_addr,u8 * data,u16 length)390c0d06caSMauro Carvalho Chehab static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */
400c0d06caSMauro Carvalho Chehab u8 i2c_addr, /* I2C address we're talking to */
410c0d06caSMauro Carvalho Chehab u8 *data, /* Data to write */
420c0d06caSMauro Carvalho Chehab u16 length) /* Size of data to write */
430c0d06caSMauro Carvalho Chehab {
440c0d06caSMauro Carvalho Chehab /* Return value - default 0 means success */
450c0d06caSMauro Carvalho Chehab int ret;
460c0d06caSMauro Carvalho Chehab
470c0d06caSMauro Carvalho Chehab
480c0d06caSMauro Carvalho Chehab if (!data) length = 0;
490c0d06caSMauro Carvalho Chehab if (length > (sizeof(hdw->cmd_buffer) - 3)) {
500c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_ERROR_LEGS,
5196292c89SMauro Carvalho Chehab "Killing an I2C write to %u that is too large (desired=%u limit=%u)",
520c0d06caSMauro Carvalho Chehab i2c_addr,
530c0d06caSMauro Carvalho Chehab length,(unsigned int)(sizeof(hdw->cmd_buffer) - 3));
540c0d06caSMauro Carvalho Chehab return -ENOTSUPP;
550c0d06caSMauro Carvalho Chehab }
560c0d06caSMauro Carvalho Chehab
570c0d06caSMauro Carvalho Chehab LOCK_TAKE(hdw->ctl_lock);
580c0d06caSMauro Carvalho Chehab
590c0d06caSMauro Carvalho Chehab /* Clear the command buffer (likely to be paranoia) */
600c0d06caSMauro Carvalho Chehab memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer));
610c0d06caSMauro Carvalho Chehab
620c0d06caSMauro Carvalho Chehab /* Set up command buffer for an I2C write */
630c0d06caSMauro Carvalho Chehab hdw->cmd_buffer[0] = FX2CMD_I2C_WRITE; /* write prefix */
640c0d06caSMauro Carvalho Chehab hdw->cmd_buffer[1] = i2c_addr; /* i2c addr of chip */
650c0d06caSMauro Carvalho Chehab hdw->cmd_buffer[2] = length; /* length of what follows */
660c0d06caSMauro Carvalho Chehab if (length) memcpy(hdw->cmd_buffer + 3, data, length);
670c0d06caSMauro Carvalho Chehab
680c0d06caSMauro Carvalho Chehab /* Do the operation */
690c0d06caSMauro Carvalho Chehab ret = pvr2_send_request(hdw,
700c0d06caSMauro Carvalho Chehab hdw->cmd_buffer,
710c0d06caSMauro Carvalho Chehab length + 3,
720c0d06caSMauro Carvalho Chehab hdw->cmd_buffer,
730c0d06caSMauro Carvalho Chehab 1);
740c0d06caSMauro Carvalho Chehab if (!ret) {
750c0d06caSMauro Carvalho Chehab if (hdw->cmd_buffer[0] != 8) {
760c0d06caSMauro Carvalho Chehab ret = -EIO;
770c0d06caSMauro Carvalho Chehab if (hdw->cmd_buffer[0] != 7) {
7896292c89SMauro Carvalho Chehab trace_i2c("unexpected status from i2_write[%d]: %d",
790c0d06caSMauro Carvalho Chehab i2c_addr,hdw->cmd_buffer[0]);
800c0d06caSMauro Carvalho Chehab }
810c0d06caSMauro Carvalho Chehab }
820c0d06caSMauro Carvalho Chehab }
830c0d06caSMauro Carvalho Chehab
840c0d06caSMauro Carvalho Chehab LOCK_GIVE(hdw->ctl_lock);
850c0d06caSMauro Carvalho Chehab
860c0d06caSMauro Carvalho Chehab return ret;
870c0d06caSMauro Carvalho Chehab }
880c0d06caSMauro Carvalho Chehab
pvr2_i2c_read(struct pvr2_hdw * hdw,u8 i2c_addr,u8 * data,u16 dlen,u8 * res,u16 rlen)890c0d06caSMauro Carvalho Chehab static int pvr2_i2c_read(struct pvr2_hdw *hdw, /* Context */
900c0d06caSMauro Carvalho Chehab u8 i2c_addr, /* I2C address we're talking to */
910c0d06caSMauro Carvalho Chehab u8 *data, /* Data to write */
920c0d06caSMauro Carvalho Chehab u16 dlen, /* Size of data to write */
930c0d06caSMauro Carvalho Chehab u8 *res, /* Where to put data we read */
940c0d06caSMauro Carvalho Chehab u16 rlen) /* Amount of data to read */
950c0d06caSMauro Carvalho Chehab {
960c0d06caSMauro Carvalho Chehab /* Return value - default 0 means success */
970c0d06caSMauro Carvalho Chehab int ret;
980c0d06caSMauro Carvalho Chehab
990c0d06caSMauro Carvalho Chehab
1000c0d06caSMauro Carvalho Chehab if (!data) dlen = 0;
1010c0d06caSMauro Carvalho Chehab if (dlen > (sizeof(hdw->cmd_buffer) - 4)) {
1020c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_ERROR_LEGS,
10396292c89SMauro Carvalho Chehab "Killing an I2C read to %u that has wlen too large (desired=%u limit=%u)",
1040c0d06caSMauro Carvalho Chehab i2c_addr,
1050c0d06caSMauro Carvalho Chehab dlen,(unsigned int)(sizeof(hdw->cmd_buffer) - 4));
1060c0d06caSMauro Carvalho Chehab return -ENOTSUPP;
1070c0d06caSMauro Carvalho Chehab }
1080c0d06caSMauro Carvalho Chehab if (res && (rlen > (sizeof(hdw->cmd_buffer) - 1))) {
1090c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_ERROR_LEGS,
11096292c89SMauro Carvalho Chehab "Killing an I2C read to %u that has rlen too large (desired=%u limit=%u)",
1110c0d06caSMauro Carvalho Chehab i2c_addr,
1120c0d06caSMauro Carvalho Chehab rlen,(unsigned int)(sizeof(hdw->cmd_buffer) - 1));
1130c0d06caSMauro Carvalho Chehab return -ENOTSUPP;
1140c0d06caSMauro Carvalho Chehab }
1150c0d06caSMauro Carvalho Chehab
1160c0d06caSMauro Carvalho Chehab LOCK_TAKE(hdw->ctl_lock);
1170c0d06caSMauro Carvalho Chehab
1180c0d06caSMauro Carvalho Chehab /* Clear the command buffer (likely to be paranoia) */
1190c0d06caSMauro Carvalho Chehab memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer));
1200c0d06caSMauro Carvalho Chehab
1210c0d06caSMauro Carvalho Chehab /* Set up command buffer for an I2C write followed by a read */
1220c0d06caSMauro Carvalho Chehab hdw->cmd_buffer[0] = FX2CMD_I2C_READ; /* read prefix */
1230c0d06caSMauro Carvalho Chehab hdw->cmd_buffer[1] = dlen; /* arg length */
1240c0d06caSMauro Carvalho Chehab hdw->cmd_buffer[2] = rlen; /* answer length. Device will send one
1250c0d06caSMauro Carvalho Chehab more byte (status). */
1260c0d06caSMauro Carvalho Chehab hdw->cmd_buffer[3] = i2c_addr; /* i2c addr of chip */
1270c0d06caSMauro Carvalho Chehab if (dlen) memcpy(hdw->cmd_buffer + 4, data, dlen);
1280c0d06caSMauro Carvalho Chehab
1290c0d06caSMauro Carvalho Chehab /* Do the operation */
1300c0d06caSMauro Carvalho Chehab ret = pvr2_send_request(hdw,
1310c0d06caSMauro Carvalho Chehab hdw->cmd_buffer,
1320c0d06caSMauro Carvalho Chehab 4 + dlen,
1330c0d06caSMauro Carvalho Chehab hdw->cmd_buffer,
1340c0d06caSMauro Carvalho Chehab rlen + 1);
1350c0d06caSMauro Carvalho Chehab if (!ret) {
1360c0d06caSMauro Carvalho Chehab if (hdw->cmd_buffer[0] != 8) {
1370c0d06caSMauro Carvalho Chehab ret = -EIO;
1380c0d06caSMauro Carvalho Chehab if (hdw->cmd_buffer[0] != 7) {
13996292c89SMauro Carvalho Chehab trace_i2c("unexpected status from i2_read[%d]: %d",
1400c0d06caSMauro Carvalho Chehab i2c_addr,hdw->cmd_buffer[0]);
1410c0d06caSMauro Carvalho Chehab }
1420c0d06caSMauro Carvalho Chehab }
1430c0d06caSMauro Carvalho Chehab }
1440c0d06caSMauro Carvalho Chehab
1450c0d06caSMauro Carvalho Chehab /* Copy back the result */
1460c0d06caSMauro Carvalho Chehab if (res && rlen) {
1470c0d06caSMauro Carvalho Chehab if (ret) {
1480c0d06caSMauro Carvalho Chehab /* Error, just blank out the return buffer */
1490c0d06caSMauro Carvalho Chehab memset(res, 0, rlen);
1500c0d06caSMauro Carvalho Chehab } else {
1510c0d06caSMauro Carvalho Chehab memcpy(res, hdw->cmd_buffer + 1, rlen);
1520c0d06caSMauro Carvalho Chehab }
1530c0d06caSMauro Carvalho Chehab }
1540c0d06caSMauro Carvalho Chehab
1550c0d06caSMauro Carvalho Chehab LOCK_GIVE(hdw->ctl_lock);
1560c0d06caSMauro Carvalho Chehab
1570c0d06caSMauro Carvalho Chehab return ret;
1580c0d06caSMauro Carvalho Chehab }
1590c0d06caSMauro Carvalho Chehab
1600c0d06caSMauro Carvalho Chehab /* This is the common low level entry point for doing I2C operations to the
1610c0d06caSMauro Carvalho Chehab hardware. */
pvr2_i2c_basic_op(struct pvr2_hdw * hdw,u8 i2c_addr,u8 * wdata,u16 wlen,u8 * rdata,u16 rlen)1620c0d06caSMauro Carvalho Chehab static int pvr2_i2c_basic_op(struct pvr2_hdw *hdw,
1630c0d06caSMauro Carvalho Chehab u8 i2c_addr,
1640c0d06caSMauro Carvalho Chehab u8 *wdata,
1650c0d06caSMauro Carvalho Chehab u16 wlen,
1660c0d06caSMauro Carvalho Chehab u8 *rdata,
1670c0d06caSMauro Carvalho Chehab u16 rlen)
1680c0d06caSMauro Carvalho Chehab {
1690c0d06caSMauro Carvalho Chehab if (!rdata) rlen = 0;
1700c0d06caSMauro Carvalho Chehab if (!wdata) wlen = 0;
1710c0d06caSMauro Carvalho Chehab if (rlen || !wlen) {
1720c0d06caSMauro Carvalho Chehab return pvr2_i2c_read(hdw,i2c_addr,wdata,wlen,rdata,rlen);
1730c0d06caSMauro Carvalho Chehab } else {
1740c0d06caSMauro Carvalho Chehab return pvr2_i2c_write(hdw,i2c_addr,wdata,wlen);
1750c0d06caSMauro Carvalho Chehab }
1760c0d06caSMauro Carvalho Chehab }
1770c0d06caSMauro Carvalho Chehab
1780c0d06caSMauro Carvalho Chehab
1790c0d06caSMauro Carvalho Chehab /* This is a special entry point for cases of I2C transaction attempts to
1800c0d06caSMauro Carvalho Chehab the IR receiver. The implementation here simulates the IR receiver by
1810c0d06caSMauro Carvalho Chehab issuing a command to the FX2 firmware and using that response to return
1820c0d06caSMauro Carvalho Chehab what the real I2C receiver would have returned. We use this for 24xxx
1830c0d06caSMauro Carvalho Chehab devices, where the IR receiver chip has been removed and replaced with
1840c0d06caSMauro Carvalho Chehab FX2 related logic. */
i2c_24xxx_ir(struct pvr2_hdw * hdw,u8 i2c_addr,u8 * wdata,u16 wlen,u8 * rdata,u16 rlen)1850c0d06caSMauro Carvalho Chehab static int i2c_24xxx_ir(struct pvr2_hdw *hdw,
1860c0d06caSMauro Carvalho Chehab u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
1870c0d06caSMauro Carvalho Chehab {
1880c0d06caSMauro Carvalho Chehab u8 dat[4];
1890c0d06caSMauro Carvalho Chehab unsigned int stat;
1900c0d06caSMauro Carvalho Chehab
1910c0d06caSMauro Carvalho Chehab if (!(rlen || wlen)) {
1920c0d06caSMauro Carvalho Chehab /* This is a probe attempt. Just let it succeed. */
1930c0d06caSMauro Carvalho Chehab return 0;
1940c0d06caSMauro Carvalho Chehab }
1950c0d06caSMauro Carvalho Chehab
1960c0d06caSMauro Carvalho Chehab /* We don't understand this kind of transaction */
1970c0d06caSMauro Carvalho Chehab if ((wlen != 0) || (rlen == 0)) return -EIO;
1980c0d06caSMauro Carvalho Chehab
1990c0d06caSMauro Carvalho Chehab if (rlen < 3) {
2000c0d06caSMauro Carvalho Chehab /* Mike Isely <isely@pobox.com> Appears to be a probe
2010c0d06caSMauro Carvalho Chehab attempt from lirc. Just fill in zeroes and return. If
2020c0d06caSMauro Carvalho Chehab we try instead to do the full transaction here, then bad
2030c0d06caSMauro Carvalho Chehab things seem to happen within the lirc driver module
2040c0d06caSMauro Carvalho Chehab (version 0.8.0-7 sources from Debian, when run under
2050c0d06caSMauro Carvalho Chehab vanilla 2.6.17.6 kernel) - and I don't have the patience
2060c0d06caSMauro Carvalho Chehab to chase it down. */
2070c0d06caSMauro Carvalho Chehab if (rlen > 0) rdata[0] = 0;
2080c0d06caSMauro Carvalho Chehab if (rlen > 1) rdata[1] = 0;
2090c0d06caSMauro Carvalho Chehab return 0;
2100c0d06caSMauro Carvalho Chehab }
2110c0d06caSMauro Carvalho Chehab
2120c0d06caSMauro Carvalho Chehab /* Issue a command to the FX2 to read the IR receiver. */
2130c0d06caSMauro Carvalho Chehab LOCK_TAKE(hdw->ctl_lock); do {
2140c0d06caSMauro Carvalho Chehab hdw->cmd_buffer[0] = FX2CMD_GET_IR_CODE;
2150c0d06caSMauro Carvalho Chehab stat = pvr2_send_request(hdw,
2160c0d06caSMauro Carvalho Chehab hdw->cmd_buffer,1,
2170c0d06caSMauro Carvalho Chehab hdw->cmd_buffer,4);
2180c0d06caSMauro Carvalho Chehab dat[0] = hdw->cmd_buffer[0];
2190c0d06caSMauro Carvalho Chehab dat[1] = hdw->cmd_buffer[1];
2200c0d06caSMauro Carvalho Chehab dat[2] = hdw->cmd_buffer[2];
2210c0d06caSMauro Carvalho Chehab dat[3] = hdw->cmd_buffer[3];
2220c0d06caSMauro Carvalho Chehab } while (0); LOCK_GIVE(hdw->ctl_lock);
2230c0d06caSMauro Carvalho Chehab
2240c0d06caSMauro Carvalho Chehab /* Give up if that operation failed. */
2250c0d06caSMauro Carvalho Chehab if (stat != 0) return stat;
2260c0d06caSMauro Carvalho Chehab
2270c0d06caSMauro Carvalho Chehab /* Mangle the results into something that looks like the real IR
2280c0d06caSMauro Carvalho Chehab receiver. */
2290c0d06caSMauro Carvalho Chehab rdata[2] = 0xc1;
2300c0d06caSMauro Carvalho Chehab if (dat[0] != 1) {
2310c0d06caSMauro Carvalho Chehab /* No code received. */
2320c0d06caSMauro Carvalho Chehab rdata[0] = 0;
2330c0d06caSMauro Carvalho Chehab rdata[1] = 0;
2340c0d06caSMauro Carvalho Chehab } else {
2350c0d06caSMauro Carvalho Chehab u16 val;
2360c0d06caSMauro Carvalho Chehab /* Mash the FX2 firmware-provided IR code into something
2370c0d06caSMauro Carvalho Chehab that the normal i2c chip-level driver expects. */
2380c0d06caSMauro Carvalho Chehab val = dat[1];
2390c0d06caSMauro Carvalho Chehab val <<= 8;
2400c0d06caSMauro Carvalho Chehab val |= dat[2];
2410c0d06caSMauro Carvalho Chehab val >>= 1;
2420c0d06caSMauro Carvalho Chehab val &= ~0x0003;
2430c0d06caSMauro Carvalho Chehab val |= 0x8000;
2440c0d06caSMauro Carvalho Chehab rdata[0] = (val >> 8) & 0xffu;
2450c0d06caSMauro Carvalho Chehab rdata[1] = val & 0xffu;
2460c0d06caSMauro Carvalho Chehab }
2470c0d06caSMauro Carvalho Chehab
2480c0d06caSMauro Carvalho Chehab return 0;
2490c0d06caSMauro Carvalho Chehab }
2500c0d06caSMauro Carvalho Chehab
2510c0d06caSMauro Carvalho Chehab /* This is a special entry point that is entered if an I2C operation is
2520c0d06caSMauro Carvalho Chehab attempted to a wm8775 chip on model 24xxx hardware. Autodetect of this
2530c0d06caSMauro Carvalho Chehab part doesn't work, but we know it is really there. So let's look for
2540c0d06caSMauro Carvalho Chehab the autodetect attempt and just return success if we see that. */
i2c_hack_wm8775(struct pvr2_hdw * hdw,u8 i2c_addr,u8 * wdata,u16 wlen,u8 * rdata,u16 rlen)2550c0d06caSMauro Carvalho Chehab static int i2c_hack_wm8775(struct pvr2_hdw *hdw,
2560c0d06caSMauro Carvalho Chehab u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
2570c0d06caSMauro Carvalho Chehab {
2580c0d06caSMauro Carvalho Chehab if (!(rlen || wlen)) {
2590c0d06caSMauro Carvalho Chehab // This is a probe attempt. Just let it succeed.
2600c0d06caSMauro Carvalho Chehab return 0;
2610c0d06caSMauro Carvalho Chehab }
2620c0d06caSMauro Carvalho Chehab return pvr2_i2c_basic_op(hdw,i2c_addr,wdata,wlen,rdata,rlen);
2630c0d06caSMauro Carvalho Chehab }
2640c0d06caSMauro Carvalho Chehab
2650c0d06caSMauro Carvalho Chehab /* This is an entry point designed to always fail any attempt to perform a
2660c0d06caSMauro Carvalho Chehab transfer. We use this to cause certain I2C addresses to not be
2670c0d06caSMauro Carvalho Chehab probed. */
i2c_black_hole(struct pvr2_hdw * hdw,u8 i2c_addr,u8 * wdata,u16 wlen,u8 * rdata,u16 rlen)2680c0d06caSMauro Carvalho Chehab static int i2c_black_hole(struct pvr2_hdw *hdw,
2690c0d06caSMauro Carvalho Chehab u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
2700c0d06caSMauro Carvalho Chehab {
2710c0d06caSMauro Carvalho Chehab return -EIO;
2720c0d06caSMauro Carvalho Chehab }
2730c0d06caSMauro Carvalho Chehab
2740c0d06caSMauro Carvalho Chehab /* This is a special entry point that is entered if an I2C operation is
2750c0d06caSMauro Carvalho Chehab attempted to a cx25840 chip on model 24xxx hardware. This chip can
2760c0d06caSMauro Carvalho Chehab sometimes wedge itself. Worse still, when this happens msp3400 can
2770c0d06caSMauro Carvalho Chehab falsely detect this part and then the system gets hosed up after msp3400
2780c0d06caSMauro Carvalho Chehab gets confused and dies. What we want to do here is try to keep msp3400
2790c0d06caSMauro Carvalho Chehab away and also try to notice if the chip is wedged and send a warning to
2800c0d06caSMauro Carvalho Chehab the system log. */
i2c_hack_cx25840(struct pvr2_hdw * hdw,u8 i2c_addr,u8 * wdata,u16 wlen,u8 * rdata,u16 rlen)2810c0d06caSMauro Carvalho Chehab static int i2c_hack_cx25840(struct pvr2_hdw *hdw,
2820c0d06caSMauro Carvalho Chehab u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
2830c0d06caSMauro Carvalho Chehab {
2840c0d06caSMauro Carvalho Chehab int ret;
2850c0d06caSMauro Carvalho Chehab unsigned int subaddr;
2860c0d06caSMauro Carvalho Chehab u8 wbuf[2];
2870c0d06caSMauro Carvalho Chehab int state = hdw->i2c_cx25840_hack_state;
2880c0d06caSMauro Carvalho Chehab
2890c0d06caSMauro Carvalho Chehab if (!(rlen || wlen)) {
2900c0d06caSMauro Carvalho Chehab // Probe attempt - always just succeed and don't bother the
2910c0d06caSMauro Carvalho Chehab // hardware (this helps to make the state machine further
2920c0d06caSMauro Carvalho Chehab // down somewhat easier).
2930c0d06caSMauro Carvalho Chehab return 0;
2940c0d06caSMauro Carvalho Chehab }
2950c0d06caSMauro Carvalho Chehab
2960c0d06caSMauro Carvalho Chehab if (state == 3) {
2970c0d06caSMauro Carvalho Chehab return pvr2_i2c_basic_op(hdw,i2c_addr,wdata,wlen,rdata,rlen);
2980c0d06caSMauro Carvalho Chehab }
2990c0d06caSMauro Carvalho Chehab
3000c0d06caSMauro Carvalho Chehab /* We're looking for the exact pattern where the revision register
3010c0d06caSMauro Carvalho Chehab is being read. The cx25840 module will always look at the
3020c0d06caSMauro Carvalho Chehab revision register first. Any other pattern of access therefore
3030c0d06caSMauro Carvalho Chehab has to be a probe attempt from somebody else so we'll reject it.
3040c0d06caSMauro Carvalho Chehab Normally we could just let each client just probe the part
3050c0d06caSMauro Carvalho Chehab anyway, but when the cx25840 is wedged, msp3400 will get a false
3060c0d06caSMauro Carvalho Chehab positive and that just screws things up... */
3070c0d06caSMauro Carvalho Chehab
3080c0d06caSMauro Carvalho Chehab if (wlen == 0) {
3090c0d06caSMauro Carvalho Chehab switch (state) {
3100c0d06caSMauro Carvalho Chehab case 1: subaddr = 0x0100; break;
3110c0d06caSMauro Carvalho Chehab case 2: subaddr = 0x0101; break;
3120c0d06caSMauro Carvalho Chehab default: goto fail;
3130c0d06caSMauro Carvalho Chehab }
3140c0d06caSMauro Carvalho Chehab } else if (wlen == 2) {
3150c0d06caSMauro Carvalho Chehab subaddr = (wdata[0] << 8) | wdata[1];
3160c0d06caSMauro Carvalho Chehab switch (subaddr) {
3170c0d06caSMauro Carvalho Chehab case 0x0100: state = 1; break;
3180c0d06caSMauro Carvalho Chehab case 0x0101: state = 2; break;
3190c0d06caSMauro Carvalho Chehab default: goto fail;
3200c0d06caSMauro Carvalho Chehab }
3210c0d06caSMauro Carvalho Chehab } else {
3220c0d06caSMauro Carvalho Chehab goto fail;
3230c0d06caSMauro Carvalho Chehab }
3240c0d06caSMauro Carvalho Chehab if (!rlen) goto success;
3250c0d06caSMauro Carvalho Chehab state = 0;
3260c0d06caSMauro Carvalho Chehab if (rlen != 1) goto fail;
3270c0d06caSMauro Carvalho Chehab
3280c0d06caSMauro Carvalho Chehab /* If we get to here then we have a legitimate read for one of the
3290c0d06caSMauro Carvalho Chehab two revision bytes, so pass it through. */
3300c0d06caSMauro Carvalho Chehab wbuf[0] = subaddr >> 8;
3310c0d06caSMauro Carvalho Chehab wbuf[1] = subaddr;
3320c0d06caSMauro Carvalho Chehab ret = pvr2_i2c_basic_op(hdw,i2c_addr,wbuf,2,rdata,rlen);
3330c0d06caSMauro Carvalho Chehab
3340c0d06caSMauro Carvalho Chehab if ((ret != 0) || (*rdata == 0x04) || (*rdata == 0x0a)) {
3350c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_ERROR_LEGS,
3361753c7c4SAndrey Konovalov "***WARNING*** Detected a wedged cx25840 chip; the device will not work.");
3370c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_ERROR_LEGS,
3381753c7c4SAndrey Konovalov "***WARNING*** Try power cycling the pvrusb2 device.");
3390c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_ERROR_LEGS,
3401753c7c4SAndrey Konovalov "***WARNING*** Disabling further access to the device to prevent other foul-ups.");
3410c0d06caSMauro Carvalho Chehab // This blocks all further communication with the part.
3420c0d06caSMauro Carvalho Chehab hdw->i2c_func[0x44] = NULL;
3430c0d06caSMauro Carvalho Chehab pvr2_hdw_render_useless(hdw);
3440c0d06caSMauro Carvalho Chehab goto fail;
3450c0d06caSMauro Carvalho Chehab }
3460c0d06caSMauro Carvalho Chehab
3470c0d06caSMauro Carvalho Chehab /* Success! */
3480c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_CHIPS,"cx25840 appears to be OK.");
3490c0d06caSMauro Carvalho Chehab state = 3;
3500c0d06caSMauro Carvalho Chehab
3510c0d06caSMauro Carvalho Chehab success:
3520c0d06caSMauro Carvalho Chehab hdw->i2c_cx25840_hack_state = state;
3530c0d06caSMauro Carvalho Chehab return 0;
3540c0d06caSMauro Carvalho Chehab
3550c0d06caSMauro Carvalho Chehab fail:
3560c0d06caSMauro Carvalho Chehab hdw->i2c_cx25840_hack_state = state;
3570c0d06caSMauro Carvalho Chehab return -EIO;
3580c0d06caSMauro Carvalho Chehab }
3590c0d06caSMauro Carvalho Chehab
3600c0d06caSMauro Carvalho Chehab /* This is a very, very limited I2C adapter implementation. We can only
3610c0d06caSMauro Carvalho Chehab support what we actually know will work on the device... */
pvr2_i2c_xfer(struct i2c_adapter * i2c_adap,struct i2c_msg msgs[],int num)3620c0d06caSMauro Carvalho Chehab static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap,
3630c0d06caSMauro Carvalho Chehab struct i2c_msg msgs[],
3640c0d06caSMauro Carvalho Chehab int num)
3650c0d06caSMauro Carvalho Chehab {
3660c0d06caSMauro Carvalho Chehab int ret = -ENOTSUPP;
3670c0d06caSMauro Carvalho Chehab pvr2_i2c_func funcp = NULL;
3680c0d06caSMauro Carvalho Chehab struct pvr2_hdw *hdw = (struct pvr2_hdw *)(i2c_adap->algo_data);
3690c0d06caSMauro Carvalho Chehab
3700c0d06caSMauro Carvalho Chehab if (!num) {
3710c0d06caSMauro Carvalho Chehab ret = -EINVAL;
3720c0d06caSMauro Carvalho Chehab goto done;
3730c0d06caSMauro Carvalho Chehab }
3740c0d06caSMauro Carvalho Chehab if (msgs[0].addr < PVR2_I2C_FUNC_CNT) {
3750c0d06caSMauro Carvalho Chehab funcp = hdw->i2c_func[msgs[0].addr];
3760c0d06caSMauro Carvalho Chehab }
3770c0d06caSMauro Carvalho Chehab if (!funcp) {
3780c0d06caSMauro Carvalho Chehab ret = -EIO;
3790c0d06caSMauro Carvalho Chehab goto done;
3800c0d06caSMauro Carvalho Chehab }
3810c0d06caSMauro Carvalho Chehab
3820c0d06caSMauro Carvalho Chehab if (num == 1) {
3830c0d06caSMauro Carvalho Chehab if (msgs[0].flags & I2C_M_RD) {
3840c0d06caSMauro Carvalho Chehab /* Simple read */
3850c0d06caSMauro Carvalho Chehab u16 tcnt,bcnt,offs;
3860c0d06caSMauro Carvalho Chehab if (!msgs[0].len) {
3870c0d06caSMauro Carvalho Chehab /* Length == 0 read. This is a probe. */
3880c0d06caSMauro Carvalho Chehab if (funcp(hdw,msgs[0].addr,NULL,0,NULL,0)) {
3890c0d06caSMauro Carvalho Chehab ret = -EIO;
3900c0d06caSMauro Carvalho Chehab goto done;
3910c0d06caSMauro Carvalho Chehab }
3920c0d06caSMauro Carvalho Chehab ret = 1;
3930c0d06caSMauro Carvalho Chehab goto done;
3940c0d06caSMauro Carvalho Chehab }
3950c0d06caSMauro Carvalho Chehab /* If the read is short enough we'll do the whole
3960c0d06caSMauro Carvalho Chehab thing atomically. Otherwise we have no choice
3970c0d06caSMauro Carvalho Chehab but to break apart the reads. */
3980c0d06caSMauro Carvalho Chehab tcnt = msgs[0].len;
3990c0d06caSMauro Carvalho Chehab offs = 0;
4000c0d06caSMauro Carvalho Chehab while (tcnt) {
4010c0d06caSMauro Carvalho Chehab bcnt = tcnt;
4020c0d06caSMauro Carvalho Chehab if (bcnt > sizeof(hdw->cmd_buffer)-1) {
4030c0d06caSMauro Carvalho Chehab bcnt = sizeof(hdw->cmd_buffer)-1;
4040c0d06caSMauro Carvalho Chehab }
4050c0d06caSMauro Carvalho Chehab if (funcp(hdw,msgs[0].addr,NULL,0,
4060c0d06caSMauro Carvalho Chehab msgs[0].buf+offs,bcnt)) {
4070c0d06caSMauro Carvalho Chehab ret = -EIO;
4080c0d06caSMauro Carvalho Chehab goto done;
4090c0d06caSMauro Carvalho Chehab }
4100c0d06caSMauro Carvalho Chehab offs += bcnt;
4110c0d06caSMauro Carvalho Chehab tcnt -= bcnt;
4120c0d06caSMauro Carvalho Chehab }
4130c0d06caSMauro Carvalho Chehab ret = 1;
4140c0d06caSMauro Carvalho Chehab goto done;
4150c0d06caSMauro Carvalho Chehab } else {
4160c0d06caSMauro Carvalho Chehab /* Simple write */
4170c0d06caSMauro Carvalho Chehab ret = 1;
4180c0d06caSMauro Carvalho Chehab if (funcp(hdw,msgs[0].addr,
4190c0d06caSMauro Carvalho Chehab msgs[0].buf,msgs[0].len,NULL,0)) {
4200c0d06caSMauro Carvalho Chehab ret = -EIO;
4210c0d06caSMauro Carvalho Chehab }
4220c0d06caSMauro Carvalho Chehab goto done;
4230c0d06caSMauro Carvalho Chehab }
4240c0d06caSMauro Carvalho Chehab } else if (num == 2) {
4250c0d06caSMauro Carvalho Chehab if (msgs[0].addr != msgs[1].addr) {
42696292c89SMauro Carvalho Chehab trace_i2c("i2c refusing 2 phase transfer with conflicting target addresses");
4270c0d06caSMauro Carvalho Chehab ret = -ENOTSUPP;
4280c0d06caSMauro Carvalho Chehab goto done;
4290c0d06caSMauro Carvalho Chehab }
4300c0d06caSMauro Carvalho Chehab if ((!((msgs[0].flags & I2C_M_RD))) &&
4310c0d06caSMauro Carvalho Chehab (msgs[1].flags & I2C_M_RD)) {
4320c0d06caSMauro Carvalho Chehab u16 tcnt,bcnt,wcnt,offs;
4330c0d06caSMauro Carvalho Chehab /* Write followed by atomic read. If the read
4340c0d06caSMauro Carvalho Chehab portion is short enough we'll do the whole thing
4350c0d06caSMauro Carvalho Chehab atomically. Otherwise we have no choice but to
4360c0d06caSMauro Carvalho Chehab break apart the reads. */
4370c0d06caSMauro Carvalho Chehab tcnt = msgs[1].len;
4380c0d06caSMauro Carvalho Chehab wcnt = msgs[0].len;
4390c0d06caSMauro Carvalho Chehab offs = 0;
4400c0d06caSMauro Carvalho Chehab while (tcnt || wcnt) {
4410c0d06caSMauro Carvalho Chehab bcnt = tcnt;
4420c0d06caSMauro Carvalho Chehab if (bcnt > sizeof(hdw->cmd_buffer)-1) {
4430c0d06caSMauro Carvalho Chehab bcnt = sizeof(hdw->cmd_buffer)-1;
4440c0d06caSMauro Carvalho Chehab }
4450c0d06caSMauro Carvalho Chehab if (funcp(hdw,msgs[0].addr,
4460c0d06caSMauro Carvalho Chehab msgs[0].buf,wcnt,
4470c0d06caSMauro Carvalho Chehab msgs[1].buf+offs,bcnt)) {
4480c0d06caSMauro Carvalho Chehab ret = -EIO;
4490c0d06caSMauro Carvalho Chehab goto done;
4500c0d06caSMauro Carvalho Chehab }
4510c0d06caSMauro Carvalho Chehab offs += bcnt;
4520c0d06caSMauro Carvalho Chehab tcnt -= bcnt;
4530c0d06caSMauro Carvalho Chehab wcnt = 0;
4540c0d06caSMauro Carvalho Chehab }
4550c0d06caSMauro Carvalho Chehab ret = 2;
4560c0d06caSMauro Carvalho Chehab goto done;
4570c0d06caSMauro Carvalho Chehab } else {
45896292c89SMauro Carvalho Chehab trace_i2c("i2c refusing complex transfer read0=%d read1=%d",
4590c0d06caSMauro Carvalho Chehab (msgs[0].flags & I2C_M_RD),
4600c0d06caSMauro Carvalho Chehab (msgs[1].flags & I2C_M_RD));
4610c0d06caSMauro Carvalho Chehab }
4620c0d06caSMauro Carvalho Chehab } else {
4630c0d06caSMauro Carvalho Chehab trace_i2c("i2c refusing %d phase transfer",num);
4640c0d06caSMauro Carvalho Chehab }
4650c0d06caSMauro Carvalho Chehab
4660c0d06caSMauro Carvalho Chehab done:
4670c0d06caSMauro Carvalho Chehab if (pvrusb2_debug & PVR2_TRACE_I2C_TRAF) {
4680c0d06caSMauro Carvalho Chehab unsigned int idx,offs,cnt;
4690c0d06caSMauro Carvalho Chehab for (idx = 0; idx < num; idx++) {
4700c0d06caSMauro Carvalho Chehab cnt = msgs[idx].len;
4718f845c63SDafna Hirschfeld pr_info("pvrusb2 i2c xfer %u/%u: addr=0x%x len=%d %s",
4720c0d06caSMauro Carvalho Chehab idx+1,num,
4730c0d06caSMauro Carvalho Chehab msgs[idx].addr,
4740c0d06caSMauro Carvalho Chehab cnt,
4750c0d06caSMauro Carvalho Chehab (msgs[idx].flags & I2C_M_RD ?
4760c0d06caSMauro Carvalho Chehab "read" : "write"));
4770c0d06caSMauro Carvalho Chehab if ((ret > 0) || !(msgs[idx].flags & I2C_M_RD)) {
4780c0d06caSMauro Carvalho Chehab if (cnt > 8) cnt = 8;
4798f845c63SDafna Hirschfeld pr_cont(" [");
48047b586f6SColin Ian King for (offs = 0; offs < cnt; offs++) {
4818f845c63SDafna Hirschfeld if (offs) pr_cont(" ");
4828f845c63SDafna Hirschfeld pr_cont("%02x", msgs[idx].buf[offs]);
4830c0d06caSMauro Carvalho Chehab }
4848f845c63SDafna Hirschfeld if (offs < cnt) pr_cont(" ...");
4858f845c63SDafna Hirschfeld pr_cont("]");
4860c0d06caSMauro Carvalho Chehab }
4870c0d06caSMauro Carvalho Chehab if (idx+1 == num) {
4888f845c63SDafna Hirschfeld pr_cont(" result=%d", ret);
4890c0d06caSMauro Carvalho Chehab }
4908f845c63SDafna Hirschfeld pr_cont("\n");
4910c0d06caSMauro Carvalho Chehab }
4920c0d06caSMauro Carvalho Chehab if (!num) {
4938f845c63SDafna Hirschfeld pr_info("pvrusb2 i2c xfer null transfer result=%d\n",
4940c0d06caSMauro Carvalho Chehab ret);
4950c0d06caSMauro Carvalho Chehab }
4960c0d06caSMauro Carvalho Chehab }
4970c0d06caSMauro Carvalho Chehab return ret;
4980c0d06caSMauro Carvalho Chehab }
4990c0d06caSMauro Carvalho Chehab
pvr2_i2c_functionality(struct i2c_adapter * adap)5000c0d06caSMauro Carvalho Chehab static u32 pvr2_i2c_functionality(struct i2c_adapter *adap)
5010c0d06caSMauro Carvalho Chehab {
5020c0d06caSMauro Carvalho Chehab return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
5030c0d06caSMauro Carvalho Chehab }
5040c0d06caSMauro Carvalho Chehab
505d746cf89SBhumika Goyal static const struct i2c_algorithm pvr2_i2c_algo_template = {
5060c0d06caSMauro Carvalho Chehab .master_xfer = pvr2_i2c_xfer,
5070c0d06caSMauro Carvalho Chehab .functionality = pvr2_i2c_functionality,
5080c0d06caSMauro Carvalho Chehab };
5090c0d06caSMauro Carvalho Chehab
5106843868fSBhumika Goyal static const struct i2c_adapter pvr2_i2c_adap_template = {
5110c0d06caSMauro Carvalho Chehab .owner = THIS_MODULE,
5120c0d06caSMauro Carvalho Chehab .class = 0,
5130c0d06caSMauro Carvalho Chehab };
5140c0d06caSMauro Carvalho Chehab
5150c0d06caSMauro Carvalho Chehab
5160c0d06caSMauro Carvalho Chehab /* Return true if device exists at given address */
do_i2c_probe(struct pvr2_hdw * hdw,int addr)5170c0d06caSMauro Carvalho Chehab static int do_i2c_probe(struct pvr2_hdw *hdw, int addr)
5180c0d06caSMauro Carvalho Chehab {
5190c0d06caSMauro Carvalho Chehab struct i2c_msg msg[1];
5200c0d06caSMauro Carvalho Chehab int rc;
5210c0d06caSMauro Carvalho Chehab msg[0].addr = 0;
5220c0d06caSMauro Carvalho Chehab msg[0].flags = I2C_M_RD;
5230c0d06caSMauro Carvalho Chehab msg[0].len = 0;
5240c0d06caSMauro Carvalho Chehab msg[0].buf = NULL;
5250c0d06caSMauro Carvalho Chehab msg[0].addr = addr;
5260c0d06caSMauro Carvalho Chehab rc = i2c_transfer(&hdw->i2c_adap, msg, ARRAY_SIZE(msg));
5270c0d06caSMauro Carvalho Chehab return rc == 1;
5280c0d06caSMauro Carvalho Chehab }
5290c0d06caSMauro Carvalho Chehab
do_i2c_scan(struct pvr2_hdw * hdw)5300c0d06caSMauro Carvalho Chehab static void do_i2c_scan(struct pvr2_hdw *hdw)
5310c0d06caSMauro Carvalho Chehab {
5320c0d06caSMauro Carvalho Chehab int i;
5338f845c63SDafna Hirschfeld pr_info("%s: i2c scan beginning\n", hdw->name);
5340c0d06caSMauro Carvalho Chehab for (i = 0; i < 128; i++) {
5350c0d06caSMauro Carvalho Chehab if (do_i2c_probe(hdw, i)) {
5368f845c63SDafna Hirschfeld pr_info("%s: i2c scan: found device @ 0x%x\n",
5370c0d06caSMauro Carvalho Chehab hdw->name, i);
5380c0d06caSMauro Carvalho Chehab }
5390c0d06caSMauro Carvalho Chehab }
5408f845c63SDafna Hirschfeld pr_info("%s: i2c scan done.\n", hdw->name);
5410c0d06caSMauro Carvalho Chehab }
5420c0d06caSMauro Carvalho Chehab
pvr2_i2c_register_ir(struct pvr2_hdw * hdw)5430c0d06caSMauro Carvalho Chehab static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw)
5440c0d06caSMauro Carvalho Chehab {
5450c0d06caSMauro Carvalho Chehab struct i2c_board_info info;
5460c0d06caSMauro Carvalho Chehab struct IR_i2c_init_data *init_data = &hdw->ir_init_data;
5470c0d06caSMauro Carvalho Chehab if (pvr2_disable_ir_video) {
5480c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_INFO,
5490c0d06caSMauro Carvalho Chehab "Automatic binding of ir_video has been disabled.");
5500c0d06caSMauro Carvalho Chehab return;
5510c0d06caSMauro Carvalho Chehab }
5520c0d06caSMauro Carvalho Chehab memset(&info, 0, sizeof(struct i2c_board_info));
5530c0d06caSMauro Carvalho Chehab switch (hdw->ir_scheme_active) {
5540c0d06caSMauro Carvalho Chehab case PVR2_IR_SCHEME_24XXX: /* FX2-controlled IR */
5550c0d06caSMauro Carvalho Chehab case PVR2_IR_SCHEME_29XXX: /* Original 29xxx device */
5560c0d06caSMauro Carvalho Chehab init_data->ir_codes = RC_MAP_HAUPPAUGE;
5570c0d06caSMauro Carvalho Chehab init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP;
5586d741bfeSSean Young init_data->type = RC_PROTO_BIT_RC5;
5590c0d06caSMauro Carvalho Chehab init_data->name = hdw->hdw_desc->description;
5600c0d06caSMauro Carvalho Chehab init_data->polling_interval = 100; /* ms From ir-kbd-i2c */
5610c0d06caSMauro Carvalho Chehab /* IR Receiver */
5620c0d06caSMauro Carvalho Chehab info.addr = 0x18;
5630c0d06caSMauro Carvalho Chehab info.platform_data = init_data;
564c0decac1SMauro Carvalho Chehab strscpy(info.type, "ir_video", I2C_NAME_SIZE);
5650c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_INFO, "Binding %s to i2c address 0x%02x.",
5660c0d06caSMauro Carvalho Chehab info.type, info.addr);
567*479ce8f5SWolfram Sang i2c_new_client_device(&hdw->i2c_adap, &info);
5680c0d06caSMauro Carvalho Chehab break;
5690c0d06caSMauro Carvalho Chehab case PVR2_IR_SCHEME_ZILOG: /* HVR-1950 style */
5700c0d06caSMauro Carvalho Chehab case PVR2_IR_SCHEME_24XXX_MCE: /* 24xxx MCE device */
5710c0d06caSMauro Carvalho Chehab init_data->ir_codes = RC_MAP_HAUPPAUGE;
5720c0d06caSMauro Carvalho Chehab init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
5736d741bfeSSean Young init_data->type = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_MCE |
5746d741bfeSSean Young RC_PROTO_BIT_RC6_6A_32;
5750c0d06caSMauro Carvalho Chehab init_data->name = hdw->hdw_desc->description;
576ab5222edSSean Young /* IR Transceiver */
5770c0d06caSMauro Carvalho Chehab info.addr = 0x71;
5780c0d06caSMauro Carvalho Chehab info.platform_data = init_data;
579c0decac1SMauro Carvalho Chehab strscpy(info.type, "ir_z8f0811_haup", I2C_NAME_SIZE);
5800c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_INFO, "Binding %s to i2c address 0x%02x.",
5810c0d06caSMauro Carvalho Chehab info.type, info.addr);
582*479ce8f5SWolfram Sang i2c_new_client_device(&hdw->i2c_adap, &info);
5830c0d06caSMauro Carvalho Chehab break;
5840c0d06caSMauro Carvalho Chehab default:
5850c0d06caSMauro Carvalho Chehab /* The device either doesn't support I2C-based IR or we
5860c0d06caSMauro Carvalho Chehab don't know (yet) how to operate IR on the device. */
5870c0d06caSMauro Carvalho Chehab break;
5880c0d06caSMauro Carvalho Chehab }
5890c0d06caSMauro Carvalho Chehab }
5900c0d06caSMauro Carvalho Chehab
pvr2_i2c_core_init(struct pvr2_hdw * hdw)5910c0d06caSMauro Carvalho Chehab void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
5920c0d06caSMauro Carvalho Chehab {
5930c0d06caSMauro Carvalho Chehab unsigned int idx;
5940c0d06caSMauro Carvalho Chehab
5950c0d06caSMauro Carvalho Chehab /* The default action for all possible I2C addresses is just to do
5960c0d06caSMauro Carvalho Chehab the transfer normally. */
5970c0d06caSMauro Carvalho Chehab for (idx = 0; idx < PVR2_I2C_FUNC_CNT; idx++) {
5980c0d06caSMauro Carvalho Chehab hdw->i2c_func[idx] = pvr2_i2c_basic_op;
5990c0d06caSMauro Carvalho Chehab }
6000c0d06caSMauro Carvalho Chehab
6010c0d06caSMauro Carvalho Chehab /* However, deal with various special cases for 24xxx hardware. */
6020c0d06caSMauro Carvalho Chehab if (ir_mode[hdw->unit_number] == 0) {
6038f845c63SDafna Hirschfeld pr_info("%s: IR disabled\n", hdw->name);
6040c0d06caSMauro Carvalho Chehab hdw->i2c_func[0x18] = i2c_black_hole;
6050c0d06caSMauro Carvalho Chehab } else if (ir_mode[hdw->unit_number] == 1) {
6060c0d06caSMauro Carvalho Chehab if (hdw->ir_scheme_active == PVR2_IR_SCHEME_24XXX) {
6070c0d06caSMauro Carvalho Chehab /* Set up translation so that our IR looks like a
6080c0d06caSMauro Carvalho Chehab 29xxx device */
6090c0d06caSMauro Carvalho Chehab hdw->i2c_func[0x18] = i2c_24xxx_ir;
6100c0d06caSMauro Carvalho Chehab }
6110c0d06caSMauro Carvalho Chehab }
6120c0d06caSMauro Carvalho Chehab if (hdw->hdw_desc->flag_has_cx25840) {
6130c0d06caSMauro Carvalho Chehab hdw->i2c_func[0x44] = i2c_hack_cx25840;
6140c0d06caSMauro Carvalho Chehab }
6150c0d06caSMauro Carvalho Chehab if (hdw->hdw_desc->flag_has_wm8775) {
6160c0d06caSMauro Carvalho Chehab hdw->i2c_func[0x1b] = i2c_hack_wm8775;
6170c0d06caSMauro Carvalho Chehab }
6180c0d06caSMauro Carvalho Chehab
6190c0d06caSMauro Carvalho Chehab // Configure the adapter and set up everything else related to it.
6205338c169SEzequiel Garcia hdw->i2c_adap = pvr2_i2c_adap_template;
6215338c169SEzequiel Garcia hdw->i2c_algo = pvr2_i2c_algo_template;
622c0decac1SMauro Carvalho Chehab strscpy(hdw->i2c_adap.name, hdw->name, sizeof(hdw->i2c_adap.name));
6230c0d06caSMauro Carvalho Chehab hdw->i2c_adap.dev.parent = &hdw->usb_dev->dev;
6240c0d06caSMauro Carvalho Chehab hdw->i2c_adap.algo = &hdw->i2c_algo;
6250c0d06caSMauro Carvalho Chehab hdw->i2c_adap.algo_data = hdw;
6260c0d06caSMauro Carvalho Chehab hdw->i2c_linked = !0;
6270c0d06caSMauro Carvalho Chehab i2c_set_adapdata(&hdw->i2c_adap, &hdw->v4l2_dev);
6280c0d06caSMauro Carvalho Chehab i2c_add_adapter(&hdw->i2c_adap);
6290c0d06caSMauro Carvalho Chehab if (hdw->i2c_func[0x18] == i2c_24xxx_ir) {
6300c0d06caSMauro Carvalho Chehab /* Probe for a different type of IR receiver on this
6310c0d06caSMauro Carvalho Chehab device. This is really the only way to differentiate
6320c0d06caSMauro Carvalho Chehab older 24xxx devices from 24xxx variants that include an
6330c0d06caSMauro Carvalho Chehab IR blaster. If the IR blaster is present, the IR
6340c0d06caSMauro Carvalho Chehab receiver is part of that chip and thus we must disable
6350c0d06caSMauro Carvalho Chehab the emulated IR receiver. */
6360c0d06caSMauro Carvalho Chehab if (do_i2c_probe(hdw, 0x71)) {
6370c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_INFO,
63896292c89SMauro Carvalho Chehab "Device has newer IR hardware; disabling unneeded virtual IR device");
6390c0d06caSMauro Carvalho Chehab hdw->i2c_func[0x18] = NULL;
6400c0d06caSMauro Carvalho Chehab /* Remember that this is a different device... */
6410c0d06caSMauro Carvalho Chehab hdw->ir_scheme_active = PVR2_IR_SCHEME_24XXX_MCE;
6420c0d06caSMauro Carvalho Chehab }
6430c0d06caSMauro Carvalho Chehab }
6440c0d06caSMauro Carvalho Chehab if (i2c_scan) do_i2c_scan(hdw);
6450c0d06caSMauro Carvalho Chehab
6460c0d06caSMauro Carvalho Chehab pvr2_i2c_register_ir(hdw);
6470c0d06caSMauro Carvalho Chehab }
6480c0d06caSMauro Carvalho Chehab
pvr2_i2c_core_done(struct pvr2_hdw * hdw)6490c0d06caSMauro Carvalho Chehab void pvr2_i2c_core_done(struct pvr2_hdw *hdw)
6500c0d06caSMauro Carvalho Chehab {
6510c0d06caSMauro Carvalho Chehab if (hdw->i2c_linked) {
6520c0d06caSMauro Carvalho Chehab i2c_del_adapter(&hdw->i2c_adap);
6530c0d06caSMauro Carvalho Chehab hdw->i2c_linked = 0;
6540c0d06caSMauro Carvalho Chehab }
6550c0d06caSMauro Carvalho Chehab }
656