diff options
Diffstat (limited to 'drivers/media/video/mxb.c')
| -rw-r--r-- | drivers/media/video/mxb.c | 872 |
1 files changed, 872 insertions, 0 deletions
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c new file mode 100644 index 00000000000..0b385002350 --- /dev/null +++ b/drivers/media/video/mxb.c | |||
| @@ -0,0 +1,872 @@ | |||
| 1 | /* | ||
| 2 | mxb - v4l2 driver for the Multimedia eXtension Board | ||
| 3 | |||
| 4 | Copyright (C) 1998-2006 Michael Hunold <michael@mihu.de> | ||
| 5 | |||
| 6 | Visit http://www.themm.net/~mihu/linux/saa7146/mxb.html | ||
| 7 | for further details about this card. | ||
| 8 | |||
| 9 | This program is free software; you can redistribute it and/or modify | ||
| 10 | it under the terms of the GNU General Public License as published by | ||
| 11 | the Free Software Foundation; either version 2 of the License, or | ||
| 12 | (at your option) any later version. | ||
| 13 | |||
| 14 | This program is distributed in the hope that it will be useful, | ||
| 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | GNU General Public License for more details. | ||
| 18 | |||
| 19 | You should have received a copy of the GNU General Public License | ||
| 20 | along with this program; if not, write to the Free Software | ||
| 21 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 22 | */ | ||
| 23 | |||
| 24 | #define DEBUG_VARIABLE debug | ||
| 25 | |||
| 26 | #include <media/saa7146_vv.h> | ||
| 27 | #include <media/tuner.h> | ||
| 28 | #include <media/v4l2-common.h> | ||
| 29 | #include <media/saa7115.h> | ||
| 30 | |||
| 31 | #include "mxb.h" | ||
| 32 | #include "tea6415c.h" | ||
| 33 | #include "tea6420.h" | ||
| 34 | |||
| 35 | #define I2C_SAA7111A 0x24 | ||
| 36 | #define I2C_TDA9840 0x42 | ||
| 37 | #define I2C_TEA6415C 0x43 | ||
| 38 | #define I2C_TEA6420_1 0x4c | ||
| 39 | #define I2C_TEA6420_2 0x4d | ||
| 40 | #define I2C_TUNER 0x60 | ||
| 41 | |||
| 42 | #define MXB_BOARD_CAN_DO_VBI(dev) (dev->revision != 0) | ||
| 43 | |||
| 44 | /* global variable */ | ||
| 45 | static int mxb_num; | ||
| 46 | |||
| 47 | /* initial frequence the tuner will be tuned to. | ||
| 48 | in verden (lower saxony, germany) 4148 is a | ||
| 49 | channel called "phoenix" */ | ||
| 50 | static int freq = 4148; | ||
| 51 | module_param(freq, int, 0644); | ||
| 52 | MODULE_PARM_DESC(freq, "initial frequency the tuner will be tuned to while setup"); | ||
| 53 | |||
| 54 | static int debug; | ||
| 55 | module_param(debug, int, 0644); | ||
| 56 | MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off)."); | ||
| 57 | |||
| 58 | #define MXB_INPUTS 4 | ||
| 59 | enum { TUNER, AUX1, AUX3, AUX3_YC }; | ||
| 60 | |||
| 61 | static struct v4l2_input mxb_inputs[MXB_INPUTS] = { | ||
| 62 | { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, | ||
| 63 | { AUX1, "AUX1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, | ||
| 64 | { AUX3, "AUX3 Composite", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, | ||
| 65 | { AUX3_YC, "AUX3 S-Video", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, | ||
| 66 | }; | ||
| 67 | |||
| 68 | /* this array holds the information, which port of the saa7146 each | ||
| 69 | input actually uses. the mxb uses port 0 for every input */ | ||
| 70 | static struct { | ||
| 71 | int hps_source; | ||
| 72 | int hps_sync; | ||
| 73 | } input_port_selection[MXB_INPUTS] = { | ||
| 74 | { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A }, | ||
| 75 | { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A }, | ||
| 76 | { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A }, | ||
| 77 | { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A }, | ||
| 78 | }; | ||
| 79 | |||
| 80 | /* this array holds the information of the audio source (mxb_audios), | ||
| 81 | which has to be switched corresponding to the video source (mxb_channels) */ | ||
| 82 | static int video_audio_connect[MXB_INPUTS] = | ||
| 83 | { 0, 1, 3, 3 }; | ||
| 84 | |||
| 85 | struct mxb_routing { | ||
| 86 | u32 input; | ||
| 87 | u32 output; | ||
| 88 | }; | ||
| 89 | |||
| 90 | /* These are the necessary input-output-pins for bringing one audio source | ||
| 91 | (see above) to the CD-output. Note that gain is set to 0 in this table. */ | ||
| 92 | static struct mxb_routing TEA6420_cd[MXB_AUDIOS + 1][2] = { | ||
| 93 | { { 1, 1 }, { 1, 1 } }, /* Tuner */ | ||
| 94 | { { 5, 1 }, { 6, 1 } }, /* AUX 1 */ | ||
| 95 | { { 4, 1 }, { 6, 1 } }, /* AUX 2 */ | ||
| 96 | { { 3, 1 }, { 6, 1 } }, /* AUX 3 */ | ||
| 97 | { { 1, 1 }, { 3, 1 } }, /* Radio */ | ||
| 98 | { { 1, 1 }, { 2, 1 } }, /* CD-Rom */ | ||
| 99 | { { 6, 1 }, { 6, 1 } } /* Mute */ | ||
| 100 | }; | ||
| 101 | |||
| 102 | /* These are the necessary input-output-pins for bringing one audio source | ||
| 103 | (see above) to the line-output. Note that gain is set to 0 in this table. */ | ||
| 104 | static struct mxb_routing TEA6420_line[MXB_AUDIOS + 1][2] = { | ||
| 105 | { { 2, 3 }, { 1, 2 } }, | ||
| 106 | { { 5, 3 }, { 6, 2 } }, | ||
| 107 | { { 4, 3 }, { 6, 2 } }, | ||
| 108 | { { 3, 3 }, { 6, 2 } }, | ||
| 109 | { { 2, 3 }, { 3, 2 } }, | ||
| 110 | { { 2, 3 }, { 2, 2 } }, | ||
| 111 | { { 6, 3 }, { 6, 2 } } /* Mute */ | ||
| 112 | }; | ||
| 113 | |||
| 114 | #define MAXCONTROLS 1 | ||
| 115 | static struct v4l2_queryctrl mxb_controls[] = { | ||
| 116 | { V4L2_CID_AUDIO_MUTE, V4L2_CTRL_TYPE_BOOLEAN, "Mute", 0, 1, 1, 0, 0 }, | ||
| 117 | }; | ||
| 118 | |||
| 119 | struct mxb | ||
| 120 | { | ||
| 121 | struct video_device *video_dev; | ||
| 122 | struct video_device *vbi_dev; | ||
| 123 | |||
| 124 | struct i2c_adapter i2c_adapter; | ||
| 125 | |||
| 126 | struct v4l2_subdev *saa7111a; | ||
| 127 | struct v4l2_subdev *tda9840; | ||
| 128 | struct v4l2_subdev *tea6415c; | ||
| 129 | struct v4l2_subdev *tuner; | ||
| 130 | struct v4l2_subdev *tea6420_1; | ||
| 131 | struct v4l2_subdev *tea6420_2; | ||
| 132 | |||
| 133 | int cur_mode; /* current audio mode (mono, stereo, ...) */ | ||
| 134 | int cur_input; /* current input */ | ||
| 135 | int cur_mute; /* current mute status */ | ||
| 136 | struct v4l2_frequency cur_freq; /* current frequency the tuner is tuned to */ | ||
| 137 | }; | ||
| 138 | |||
| 139 | #define saa7111a_call(mxb, o, f, args...) \ | ||
| 140 | v4l2_subdev_call(mxb->saa7111a, o, f, ##args) | ||
| 141 | #define tda9840_call(mxb, o, f, args...) \ | ||
| 142 | v4l2_subdev_call(mxb->tda9840, o, f, ##args) | ||
| 143 | #define tea6415c_call(mxb, o, f, args...) \ | ||
| 144 | v4l2_subdev_call(mxb->tea6415c, o, f, ##args) | ||
| 145 | #define tuner_call(mxb, o, f, args...) \ | ||
| 146 | v4l2_subdev_call(mxb->tuner, o, f, ##args) | ||
| 147 | #define call_all(dev, o, f, args...) \ | ||
| 148 | v4l2_device_call_until_err(&dev->v4l2_dev, 0, o, f, ##args) | ||
| 149 | |||
| 150 | static inline void tea6420_route_cd(struct mxb *mxb, int idx) | ||
| 151 | { | ||
| 152 | v4l2_subdev_call(mxb->tea6420_1, audio, s_routing, | ||
| 153 | TEA6420_cd[idx][0].input, TEA6420_cd[idx][0].output, 0); | ||
| 154 | v4l2_subdev_call(mxb->tea6420_2, audio, s_routing, | ||
| 155 | TEA6420_cd[idx][1].input, TEA6420_cd[idx][1].output, 0); | ||
| 156 | } | ||
| 157 | |||
| 158 | static inline void tea6420_route_line(struct mxb *mxb, int idx) | ||
| 159 | { | ||
| 160 | v4l2_subdev_call(mxb->tea6420_1, audio, s_routing, | ||
| 161 | TEA6420_line[idx][0].input, TEA6420_line[idx][0].output, 0); | ||
| 162 | v4l2_subdev_call(mxb->tea6420_2, audio, s_routing, | ||
| 163 | TEA6420_line[idx][1].input, TEA6420_line[idx][1].output, 0); | ||
| 164 | } | ||
| 165 | |||
| 166 | static struct saa7146_extension extension; | ||
| 167 | |||
| 168 | static int mxb_probe(struct saa7146_dev *dev) | ||
| 169 | { | ||
| 170 | struct mxb *mxb = NULL; | ||
| 171 | |||
| 172 | mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL); | ||
| 173 | if (mxb == NULL) { | ||
| 174 | DEB_D(("not enough kernel memory.\n")); | ||
| 175 | return -ENOMEM; | ||
| 176 | } | ||
| 177 | |||
| 178 | snprintf(mxb->i2c_adapter.name, sizeof(mxb->i2c_adapter.name), "mxb%d", mxb_num); | ||
| 179 | |||
| 180 | saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); | ||
| 181 | if (i2c_add_adapter(&mxb->i2c_adapter) < 0) { | ||
| 182 | DEB_S(("cannot register i2c-device. skipping.\n")); | ||
| 183 | kfree(mxb); | ||
| 184 | return -EFAULT; | ||
| 185 | } | ||
| 186 | |||
| 187 | mxb->saa7111a = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, | ||
| 188 | "saa7111", I2C_SAA7111A, NULL); | ||
| 189 | mxb->tea6420_1 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, | ||
| 190 | "tea6420", I2C_TEA6420_1, NULL); | ||
| 191 | mxb->tea6420_2 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, | ||
| 192 | "tea6420", I2C_TEA6420_2, NULL); | ||
| 193 | mxb->tea6415c = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, | ||
| 194 | "tea6415c", I2C_TEA6415C, NULL); | ||
| 195 | mxb->tda9840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, | ||
| 196 | "tda9840", I2C_TDA9840, NULL); | ||
| 197 | mxb->tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, | ||
| 198 | "tuner", I2C_TUNER, NULL); | ||
| 199 | |||
| 200 | /* check if all devices are present */ | ||
| 201 | if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c || | ||
| 202 | !mxb->tda9840 || !mxb->saa7111a || !mxb->tuner) { | ||
| 203 | printk("mxb: did not find all i2c devices. aborting\n"); | ||
| 204 | i2c_del_adapter(&mxb->i2c_adapter); | ||
| 205 | kfree(mxb); | ||
| 206 | return -ENODEV; | ||
| 207 | } | ||
| 208 | |||
| 209 | /* all devices are present, probe was successful */ | ||
| 210 | |||
| 211 | /* we store the pointer in our private data field */ | ||
| 212 | dev->ext_priv = mxb; | ||
| 213 | |||
| 214 | return 0; | ||
| 215 | } | ||
| 216 | |||
| 217 | /* some init data for the saa7740, the so-called 'sound arena module'. | ||
