diff options
author | Scott Alfter <salfter@ssai.us> | 2006-05-20 15:04:31 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2006-06-25 01:05:00 -0400 |
commit | 88ca8ed0b7f2f04a055ff3c389f398ba3ad3d27d (patch) | |
tree | 03964b1b5ca2bee2be790647efa3d922201b1710 /drivers/media/video/tlv320aic23b.c | |
parent | a22f1cbc2d3acd99986e96092109f6ced0f0022e (diff) |
V4L/DVB (4048): Add support for the Texas Instruments TLV320AIC23B audio codec
Signed-off-by: Scott Alfter <salfter@ssai.us>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/tlv320aic23b.c')
-rw-r--r-- | drivers/media/video/tlv320aic23b.c | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c new file mode 100644 index 000000000000..76b2e96429d9 --- /dev/null +++ b/drivers/media/video/tlv320aic23b.c | |||
@@ -0,0 +1,217 @@ | |||
1 | /* | ||
2 | * tlv320aic23b - driver version 0.0.1 | ||
3 | * | ||
4 | * Copyright (C) 2006 Scott Alfter <salfter@ssai.us> | ||
5 | * | ||
6 | * Based on wm8775 driver | ||
7 | * | ||
8 | * Copyright (C) 2004 Ulf Eklund <ivtv at eklund.to> | ||
9 | * Copyright (C) 2005 Hans Verkuil <hverkuil@xs4all.nl> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
24 | */ | ||
25 | |||
26 | #include <linux/module.h> | ||
27 | #include <linux/types.h> | ||
28 | #include <linux/ioctl.h> | ||
29 | #include <asm/uaccess.h> | ||
30 | #include <linux/i2c.h> | ||
31 | #include <linux/i2c-id.h> | ||
32 | #include <linux/videodev.h> | ||
33 | #include <media/v4l2-common.h> | ||
34 | |||
35 | MODULE_DESCRIPTION("tlv320aic23b driver"); | ||
36 | MODULE_AUTHOR("Scott Alfter, Ulf Eklund, Hans Verkuil"); | ||
37 | MODULE_LICENSE("GPL"); | ||
38 | |||
39 | static unsigned short normal_i2c[] = { 0x34 >> 1, I2C_CLIENT_END }; | ||
40 | |||
41 | |||
42 | I2C_CLIENT_INSMOD; | ||
43 | |||
44 | /* ----------------------------------------------------------------------- */ | ||
45 | |||
46 | struct tlv320aic23b_state { | ||
47 | u8 muted; | ||
48 | }; | ||
49 | |||
50 | static int tlv320aic23b_write(struct i2c_client *client, int reg, u16 val) | ||
51 | { | ||
52 | int i; | ||
53 | |||
54 | if ((reg < 0 || reg > 9) && (reg != 15)) { | ||
55 | v4l_err(client, "Invalid register R%d\n", reg); | ||
56 | return -1; | ||
57 | } | ||
58 | |||
59 | for (i = 0; i < 3; i++) { | ||
60 | if (i2c_smbus_write_byte_data(client, (reg << 1) | | ||
61 | (val >> 8), val & 0xff) == 0) { | ||
62 | return 0; | ||
63 | } | ||
64 | } | ||
65 | v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg); | ||
66 | return -1; | ||
67 | } | ||
68 | |||
69 | static int tlv320aic23b_command(struct i2c_client *client, unsigned int cmd, | ||
70 | void *arg) | ||
71 | { | ||
72 | struct tlv320aic23b_state *state = i2c_get_clientdata(client); | ||
73 | struct v4l2_control *ctrl = arg; | ||
74 | u32* freq = arg; | ||
75 | |||
76 | switch (cmd) { | ||
77 | case VIDIOC_INT_AUDIO_CLOCK_FREQ: | ||
78 | switch (*freq) { | ||
79 | case 32000: /* set sample rate to 32 kHz */ | ||
80 | tlv320aic23b_write(client, 8, 0x018); | ||
81 | break; | ||
82 | case 44100: /* set sample rate to 44.1 kHz */ | ||
83 | tlv320aic23b_write(client, 8, 0x022); | ||
84 | break; | ||
85 | case 48000: /* set sample rate to 48 kHz */ | ||
86 | tlv320aic23b_write(client, 8, 0x000); | ||
87 | break; | ||
88 | default: | ||
89 | return -EINVAL; | ||
90 | } | ||
91 | break; | ||
92 | |||
93 | case VIDIOC_G_CTRL: | ||
94 | if (ctrl->id != V4L2_CID_AUDIO_MUTE) | ||
95 | return -EINVAL; | ||
96 | ctrl->value = state->muted; | ||
97 | break; | ||
98 | |||
99 | case VIDIOC_S_CTRL: | ||
100 | if (ctrl->id != V4L2_CID_AUDIO_MUTE) | ||
101 | return -EINVAL; | ||
102 | state->muted = ctrl->value; | ||
103 | tlv320aic23b_write(client, 0, 0x180); /* mute both channels */ | ||
104 | /* set gain on both channels to +3.0 dB */ | ||
105 | if (!state->muted) | ||
106 | tlv320aic23b_write(client, 0, 0x119); | ||
107 | break; | ||
108 | |||
109 | case VIDIOC_LOG_STATUS: | ||
110 | v4l_info(client, "Input: %s\n", | ||
111 | state->muted ? "muted" : "active"); | ||
112 | break; | ||
113 | |||
114 | default: | ||
115 | return -EINVAL; | ||
116 | } | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | /* ----------------------------------------------------------------------- */ | ||
121 | |||
122 | /* i2c implementation */ | ||
123 | |||
124 | /* | ||
125 | * Generic i2c probe | ||
126 | * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' | ||
127 | */ | ||
128 | |||
129 | static struct i2c_driver i2c_driver; | ||
130 | |||
131 | static int tlv320aic23b_attach(struct i2c_adapter *adapter, int address, int kind) | ||
132 | { | ||
133 | struct i2c_client *client; | ||
134 | struct tlv320aic23b_state *state; | ||
135 | |||
136 | /* Check if the adapter supports the needed features */ | ||
137 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
138 | return 0; | ||
139 | |||
140 | client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); | ||
141 | if (client == 0) | ||
142 | return -ENOMEM; | ||
143 | |||
144 | client->addr = address; | ||
145 | client->adapter = adapter; | ||
146 | client->driver = &i2c_driver; | ||
147 | snprintf(client->name, sizeof(client->name) - 1, "tlv320aic23b"); | ||
148 | |||
149 | v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); | ||
150 | |||
151 | state = kmalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL); | ||
152 | if (state == NULL) { | ||
153 | kfree(client); | ||
154 | return -ENOMEM; | ||
155 | } | ||
156 | state->muted = 0; | ||
157 | i2c_set_clientdata(client, state); | ||
158 | |||
159 | /* initialize tlv320aic23b */ | ||
160 | tlv320aic23b_write(client, 15, 0x000); /* RESET */ | ||
161 | tlv320aic23b_write(client, 6, 0x00A); /* turn off DAC & mic input */ | ||
162 | tlv320aic23b_write(client, 7, 0x049); /* left-justified, 24-bit, master mode */ | ||
163 | tlv320aic23b_write(client, 0, 0x119); /* set gain on both channels to +3.0 dB */ | ||
164 | tlv320aic23b_write(client, 8, 0x000); /* set sample rate to 48 kHz */ | ||
165 | tlv320aic23b_write(client, 9, 0x001); /* activate digital interface */ | ||
166 | |||
167 | i2c_attach_client(client); | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static int tlv320aic23b_probe(struct i2c_adapter *adapter) | ||
173 | { | ||
174 | if (adapter->class & I2C_CLASS_TV_ANALOG) | ||
175 | return i2c_probe(adapter, &addr_data, tlv320aic23b_attach); | ||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static int tlv320aic23b_detach(struct i2c_client *client) | ||
180 | { | ||
181 | int err; | ||
182 | |||
183 | err = i2c_detach_client(client); | ||
184 | if (err) { | ||
185 | return err; | ||
186 | } | ||
187 | kfree(client); | ||
188 | |||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | /* ----------------------------------------------------------------------- */ | ||
193 | |||
194 | /* i2c implementation */ | ||
195 | static struct i2c_driver i2c_driver = { | ||
196 | .driver = { | ||
197 | .name = "tlv320aic23b", | ||
198 | }, | ||
199 | .id = I2C_DRIVERID_TLV320AIC23B, | ||
200 | .attach_adapter = tlv320aic23b_probe, | ||
201 | .detach_client = tlv320aic23b_detach, | ||
202 | .command = tlv320aic23b_command, | ||
203 | }; | ||
204 | |||
205 | |||
206 | static int __init tlv320aic23b_init_module(void) | ||
207 | { | ||
208 | return i2c_add_driver(&i2c_driver); | ||
209 | } | ||
210 | |||
211 | static void __exit tlv320aic23b_cleanup_module(void) | ||
212 | { | ||
213 | i2c_del_driver(&i2c_driver); | ||
214 | } | ||
215 | |||
216 | module_init(tlv320aic23b_init_module); | ||
217 | module_exit(tlv320aic23b_cleanup_module); | ||