aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx25840/cx25840-core.c
diff options
context:
space:
mode:
authorAndy Walls <awalls@md.metrocast.net>2010-07-18 21:08:03 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-08-08 22:42:55 -0400
commit52fd3dda130d03ae5c2bbdcbe81f6e083c051e12 (patch)
tree1b391a39d888314fe8ed3ac968a2384898938b3b /drivers/media/video/cx25840/cx25840-core.c
parent260e689ba237fb513b49e98841d98e93ea639c75 (diff)
V4L/DVB: cx25840: Add support for CX2388[57] A/V core integrated IR controllers
This patch is primarily a port of the integrated IR controller code in cx23885/cx23888-ir.c. Right now, only the CX2388[57] AV core will really try to set up IR. This IR support, by design, still requires the bridge driver to do final IO pin mux configuration and setup of the IR controller parameters. For the CX2388[578] chips, enabling the AV Core for IR also starts sending Audio and Video interrupts to the bridge driver. For CX2388[578] chips audio and video interrupts are ignored and acknowledged when they happen. IR interrupt handling and status logging is exluded for the CX23888 which does not have an IR controller on the AV core. Note that experimentation reveals that the IR irq enables on the CX23885 have an inverted logic sense. The CX23887 likely suffers from the same quirk. For these chips, those irq enable bits are handled as interrupt disables. Signed-off-by: Andy Walls <awalls@md.metrocast.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/cx25840/cx25840-core.c')
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c128
1 files changed, 128 insertions, 0 deletions
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 46a046d6405..9fab0b17084 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -15,6 +15,9 @@
15 * 15 *
16 * CX23885 support by Steven Toth <stoth@linuxtv.org>. 16 * CX23885 support by Steven Toth <stoth@linuxtv.org>.
17 * 17 *
18 * CX2388[578] IRQ handling, IO Pin mux configuration and other small fixes are
19 * Copyright (C) 2010 Andy Walls <awalls@md.metrocast.net>
20 *
18 * This program is free software; you can redistribute it and/or 21 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License 22 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation; either version 2 23 * as published by the Free Software Foundation; either version 2
@@ -48,6 +51,28 @@ MODULE_DESCRIPTION("Conexant CX25840 audio/video decoder driver");
48MODULE_AUTHOR("Ulf Eklund, Chris Kennedy, Hans Verkuil, Tyler Trafford"); 51MODULE_AUTHOR("Ulf Eklund, Chris Kennedy, Hans Verkuil, Tyler Trafford");
49MODULE_LICENSE("GPL"); 52MODULE_LICENSE("GPL");
50 53
54#define CX25840_VID_INT_STAT_REG 0x410
55#define CX25840_VID_INT_STAT_BITS 0x0000ffff
56#define CX25840_VID_INT_MASK_BITS 0xffff0000
57#define CX25840_VID_INT_MASK_SHFT 16
58#define CX25840_VID_INT_MASK_REG 0x412
59
60#define CX23885_AUD_MC_INT_MASK_REG 0x80c
61#define CX23885_AUD_MC_INT_STAT_BITS 0xffff0000
62#define CX23885_AUD_MC_INT_CTRL_BITS 0x0000ffff
63#define CX23885_AUD_MC_INT_STAT_SHFT 16
64
65#define CX25840_AUD_INT_CTRL_REG 0x812
66#define CX25840_AUD_INT_STAT_REG 0x813
67
68#define CX23885_PIN_CTRL_IRQ_REG 0x123
69#define CX23885_PIN_CTRL_IRQ_IR_STAT 0x40
70#define CX23885_PIN_CTRL_IRQ_AUD_STAT 0x20
71#define CX23885_PIN_CTRL_IRQ_VID_STAT 0x10
72
73#define CX25840_IR_STATS_REG 0x210
74#define CX25840_IR_IRQEN_REG 0x214
75
51static int cx25840_debug; 76static int cx25840_debug;
52 77
53module_param_named(debug,cx25840_debug, int, 0644); 78module_param_named(debug,cx25840_debug, int, 0644);
@@ -137,6 +162,14 @@ int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask,
137 or_value); 162 or_value);
138} 163}
139 164
165int cx25840_and_or4(struct i2c_client *client, u16 addr, u32 and_mask,
166 u32 or_value)
167{
168 return cx25840_write4(client, addr,
169 (cx25840_read4(client, addr) & and_mask) |
170 or_value);
171}
172
140/* ----------------------------------------------------------------------- */ 173/* ----------------------------------------------------------------------- */
141 174
142static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, 175static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
@@ -592,6 +625,13 @@ static void cx23885_initialize(struct i2c_client *client)
592 625
593 /* start microcontroller */ 626 /* start microcontroller */
594 cx25840_and_or(client, 0x803, ~0x10, 0x10); 627 cx25840_and_or(client, 0x803, ~0x10, 0x10);
628
629 /* Disable and clear video interrupts - we don't use them */
630 cx25840_write4(client, CX25840_VID_INT_STAT_REG, 0xffffffff);
631
632 /* Disable and clear audio interrupts - we don't use them */
633 cx25840_write(client, CX25840_AUD_INT_CTRL_REG, 0xff);
634 cx25840_write(client, CX25840_AUD_INT_STAT_REG, 0xff);
595} 635}
596 636
597/* ----------------------------------------------------------------------- */ 637/* ----------------------------------------------------------------------- */
@@ -1748,9 +1788,93 @@ static int cx25840_log_status(struct v4l2_subdev *sd)
1748 log_video_status(client); 1788 log_video_status(client);
1749 if (!is_cx2583x(state)) 1789 if (!is_cx2583x(state))
1750 log_audio_status(client); 1790 log_audio_status(client);
1791 cx25840_ir_log_status(sd);
1751 return 0; 1792 return 0;
1752} 1793}
1753 1794
1795static int cx23885_irq_handler(struct v4l2_subdev *sd, u32 status,
1796 bool *handled)
1797{
1798 struct cx25840_state *state = to_state(sd);
1799 struct i2c_client *c = v4l2_get_subdevdata(sd);
1800 u8 irq_stat, aud_stat, aud_en, ir_stat, ir_en;
1801 u32 vid_stat, aud_mc_stat;
1802 bool block_handled;
1803 int ret = 0;
1804
1805 irq_stat = cx25840_read(c, CX23885_PIN_CTRL_IRQ_REG);
1806 v4l_dbg(2, cx25840_debug, c, "AV Core IRQ status (entry): %s %s %s\n",
1807 irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT ? "ir" : " ",
1808 irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT ? "aud" : " ",
1809 irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT ? "vid" : " ");
1810
1811 if ((is_cx23885(state) || is_cx23887(state))) {
1812 ir_stat = cx25840_read(c, CX25840_IR_STATS_REG);
1813 ir_en = cx25840_read(c, CX25840_IR_IRQEN_REG);
1814 v4l_dbg(2, cx25840_debug, c,
1815 "AV Core ir IRQ status: %#04x disables: %#04x\n",
1816 ir_stat, ir_en);
1817 if (irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT) {
1818 block_handled = false;
1819 ret = cx25840_ir_irq_handler(sd,
1820 status, &block_handled);
1821 if (block_handled)
1822 *handled = true;
1823 }
1824 }
1825
1826 aud_stat = cx25840_read(c, CX25840_AUD_INT_STAT_REG);
1827 aud_en = cx25840_read(c, CX25840_AUD_INT_CTRL_REG);
1828 v4l_dbg(2, cx25840_debug, c,
1829 "AV Core audio IRQ status: %#04x disables: %#04x\n",
1830 aud_stat, aud_en);
1831 aud_mc_stat = cx25840_read4(c, CX23885_AUD_MC_INT_MASK_REG);
1832 v4l_dbg(2, cx25840_debug, c,
1833 "AV Core audio MC IRQ status: %#06x enables: %#06x\n",
1834 aud_mc_stat >> CX23885_AUD_MC_INT_STAT_SHFT,
1835 aud_mc_stat & CX23885_AUD_MC_INT_CTRL_BITS);
1836 if (irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT) {
1837 if (aud_stat) {
1838 cx25840_write(c, CX25840_AUD_INT_STAT_REG, aud_stat);
1839 *handled = true;
1840 }
1841 }
1842
1843 vid_stat = cx25840_read4(c, CX25840_VID_INT_STAT_REG);
1844 v4l_dbg(2, cx25840_debug, c,
1845 "AV Core video IRQ status: %#06x disables: %#06x\n",
1846 vid_stat & CX25840_VID_INT_STAT_BITS,
1847 vid_stat >> CX25840_VID_INT_MASK_SHFT);
1848 if (irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT) {
1849 if (vid_stat & CX25840_VID_INT_STAT_BITS) {
1850 cx25840_write4(c, CX25840_VID_INT_STAT_REG, vid_stat);
1851 *handled = true;
1852 }
1853 }
1854
1855 irq_stat = cx25840_read(c, CX23885_PIN_CTRL_IRQ_REG);
1856 v4l_dbg(2, cx25840_debug, c, "AV Core IRQ status (exit): %s %s %s\n",
1857 irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT ? "ir" : " ",
1858 irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT ? "aud" : " ",
1859 irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT ? "vid" : " ");
1860
1861 return ret;
1862}
1863
1864static int cx25840_irq_handler(struct v4l2_subdev *sd, u32 status,
1865 bool *handled)
1866{
1867 struct cx25840_state *state = to_state(sd);
1868
1869 *handled = false;
1870
1871 /* Only support the CX2388[578] AV Core for now */
1872 if (is_cx2388x(state))
1873 return cx23885_irq_handler(sd, status, handled);
1874
1875 return -ENODEV;
1876}
1877
1754/* ----------------------------------------------------------------------- */ 1878/* ----------------------------------------------------------------------- */
1755 1879
1756static const struct v4l2_subdev_core_ops cx25840_core_ops = { 1880static const struct v4l2_subdev_core_ops cx25840_core_ops = {
@@ -1767,6 +1891,7 @@ static const struct v4l2_subdev_core_ops cx25840_core_ops = {
1767 .g_register = cx25840_g_register, 1891 .g_register = cx25840_g_register,
1768 .s_register = cx25840_s_register, 1892 .s_register = cx25840_s_register,
1769#endif 1893#endif
1894 .interrupt_service_routine = cx25840_irq_handler,
1770}; 1895};
1771 1896
1772static const struct v4l2_subdev_tuner_ops cx25840_tuner_ops = { 1897static const struct v4l2_subdev_tuner_ops cx25840_tuner_ops = {
@@ -1801,6 +1926,7 @@ static const struct v4l2_subdev_ops cx25840_ops = {
1801 .audio = &cx25840_audio_ops, 1926 .audio = &cx25840_audio_ops,
1802 .video = &cx25840_video_ops, 1927 .video = &cx25840_video_ops,
1803 .vbi = &cx25840_vbi_ops, 1928 .vbi = &cx25840_vbi_ops,
1929 .ir = &cx25840_ir_ops,
1804}; 1930};
1805 1931
1806/* ----------------------------------------------------------------------- */ 1932/* ----------------------------------------------------------------------- */
@@ -1942,6 +2068,7 @@ static int cx25840_probe(struct i2c_client *client,
1942 state->id = id; 2068 state->id = id;
1943 state->rev = device_id; 2069 state->rev = device_id;
1944 2070
2071 cx25840_ir_probe(sd);
1945 return 0; 2072 return 0;
1946} 2073}
1947 2074
@@ -1949,6 +2076,7 @@ static int cx25840_remove(struct i2c_client *client)
1949{ 2076{
1950 struct v4l2_subdev *sd = i2c_get_clientdata(client); 2077 struct v4l2_subdev *sd = i2c_get_clientdata(client);
1951 2078
2079 cx25840_ir_remove(sd);
1952 v4l2_device_unregister_subdev(sd); 2080 v4l2_device_unregister_subdev(sd);
1953 kfree(to_state(sd)); 2081 kfree(to_state(sd));
1954 return 0; 2082 return 0;