blob: 7d997aeda63eb1e56019e38d186e18563e411981 [file] [log] [blame]
Hans Verkuilf4067fd2005-11-08 21:37:55 -08001/*
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>
Hans Verkuile2998e12005-11-08 21:38:49 -080028#include <linux/i2c-id.h>
Hans Verkuilf4067fd2005-11-08 21:37:55 -080029#include <linux/videodev.h>
30#include <media/audiochip.h>
Hans Verkuilf4067fd2005-11-08 21:37:55 -080031
32MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
33MODULE_AUTHOR("Martin Vaughan");
34MODULE_LICENSE("GPL");
35
36static int debug = 0;
37
38module_param(debug, bool, 0644);
39
40MODULE_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) \
Laurent Riffard604f28e2005-11-26 20:43:39 +010045 printk(KERN_INFO "%s debug %d-%04x: " fmt, \
46 client->driver->driver.name, \
Hans Verkuilf4067fd2005-11-08 21:37:55 -080047 i2c_adapter_id(client->adapter), client->addr , ## arg); \
48 } while (0)
49
50#define cs53l32a_err(fmt, arg...) do { \
Laurent Riffard604f28e2005-11-26 20:43:39 +010051 printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \
Hans Verkuilf4067fd2005-11-08 21:37:55 -080052 i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
53#define cs53l32a_info(fmt, arg...) do { \
Laurent Riffard604f28e2005-11-26 20:43:39 +010054 printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \
Hans Verkuilf4067fd2005-11-08 21:37:55 -080055 i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
56
57static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
58
59
60I2C_CLIENT_INSMOD;
61
62/* ----------------------------------------------------------------------- */
63
64static int cs53l32a_write(struct i2c_client *client, u8 reg, u8 value)
65{
66 return i2c_smbus_write_byte_data(client, reg, value);
67}
68
69static int cs53l32a_read(struct i2c_client *client, u8 reg)
70{
71 return i2c_smbus_read_byte_data(client, reg);
72}
73
74static int cs53l32a_command(struct i2c_client *client, unsigned int cmd,
75 void *arg)
76{
Hans Verkuil93605352006-01-09 15:25:39 -020077 struct v4l2_audio *input = arg;
78 struct v4l2_control *ctrl = arg;
Hans Verkuilf4067fd2005-11-08 21:37:55 -080079
80 switch (cmd) {
Hans Verkuil93605352006-01-09 15:25:39 -020081 case VIDIOC_S_AUDIO:
82 /* There are 2 physical inputs, but the second input can be
83 placed in two modes, the first mode bypasses the PGA (gain),
84 the second goes through the PGA. Hence there are three
85 possible inputs to choose from. */
86 if (input->index > 2) {
87 cs53l32a_err("Invalid input %d.\n", input->index);
Hans Verkuilf4067fd2005-11-08 21:37:55 -080088 return -EINVAL;
89 }
Hans Verkuil93605352006-01-09 15:25:39 -020090 cs53l32a_write(client, 0x01, 0x01 + (input->index << 4));
91 break;
92
93 case VIDIOC_G_AUDIO:
94 memset(input, 0, sizeof(*input));
95 input->index = (cs53l32a_read(client, 0x01) >> 4) & 3;
96 break;
97
98 case VIDIOC_G_CTRL:
99 if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
100 ctrl->value = (cs53l32a_read(client, 0x03) & 0xc0) != 0;
101 break;
102 }
103 if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
104 return -EINVAL;
105 ctrl->value = (s8)cs53l32a_read(client, 0x04);
Hans Verkuilf4067fd2005-11-08 21:37:55 -0800106 break;
107
108 case VIDIOC_S_CTRL:
Hans Verkuil93605352006-01-09 15:25:39 -0200109 if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
110 cs53l32a_write(client, 0x03, ctrl->value ? 0xf0 : 0x30);
Hans Verkuilf4067fd2005-11-08 21:37:55 -0800111 break;
112 }
Hans Verkuil93605352006-01-09 15:25:39 -0200113 if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
114 return -EINVAL;
115 if (ctrl->value > 12 || ctrl->value < -96)
116 return -EINVAL;
117 cs53l32a_write(client, 0x04, (u8) ctrl->value);
118 cs53l32a_write(client, 0x05, (u8) ctrl->value);
119 break;
Hans Verkuilf4067fd2005-11-08 21:37:55 -0800120
121 case VIDIOC_LOG_STATUS:
122 {
123 u8 v = cs53l32a_read(client, 0x01);
124 u8 m = cs53l32a_read(client, 0x03);
Hans Verkuil93605352006-01-09 15:25:39 -0200125 s8 vol = cs53l32a_read(client, 0x04);
Hans Verkuilf4067fd2005-11-08 21:37:55 -0800126
Hans Verkuil93605352006-01-09 15:25:39 -0200127 cs53l32a_info("Input: %d%s\n", (v >> 4) & 3,
Hans Verkuilf4067fd2005-11-08 21:37:55 -0800128 (m & 0xC0) ? " (muted)" : "");
Hans Verkuil93605352006-01-09 15:25:39 -0200129 cs53l32a_info("Volume: %d dB\n", vol);
Hans Verkuilf4067fd2005-11-08 21:37:55 -0800130 break;
131 }
132
133 default:
134 return -EINVAL;
135 }
136 return 0;
137}
138
139/* ----------------------------------------------------------------------- */
140
141/* i2c implementation */
142
143/*
144 * Generic i2c probe
145 * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
146 */
147
148static struct i2c_driver i2c_driver;
149
150static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind)
151{
152 struct i2c_client *client;
153 int i;
154
155 /* Check if the adapter supports the needed features */
156 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
157 return 0;
158
159 client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
160 if (client == 0)
161 return -ENOMEM;
162
163 memset(client, 0, sizeof(struct i2c_client));
164 client->addr = address;
165 client->adapter = adapter;
166 client->driver = &i2c_driver;
Hans Verkuilf4067fd2005-11-08 21:37:55 -0800167 snprintf(client->name, sizeof(client->name) - 1, "cs53l32a");
168
169 cs53l32a_info("chip found @ 0x%x (%s)\n", address << 1, adapter->name);
170
171 for (i = 1; i <= 7; i++) {
172 u8 v = cs53l32a_read(client, i);
173
174 cs53l32a_dbg("Read Reg %d %02x\n", i, v);
175 }
176
177 /* Set cs53l32a internal register for Adaptec 2010/2410 setup */
178
179 cs53l32a_write(client, 0x01, (u8) 0x21);
180 cs53l32a_write(client, 0x02, (u8) 0x29);
181 cs53l32a_write(client, 0x03, (u8) 0x30);
182 cs53l32a_write(client, 0x04, (u8) 0x00);
183 cs53l32a_write(client, 0x05, (u8) 0x00);
184 cs53l32a_write(client, 0x06, (u8) 0x00);
185 cs53l32a_write(client, 0x07, (u8) 0x00);
186
187 /* Display results, should be 0x21,0x29,0x30,0x00,0x00,0x00,0x00 */
188
189 for (i = 1; i <= 7; i++) {
190 u8 v = cs53l32a_read(client, i);
191
192 cs53l32a_dbg("Read Reg %d %02x\n", i, v);
193 }
194
195 i2c_attach_client(client);
196
197 return 0;
198}
199
200static int cs53l32a_probe(struct i2c_adapter *adapter)
201{
Hans Verkuile2998e12005-11-08 21:38:49 -0800202 if (adapter->class & I2C_CLASS_TV_ANALOG)
Hans Verkuile2998e12005-11-08 21:38:49 -0800203 return i2c_probe(adapter, &addr_data, cs53l32a_attach);
204 return 0;
Hans Verkuilf4067fd2005-11-08 21:37:55 -0800205}
206
207static int cs53l32a_detach(struct i2c_client *client)
208{
209 int err;
210
211 err = i2c_detach_client(client);
212 if (err) {
213 return err;
214 }
215 kfree(client);
216
217 return 0;
218}
219
220/* ----------------------------------------------------------------------- */
221
222/* i2c implementation */
223static struct i2c_driver i2c_driver = {
Laurent Riffard604f28e2005-11-26 20:43:39 +0100224 .driver = {
Laurent Riffard604f28e2005-11-26 20:43:39 +0100225 .name = "cs53l32a",
226 },
Hans Verkuilf4067fd2005-11-08 21:37:55 -0800227 .id = I2C_DRIVERID_CS53L32A,
Hans Verkuilf4067fd2005-11-08 21:37:55 -0800228 .attach_adapter = cs53l32a_probe,
229 .detach_client = cs53l32a_detach,
230 .command = cs53l32a_command,
Hans Verkuilf4067fd2005-11-08 21:37:55 -0800231};
232
233
234static int __init cs53l32a_init_module(void)
235{
236 return i2c_add_driver(&i2c_driver);
237}
238
239static void __exit cs53l32a_cleanup_module(void)
240{
241 i2c_del_driver(&i2c_driver);
242}
243
244module_init(cs53l32a_init_module);
245module_exit(cs53l32a_cleanup_module);