diff options
-rw-r--r-- | drivers/media/video/cs53l32a.c | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c new file mode 100644 index 000000000000..7434e5e66d59 --- /dev/null +++ b/drivers/media/video/cs53l32a.c | |||
@@ -0,0 +1,234 @@ | |||
1 | /* | ||
2 | * cs53l32a (Adaptec AVC-2010 and AVC-2410) i2c ivtv driver. | ||
3 | * Copyright (C) 2005 Martin Vaughan | ||
4 | * | ||
5 | * Audio source switching for Adaptec AVC-2410 added by Trev Jackson | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
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/videodev.h> | ||
29 | #include <media/audiochip.h> | ||
30 | #include <media/id.h> | ||
31 | |||
32 | MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC"); | ||
33 | MODULE_AUTHOR("Martin Vaughan"); | ||
34 | MODULE_LICENSE("GPL"); | ||
35 | |||
36 | static int debug = 0; | ||
37 | |||
38 | module_param(debug, bool, 0644); | ||
39 | |||
40 | MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On"); | ||
41 | |||
42 | #define cs53l32a_dbg(fmt, arg...) \ | ||
43 | do { \ | ||
44 | if (debug) \ | ||
45 | printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \ | ||
46 | i2c_adapter_id(client->adapter), client->addr , ## arg); \ | ||
47 | } while (0) | ||
48 | |||
49 | #define cs53l32a_err(fmt, arg...) do { \ | ||
50 | printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \ | ||
51 | i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) | ||
52 | #define cs53l32a_info(fmt, arg...) do { \ | ||
53 | printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \ | ||
54 | i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) | ||
55 | |||
56 | static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END }; | ||
57 | |||
58 | |||
59 | I2C_CLIENT_INSMOD; | ||
60 | |||
61 | /* ----------------------------------------------------------------------- */ | ||
62 | |||
63 | static int cs53l32a_write(struct i2c_client *client, u8 reg, u8 value) | ||
64 | { | ||
65 | return i2c_smbus_write_byte_data(client, reg, value); | ||
66 | } | ||
67 | |||
68 | static int cs53l32a_read(struct i2c_client *client, u8 reg) | ||
69 | { | ||
70 | return i2c_smbus_read_byte_data(client, reg); | ||
71 | } | ||
72 | |||
73 | static int cs53l32a_command(struct i2c_client *client, unsigned int cmd, | ||
74 | void *arg) | ||
75 | { | ||
76 | int *input = arg; | ||
77 | |||
78 | switch (cmd) { | ||
79 | case AUDC_SET_INPUT: | ||
80 | switch (*input) { | ||
81 | case AUDIO_TUNER: | ||
82 | cs53l32a_write(client, 0x01, 0x01); | ||
83 | break; | ||
84 | case AUDIO_EXTERN: | ||
85 | cs53l32a_write(client, 0x01, 0x21); | ||
86 | break; | ||
87 | case AUDIO_MUTE: | ||
88 | cs53l32a_write(client, 0x03, 0xF0); | ||
89 | break; | ||
90 | case AUDIO_UNMUTE: | ||
91 | cs53l32a_write(client, 0x03, 0x30); | ||
92 | break; | ||
93 | default: | ||
94 | cs53l32a_err("Invalid input %d.\n", *input); | ||
95 | return -EINVAL; | ||
96 | } | ||
97 | break; | ||
98 | |||
99 | case VIDIOC_S_CTRL: | ||
100 | { | ||
101 | struct v4l2_control *ctrl = arg; | ||
102 | |||
103 | if (ctrl->id != V4L2_CID_AUDIO_VOLUME) | ||
104 | return -EINVAL; | ||
105 | if (ctrl->value > 12 || ctrl->value < -90) | ||
106 | return -EINVAL; | ||
107 | cs53l32a_write(client, 0x04, (u8) ctrl->value); | ||
108 | cs53l32a_write(client, 0x05, (u8) ctrl->value); | ||
109 | break; | ||
110 | } | ||
111 | |||
112 | case VIDIOC_LOG_STATUS: | ||
113 | { | ||
114 | u8 v = cs53l32a_read(client, 0x01); | ||
115 | u8 m = cs53l32a_read(client, 0x03); | ||
116 | |||
117 | cs53l32a_info("Input: %s%s\n", | ||
118 | v == 0x21 ? "external line in" : "tuner", | ||
119 | (m & 0xC0) ? " (muted)" : ""); | ||
120 | break; | ||
121 | } | ||
122 | |||
123 | default: | ||
124 | return -EINVAL; | ||
125 | } | ||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | /* ----------------------------------------------------------------------- */ | ||
130 | |||
131 | /* i2c implementation */ | ||
132 | |||
133 | /* | ||
134 | * Generic i2c probe | ||
135 | * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' | ||
136 | */ | ||
137 | |||
138 | static struct i2c_driver i2c_driver; | ||
139 | |||
140 | static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind) | ||
141 | { | ||
142 | struct i2c_client *client; | ||
143 | int i; | ||
144 | |||
145 | /* Check if the adapter supports the needed features */ | ||
146 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
147 | return 0; | ||
148 | |||
149 | client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); | ||
150 | if (client == 0) | ||
151 | return -ENOMEM; | ||
152 | |||
153 | memset(client, 0, sizeof(struct i2c_client)); | ||
154 | client->addr = address; | ||
155 | client->adapter = adapter; | ||
156 | client->driver = &i2c_driver; | ||
157 | client->flags = I2C_CLIENT_ALLOW_USE; | ||
158 | snprintf(client->name, sizeof(client->name) - 1, "cs53l32a"); | ||
159 | |||
160 | cs53l32a_info("chip found @ 0x%x (%s)\n", address << 1, adapter->name); | ||
161 | |||
162 | for (i = 1; i <= 7; i++) { | ||
163 | u8 v = cs53l32a_read(client, i); | ||
164 | |||
165 | cs53l32a_dbg("Read Reg %d %02x\n", i, v); | ||
166 | } | ||
167 | |||
168 | /* Set cs53l32a internal register for Adaptec 2010/2410 setup */ | ||
169 | |||
170 | cs53l32a_write(client, 0x01, (u8) 0x21); | ||
171 | cs53l32a_write(client, 0x02, (u8) 0x29); | ||
172 | cs53l32a_write(client, 0x03, (u8) 0x30); | ||
173 | cs53l32a_write(client, 0x04, (u8) 0x00); | ||
174 | cs53l32a_write(client, 0x05, (u8) 0x00); | ||
175 | cs53l32a_write(client, 0x06, (u8) 0x00); | ||
176 | cs53l32a_write(client, 0x07, (u8) 0x00); | ||
177 | |||
178 | /* Display results, should be 0x21,0x29,0x30,0x00,0x00,0x00,0x00 */ | ||
179 | |||
180 | for (i = 1; i <= 7; i++) { | ||
181 | u8 v = cs53l32a_read(client, i); | ||
182 | |||
183 | cs53l32a_dbg("Read Reg %d %02x\n", i, v); | ||
184 | } | ||
185 | |||
186 | i2c_attach_client(client); | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | static int cs53l32a_probe(struct i2c_adapter *adapter) | ||
192 | { | ||
193 | return i2c_probe(adapter, &addr_data, cs53l32a_attach); | ||
194 | } | ||
195 | |||
196 | static int cs53l32a_detach(struct i2c_client *client) | ||
197 | { | ||
198 | int err; | ||
199 | |||
200 | err = i2c_detach_client(client); | ||
201 | if (err) { | ||
202 | return err; | ||
203 | } | ||
204 | kfree(client); | ||
205 | |||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | /* ----------------------------------------------------------------------- */ | ||
210 | |||
211 | /* i2c implementation */ | ||
212 | static struct i2c_driver i2c_driver = { | ||
213 | .name = "cs53l32a", | ||
214 | .id = I2C_DRIVERID_CS53L32A, | ||
215 | .flags = I2C_DF_NOTIFY, | ||
216 | .attach_adapter = cs53l32a_probe, | ||
217 | .detach_client = cs53l32a_detach, | ||
218 | .command = cs53l32a_command, | ||
219 | .owner = THIS_MODULE, | ||
220 | }; | ||
221 | |||
222 | |||
223 | static int __init cs53l32a_init_module(void) | ||
224 | { | ||
225 | return i2c_add_driver(&i2c_driver); | ||
226 | } | ||
227 | |||
228 | static void __exit cs53l32a_cleanup_module(void) | ||
229 | { | ||
230 | i2c_del_driver(&i2c_driver); | ||
231 | } | ||
232 | |||
233 | module_init(cs53l32a_init_module); | ||
234 | module_exit(cs53l32a_cleanup_module); | ||