aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/video/tlv320aic23b.c141
1 files changed, 87 insertions, 54 deletions
diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c
index 281065b9dd2d..5c95ecd09dc2 100644
--- a/drivers/media/video/tlv320aic23b.c
+++ b/drivers/media/video/tlv320aic23b.c
@@ -30,7 +30,7 @@
30#include <linux/i2c.h> 30#include <linux/i2c.h>
31#include <linux/i2c-id.h> 31#include <linux/i2c-id.h>
32#include <linux/videodev2.h> 32#include <linux/videodev2.h>
33#include <media/v4l2-common.h> 33#include <media/v4l2-device.h>
34#include <media/v4l2-i2c-drv-legacy.h> 34#include <media/v4l2-i2c-drv-legacy.h>
35 35
36MODULE_DESCRIPTION("tlv320aic23b driver"); 36MODULE_DESCRIPTION("tlv320aic23b driver");
@@ -44,15 +44,22 @@ I2C_CLIENT_INSMOD;
44/* ----------------------------------------------------------------------- */ 44/* ----------------------------------------------------------------------- */
45 45
46struct tlv320aic23b_state { 46struct tlv320aic23b_state {
47 struct v4l2_subdev sd;
47 u8 muted; 48 u8 muted;
48}; 49};
49 50
50static int tlv320aic23b_write(struct i2c_client *client, int reg, u16 val) 51static inline struct tlv320aic23b_state *to_state(struct v4l2_subdev *sd)
51{ 52{
53 return container_of(sd, struct tlv320aic23b_state, sd);
54}
55
56static int tlv320aic23b_write(struct v4l2_subdev *sd, int reg, u16 val)
57{
58 struct i2c_client *client = v4l2_get_subdevdata(sd);
52 int i; 59 int i;
53 60
54 if ((reg < 0 || reg > 9) && (reg != 15)) { 61 if ((reg < 0 || reg > 9) && (reg != 15)) {
55 v4l_err(client, "Invalid register R%d\n", reg); 62 v4l2_err(sd, "Invalid register R%d\n", reg);
56 return -1; 63 return -1;
57 } 64 }
58 65
@@ -60,61 +67,82 @@ static int tlv320aic23b_write(struct i2c_client *client, int reg, u16 val)
60 if (i2c_smbus_write_byte_data(client, 67 if (i2c_smbus_write_byte_data(client,
61 (reg << 1) | (val >> 8), val & 0xff) == 0) 68 (reg << 1) | (val >> 8), val & 0xff) == 0)
62 return 0; 69 return 0;
63 v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg); 70 v4l2_err(sd, "I2C: cannot write %03x to register R%d\n", val, reg);
64 return -1; 71 return -1;
65} 72}
66 73
67static int tlv320aic23b_command(struct i2c_client *client, 74static int tlv320aic23b_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
68 unsigned int cmd, void *arg)
69{ 75{
70 struct tlv320aic23b_state *state = i2c_get_clientdata(client); 76 switch (freq) {
71 struct v4l2_control *ctrl = arg; 77 case 32000: /* set sample rate to 32 kHz */
72 u32 *freq = arg; 78 tlv320aic23b_write(sd, 8, 0x018);
73
74 switch (cmd) {
75 case VIDIOC_INT_AUDIO_CLOCK_FREQ:
76 switch (*freq) {
77 case 32000: /* set sample rate to 32 kHz */
78 tlv320aic23b_write(client, 8, 0x018);
79 break;
80 case 44100: /* set sample rate to 44.1 kHz */
81 tlv320aic23b_write(client, 8, 0x022);
82 break;
83 case 48000: /* set sample rate to 48 kHz */
84 tlv320aic23b_write(client, 8, 0x000);
85 break;
86 default:
87 return -EINVAL;
88 }
89 break;
90
91 case VIDIOC_G_CTRL:
92 if (ctrl->id != V4L2_CID_AUDIO_MUTE)
93 return -EINVAL;
94 ctrl->value = state->muted;
95 break; 79 break;
96 80 case 44100: /* set sample rate to 44.1 kHz */
97 case VIDIOC_S_CTRL: 81 tlv320aic23b_write(sd, 8, 0x022);
98 if (ctrl->id != V4L2_CID_AUDIO_MUTE)
99 return -EINVAL;
100 state->muted = ctrl->value;
101 tlv320aic23b_write(client, 0, 0x180); /* mute both channels */
102 /* set gain on both channels to +3.0 dB */
103 if (!state->muted)
104 tlv320aic23b_write(client, 0, 0x119);
105 break; 82 break;
106 83 case 48000: /* set sample rate to 48 kHz */
107 case VIDIOC_LOG_STATUS: 84 tlv320aic23b_write(sd, 8, 0x000);
108 v4l_info(client, "Input: %s\n",
109 state->muted ? "muted" : "active");
110 break; 85 break;
111
112 default: 86 default:
113 return -EINVAL; 87 return -EINVAL;
114 } 88 }
115 return 0; 89 return 0;
116} 90}
117 91
92static int tlv320aic23b_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
93{
94 struct tlv320aic23b_state *state = to_state(sd);
95
96 if (ctrl->id != V4L2_CID_AUDIO_MUTE)
97 return -EINVAL;
98 ctrl->value = state->muted;
99 return 0;
100}
101
102static int tlv320aic23b_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
103{
104 struct tlv320aic23b_state *state = to_state(sd);
105
106 if (ctrl->id != V4L2_CID_AUDIO_MUTE)
107 return -EINVAL;
108 state->muted = ctrl->value;
109 tlv320aic23b_write(sd, 0, 0x180); /* mute both channels */
110 /* set gain on both channels to +3.0 dB */
111 if (!state->muted)
112 tlv320aic23b_write(sd, 0, 0x119);
113 return 0;
114}
115
116static int tlv320aic23b_log_status(struct v4l2_subdev *sd)
117{
118 struct tlv320aic23b_state *state = to_state(sd);
119
120 v4l2_info(sd, "Input: %s\n", state->muted ? "muted" : "active");
121 return 0;
122}
123
124static int tlv320aic23b_command(struct i2c_client *client, unsigned cmd, void *arg)
125{
126 return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
127}
128
129/* ----------------------------------------------------------------------- */
130
131static const struct v4l2_subdev_core_ops tlv320aic23b_core_ops = {
132 .log_status = tlv320aic23b_log_status,
133 .g_ctrl = tlv320aic23b_g_ctrl,
134 .s_ctrl = tlv320aic23b_s_ctrl,
135};
136
137static const struct v4l2_subdev_audio_ops tlv320aic23b_audio_ops = {
138 .s_clock_freq = tlv320aic23b_s_clock_freq,
139};
140
141static const struct v4l2_subdev_ops tlv320aic23b_ops = {
142 .core = &tlv320aic23b_core_ops,
143 .audio = &tlv320aic23b_audio_ops,
144};
145
118/* ----------------------------------------------------------------------- */ 146/* ----------------------------------------------------------------------- */
119 147
120/* i2c implementation */ 148/* i2c implementation */
@@ -128,6 +156,7 @@ static int tlv320aic23b_probe(struct i2c_client *client,
128 const struct i2c_device_id *id) 156 const struct i2c_device_id *id)
129{ 157{
130 struct tlv320aic23b_state *state; 158 struct tlv320aic23b_state *state;
159 struct v4l2_subdev *sd;
131 160
132 /* Check if the adapter supports the needed features */ 161 /* Check if the adapter supports the needed features */
133 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 162 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -136,32 +165,36 @@ static int tlv320aic23b_probe(struct i2c_client *client,
136 v4l_info(client, "chip found @ 0x%x (%s)\n", 165 v4l_info(client, "chip found @ 0x%x (%s)\n",
137 client->addr << 1, client->adapter->name); 166 client->addr << 1, client->adapter->name);
138 167
139 state = kmalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL); 168 state = kzalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL);
140 if (state == NULL) 169 if (state == NULL)
141 return -ENOMEM; 170 return -ENOMEM;
171 sd = &state->sd;
172 v4l2_i2c_subdev_init(sd, client, &tlv320aic23b_ops);
142 state->muted = 0; 173 state->muted = 0;
143 i2c_set_clientdata(client, state);
144 174
145 /* Initialize tlv320aic23b */ 175 /* Initialize tlv320aic23b */
146 176
147 /* RESET */ 177 /* RESET */
148 tlv320aic23b_write(client, 15, 0x000); 178 tlv320aic23b_write(sd, 15, 0x000);
149 /* turn off DAC & mic input */ 179 /* turn off DAC & mic input */
150 tlv320aic23b_write(client, 6, 0x00A); 180 tlv320aic23b_write(sd, 6, 0x00A);
151 /* left-justified, 24-bit, master mode */ 181 /* left-justified, 24-bit, master mode */
152 tlv320aic23b_write(client, 7, 0x049); 182 tlv320aic23b_write(sd, 7, 0x049);
153 /* set gain on both channels to +3.0 dB */ 183 /* set gain on both channels to +3.0 dB */
154 tlv320aic23b_write(client, 0, 0x119); 184 tlv320aic23b_write(sd, 0, 0x119);
155 /* set sample rate to 48 kHz */ 185 /* set sample rate to 48 kHz */
156 tlv320aic23b_write(client, 8, 0x000); 186 tlv320aic23b_write(sd, 8, 0x000);
157 /* activate digital interface */ 187 /* activate digital interface */
158 tlv320aic23b_write(client, 9, 0x001); 188 tlv320aic23b_write(sd, 9, 0x001);
159 return 0; 189 return 0;
160} 190}
161 191
162static int tlv320aic23b_remove(struct i2c_client *client) 192static int tlv320aic23b_remove(struct i2c_client *client)
163{ 193{
164 kfree(i2c_get_clientdata(client)); 194 struct v4l2_subdev *sd = i2c_get_clientdata(client);
195
196 v4l2_device_unregister_subdev(sd);
197 kfree(to_state(sd));
165 return 0; 198 return 0;
166} 199}
167 200