]> err.no Git - linux-2.6/blob - drivers/media/video/vp27smpx.c
V4L/DVB (6003): vp27smpx: correctly attribute the origin of the driver
[linux-2.6] / drivers / media / video / vp27smpx.c
1 /*
2  * vp27smpx - driver version 0.0.1
3  *
4  * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
5  *
6  * Based on a tvaudio patch from Kazuhiko Kawakami <kazz-0@mail.goo.ne.jp>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22
23 #include <linux/module.h>
24 #include <linux/types.h>
25 #include <linux/ioctl.h>
26 #include <asm/uaccess.h>
27 #include <linux/i2c.h>
28 #include <linux/i2c-id.h>
29 #include <linux/videodev.h>
30 #include <media/v4l2-common.h>
31 #include <media/v4l2-chip-ident.h>
32
33 MODULE_DESCRIPTION("vp27smpx driver");
34 MODULE_AUTHOR("Hans Verkuil");
35 MODULE_LICENSE("GPL");
36
37 static unsigned short normal_i2c[] = { 0xb6 >> 1, I2C_CLIENT_END };
38
39
40 I2C_CLIENT_INSMOD;
41
42 /* ----------------------------------------------------------------------- */
43
44 struct vp27smpx_state {
45         int radio;
46         u32 audmode;
47 };
48
49 static void vp27smpx_set_audmode(struct i2c_client *client, u32 audmode)
50 {
51         struct vp27smpx_state *state = i2c_get_clientdata(client);
52         u8 data[3] = { 0x00, 0x00, 0x04 };
53
54         switch (audmode) {
55                 case V4L2_TUNER_MODE_MONO:
56                 case V4L2_TUNER_MODE_LANG1:
57                         break;
58                 case V4L2_TUNER_MODE_STEREO:
59                 case V4L2_TUNER_MODE_LANG1_LANG2:
60                         data[1] = 0x01;
61                         break;
62                 case V4L2_TUNER_MODE_LANG2:
63                         data[1] = 0x02;
64                         break;
65         }
66
67         if (i2c_master_send(client, data, sizeof(data)) != sizeof(data)) {
68                 v4l_err(client, "%s: I/O error setting audmode\n", client->name);
69         }
70         else {
71                 state->audmode = audmode;
72         }
73 }
74
75 static int vp27smpx_command(struct i2c_client *client, unsigned int cmd,
76                           void *arg)
77 {
78         struct vp27smpx_state *state = i2c_get_clientdata(client);
79         struct v4l2_tuner *vt = arg;
80
81         switch (cmd) {
82         case AUDC_SET_RADIO:
83                 state->radio = 1;
84                 break;
85
86         case VIDIOC_S_STD:
87                 state->radio = 0;
88                 break;
89
90         case VIDIOC_S_TUNER:
91                 if (!state->radio)
92                         vp27smpx_set_audmode(client, vt->audmode);
93                 break;
94
95         case VIDIOC_G_TUNER:
96                 if (state->radio)
97                         break;
98                 vt->audmode = state->audmode;
99                 vt->capability = V4L2_TUNER_CAP_STEREO |
100                         V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
101                 vt->rxsubchans = V4L2_TUNER_SUB_MONO;
102                 break;
103
104         case VIDIOC_G_CHIP_IDENT:
105                 return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_VP27SMPX, 0);
106
107         case VIDIOC_LOG_STATUS:
108                 v4l_info(client, "Audio Mode: %u%s\n", state->audmode,
109                                 state->radio ? " (Radio)" : "");
110                 break;
111
112         default:
113                 return -EINVAL;
114         }
115         return 0;
116 }
117
118 /* ----------------------------------------------------------------------- */
119
120 /* i2c implementation */
121
122 /*
123  * Generic i2c probe
124  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
125  */
126
127 static struct i2c_driver i2c_driver;
128
129 static int vp27smpx_attach(struct i2c_adapter *adapter, int address, int kind)
130 {
131         struct i2c_client *client;
132         struct vp27smpx_state *state;
133
134         /* Check if the adapter supports the needed features */
135         if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
136                 return 0;
137
138         client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
139         if (client == 0)
140                 return -ENOMEM;
141
142         client->addr = address;
143         client->adapter = adapter;
144         client->driver = &i2c_driver;
145         snprintf(client->name, sizeof(client->name) - 1, "vp27smpx");
146
147         v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
148
149         state = kzalloc(sizeof(struct vp27smpx_state), GFP_KERNEL);
150         if (state == NULL) {
151                 kfree(client);
152                 return -ENOMEM;
153         }
154         state->audmode = V4L2_TUNER_MODE_STEREO;
155         i2c_set_clientdata(client, state);
156
157         /* initialize vp27smpx */
158         vp27smpx_set_audmode(client, state->audmode);
159         i2c_attach_client(client);
160
161         return 0;
162 }
163
164 static int vp27smpx_probe(struct i2c_adapter *adapter)
165 {
166         if (adapter->class & I2C_CLASS_TV_ANALOG)
167                 return i2c_probe(adapter, &addr_data, vp27smpx_attach);
168         return 0;
169 }
170
171 static int vp27smpx_detach(struct i2c_client *client)
172 {
173         struct vp27smpx_state *state = i2c_get_clientdata(client);
174         int err;
175
176         err = i2c_detach_client(client);
177         if (err) {
178                 return err;
179         }
180         kfree(state);
181         kfree(client);
182
183         return 0;
184 }
185
186 /* ----------------------------------------------------------------------- */
187
188 /* i2c implementation */
189 static struct i2c_driver i2c_driver = {
190         .driver = {
191                 .name = "vp27smpx",
192         },
193         .id             = I2C_DRIVERID_VP27SMPX,
194         .attach_adapter = vp27smpx_probe,
195         .detach_client  = vp27smpx_detach,
196         .command        = vp27smpx_command,
197 };
198
199
200 static int __init vp27smpx_init_module(void)
201 {
202         return i2c_add_driver(&i2c_driver);
203 }
204
205 static void __exit vp27smpx_cleanup_module(void)
206 {
207         i2c_del_driver(&i2c_driver);
208 }
209
210 module_init(vp27smpx_init_module);
211 module_exit(vp27smpx_cleanup_module);