aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cs53l32a.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/cs53l32a.c')
-rw-r--r--drivers/media/video/cs53l32a.c188
1 files changed, 112 insertions, 76 deletions
diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c
index c4444500b330..cb65d519cf78 100644
--- a/drivers/media/video/cs53l32a.c
+++ b/drivers/media/video/cs53l32a.c
@@ -27,7 +27,7 @@
27#include <linux/i2c.h> 27#include <linux/i2c.h>
28#include <linux/i2c-id.h> 28#include <linux/i2c-id.h>
29#include <linux/videodev2.h> 29#include <linux/videodev2.h>
30#include <media/v4l2-common.h> 30#include <media/v4l2-device.h>
31#include <media/v4l2-chip-ident.h> 31#include <media/v4l2-chip-ident.h>
32#include <media/v4l2-i2c-drv-legacy.h> 32#include <media/v4l2-i2c-drv-legacy.h>
33 33
@@ -47,84 +47,104 @@ I2C_CLIENT_INSMOD;
47 47
48/* ----------------------------------------------------------------------- */ 48/* ----------------------------------------------------------------------- */
49 49
50static int cs53l32a_write(struct i2c_client *client, u8 reg, u8 value) 50static int cs53l32a_write(struct v4l2_subdev *sd, u8 reg, u8 value)
51{ 51{
52 struct i2c_client *client = v4l2_get_subdevdata(sd);
53
52 return i2c_smbus_write_byte_data(client, reg, value); 54 return i2c_smbus_write_byte_data(client, reg, value);
53} 55}
54 56
55static int cs53l32a_read(struct i2c_client *client, u8 reg) 57static int cs53l32a_read(struct v4l2_subdev *sd, u8 reg)
56{ 58{
59 struct i2c_client *client = v4l2_get_subdevdata(sd);
60
57 return i2c_smbus_read_byte_data(client, reg); 61 return i2c_smbus_read_byte_data(client, reg);
58} 62}
59 63
60static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg) 64static int cs53l32a_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
61{ 65{
62 struct v4l2_routing *route = arg; 66 /* There are 2 physical inputs, but the second input can be
63 struct v4l2_control *ctrl = arg; 67 placed in two modes, the first mode bypasses the PGA (gain),
64 68 the second goes through the PGA. Hence there are three
65 switch (cmd) { 69 possible inputs to choose from. */
66 case VIDIOC_INT_G_AUDIO_ROUTING: 70 if (route->input > 2) {
67 route->input = (cs53l32a_read(client, 0x01) >> 4) & 3; 71 v4l2_err(sd, "Invalid input %d.\n", route->input);
68 route->output = 0;
69 break;
70
71 case VIDIOC_INT_S_AUDIO_ROUTING:
72 /* There are 2 physical inputs, but the second input can be
73 placed in two modes, the first mode bypasses the PGA (gain),
74 the second goes through the PGA. Hence there are three
75 possible inputs to choose from. */
76 if (route->input > 2) {
77 v4l_err(client, "Invalid input %d.\n", route->input);
78 return -EINVAL;
79 }
80 cs53l32a_write(client, 0x01, 0x01 + (route->input << 4));
81 break;
82
83 case VIDIOC_G_CTRL:
84 if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
85 ctrl->value = (cs53l32a_read(client, 0x03) & 0xc0) != 0;
86 break;
87 }
88 if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
89 return -EINVAL;
90 ctrl->value = (s8)cs53l32a_read(client, 0x04);
91 break;
92
93 case VIDIOC_S_CTRL:
94 if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
95 cs53l32a_write(client, 0x03, ctrl->value ? 0xf0 : 0x30);
96 break;
97 }
98 if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
99 return -EINVAL;
100 if (ctrl->value > 12 || ctrl->value < -96)
101 return -EINVAL;
102 cs53l32a_write(client, 0x04, (u8) ctrl->value);
103 cs53l32a_write(client, 0x05, (u8) ctrl->value);
104 break;
105
106 case VIDIOC_G_CHIP_IDENT:
107 return v4l2_chip_ident_i2c_client(client,
108 arg, V4L2_IDENT_CS53l32A, 0);
109
110 case VIDIOC_LOG_STATUS:
111 {
112 u8 v = cs53l32a_read(client, 0x01);
113 u8 m = cs53l32a_read(client, 0x03);
114 s8 vol = cs53l32a_read(client, 0x04);
115
116 v4l_info(client, "Input: %d%s\n", (v >> 4) & 3,
117 (m & 0xC0) ? " (muted)" : "");
118 v4l_info(client, "Volume: %d dB\n", vol);
119 break;
120 }
121
122 default:
123 return -EINVAL; 72 return -EINVAL;
124 } 73 }
74 cs53l32a_write(sd, 0x01, 0x01 + (route->input << 4));
75 return 0;
76}
77
78static int cs53l32a_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
79{
80 if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
81 ctrl->value = (cs53l32a_read(sd, 0x03) & 0xc0) != 0;
82 return 0;
83 }
84 if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
85 return -EINVAL;
86 ctrl->value = (s8)cs53l32a_read(sd, 0x04);
87 return 0;
88}
89
90static int cs53l32a_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
91{
92 if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
93 cs53l32a_write(sd, 0x03, ctrl->value ? 0xf0 : 0x30);
94 return 0;
95 }
96 if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
97 return -EINVAL;
98 if (ctrl->value > 12 || ctrl->value < -96)
99 return -EINVAL;
100 cs53l32a_write(sd, 0x04, (u8) ctrl->value);
101 cs53l32a_write(sd, 0x05, (u8) ctrl->value);
125 return 0; 102 return 0;
126} 103}
127 104
105static int cs53l32a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip)
106{
107 struct i2c_client *client = v4l2_get_subdevdata(sd);
108
109 return v4l2_chip_ident_i2c_client(client,
110 chip, V4L2_IDENT_CS53l32A, 0);
111}
112
113static int cs53l32a_log_status(struct v4l2_subdev *sd)
114{
115 u8 v = cs53l32a_read(sd, 0x01);
116 u8 m = cs53l32a_read(sd, 0x03);
117 s8 vol = cs53l32a_read(sd, 0x04);
118
119 v4l2_info(sd, "Input: %d%s\n", (v >> 4) & 3,
120 (m & 0xC0) ? " (muted)" : "");
121 v4l2_info(sd, "Volume: %d dB\n", vol);
122 return 0;
123}
124
125static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg)
126{
127 return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
128}
129
130/* ----------------------------------------------------------------------- */
131
132static const struct v4l2_subdev_core_ops cs53l32a_core_ops = {
133 .log_status = cs53l32a_log_status,
134 .g_chip_ident = cs53l32a_g_chip_ident,
135 .g_ctrl = cs53l32a_g_ctrl,
136 .s_ctrl = cs53l32a_s_ctrl,
137};
138
139static const struct v4l2_subdev_audio_ops cs53l32a_audio_ops = {
140 .s_routing = cs53l32a_s_routing,
141};
142
143static const struct v4l2_subdev_ops cs53l32a_ops = {
144 .core = &cs53l32a_core_ops,
145 .audio = &cs53l32a_audio_ops,
146};
147
128/* ----------------------------------------------------------------------- */ 148/* ----------------------------------------------------------------------- */
129 149
130/* i2c implementation */ 150/* i2c implementation */
@@ -137,6 +157,7 @@ static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg)
137static int cs53l32a_probe(struct i2c_client *client, 157static int cs53l32a_probe(struct i2c_client *client,
138 const struct i2c_device_id *id) 158 const struct i2c_device_id *id)
139{ 159{
160 struct v4l2_subdev *sd;
140 int i; 161 int i;
141 162
142 /* Check if the adapter supports the needed features */ 163 /* Check if the adapter supports the needed features */
@@ -149,32 +170,46 @@ static int cs53l32a_probe(struct i2c_client *client,
149 v4l_info(client, "chip found @ 0x%x (%s)\n", 170 v4l_info(client, "chip found @ 0x%x (%s)\n",
150 client->addr << 1, client->adapter->name); 171 client->addr << 1, client->adapter->name);
151 172
173 sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
174 if (sd == NULL)
175 return -ENOMEM;
176 v4l2_i2c_subdev_init(sd, client, &cs53l32a_ops);
177
152 for (i = 1; i <= 7; i++) { 178 for (i = 1; i <= 7; i++) {
153 u8 v = cs53l32a_read(client, i); 179 u8 v = cs53l32a_read(sd, i);
154 180
155 v4l_dbg(1, debug, client, "Read Reg %d %02x\n", i, v); 181 v4l2_dbg(1, debug, sd, "Read Reg %d %02x\n", i, v);
156 } 182 }
157 183
158 /* Set cs53l32a internal register for Adaptec 2010/2410 setup */ 184 /* Set cs53l32a internal register for Adaptec 2010/2410 setup */
159 185
160 cs53l32a_write(client, 0x01, (u8) 0x21); 186 cs53l32a_write(sd, 0x01, (u8) 0x21);
161 cs53l32a_write(client, 0x02, (u8) 0x29); 187 cs53l32a_write(sd, 0x02, (u8) 0x29);
162 cs53l32a_write(client, 0x03, (u8) 0x30); 188 cs53l32a_write(sd, 0x03, (u8) 0x30);
163 cs53l32a_write(client, 0x04, (u8) 0x00); 189 cs53l32a_write(sd, 0x04, (u8) 0x00);
164 cs53l32a_write(client, 0x05, (u8) 0x00); 190 cs53l32a_write(sd, 0x05, (u8) 0x00);
165 cs53l32a_write(client, 0x06, (u8) 0x00); 191 cs53l32a_write(sd, 0x06, (u8) 0x00);
166 cs53l32a_write(client, 0x07, (u8) 0x00); 192 cs53l32a_write(sd, 0x07, (u8) 0x00);
167 193
168 /* Display results, should be 0x21,0x29,0x30,0x00,0x00,0x00,0x00 */ 194 /* Display results, should be 0x21,0x29,0x30,0x00,0x00,0x00,0x00 */
169 195
170 for (i = 1; i <= 7; i++) { 196 for (i = 1; i <= 7; i++) {
171 u8 v = cs53l32a_read(client, i); 197 u8 v = cs53l32a_read(sd, i);
172 198
173 v4l_dbg(1, debug, client, "Read Reg %d %02x\n", i, v); 199 v4l2_dbg(1, debug, sd, "Read Reg %d %02x\n", i, v);
174 } 200 }
175 return 0; 201 return 0;
176} 202}
177 203
204static int cs53l32a_remove(struct i2c_client *client)
205{
206 struct v4l2_subdev *sd = i2c_get_clientdata(client);
207
208 v4l2_device_unregister_subdev(sd);
209 kfree(sd);
210 return 0;
211}
212
178static const struct i2c_device_id cs53l32a_id[] = { 213static const struct i2c_device_id cs53l32a_id[] = {
179 { "cs53l32a", 0 }, 214 { "cs53l32a", 0 },
180 { } 215 { }
@@ -185,6 +220,7 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
185 .name = "cs53l32a", 220 .name = "cs53l32a",
186 .driverid = I2C_DRIVERID_CS53L32A, 221 .driverid = I2C_DRIVERID_CS53L32A,
187 .command = cs53l32a_command, 222 .command = cs53l32a_command,
223 .remove = cs53l32a_remove,
188 .probe = cs53l32a_probe, 224 .probe = cs53l32a_probe,
189 .id_table = cs53l32a_id, 225 .id_table = cs53l32a_id,
190}; 226};