aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/m52790.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/m52790.c')
-rw-r--r--drivers/media/video/m52790.c176
1 files changed, 111 insertions, 65 deletions
diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c
index 89a781c6929d..07be14a9fe7b 100644
--- a/drivers/media/video/m52790.c
+++ b/drivers/media/video/m52790.c
@@ -28,7 +28,7 @@
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/m52790.h> 30#include <media/m52790.h>
31#include <media/v4l2-common.h> 31#include <media/v4l2-device.h>
32#include <media/v4l2-chip-ident.h> 32#include <media/v4l2-chip-ident.h>
33#include <media/v4l2-i2c-drv.h> 33#include <media/v4l2-i2c-drv.h>
34 34
@@ -38,89 +38,130 @@ MODULE_LICENSE("GPL");
38 38
39 39
40struct m52790_state { 40struct m52790_state {
41 struct v4l2_subdev sd;
41 u16 input; 42 u16 input;
42 u16 output; 43 u16 output;
43}; 44};
44 45
46static inline struct m52790_state *to_state(struct v4l2_subdev *sd)
47{
48 return container_of(sd, struct m52790_state, sd);
49}
50
45/* ----------------------------------------------------------------------- */ 51/* ----------------------------------------------------------------------- */
46 52
47static int m52790_write(struct i2c_client *client) 53static int m52790_write(struct v4l2_subdev *sd)
48{ 54{
49 struct m52790_state *state = i2c_get_clientdata(client); 55 struct m52790_state *state = to_state(sd);
56 struct i2c_client *client = v4l2_get_subdevdata(sd);
57
50 u8 sw1 = (state->input | state->output) & 0xff; 58 u8 sw1 = (state->input | state->output) & 0xff;
51 u8 sw2 = (state->input | state->output) >> 8; 59 u8 sw2 = (state->input | state->output) >> 8;
52 60
53 return i2c_smbus_write_byte_data(client, sw1, sw2); 61 return i2c_smbus_write_byte_data(client, sw1, sw2);
54} 62}
55 63
56static int m52790_command(struct i2c_client *client, unsigned int cmd, 64/* Note: audio and video are linked and cannot be switched separately.
57 void *arg) 65 So audio and video routing commands are identical for this chip.
66 In theory the video amplifier and audio modes could be handled
67 separately for the output, but that seems to be overkill right now.
68 The same holds for implementing an audio mute control, this is now
69 part of the audio output routing. The normal case is that another
70 chip takes care of the actual muting so making it part of the
71 output routing seems to be the right thing to do for now. */
72static int m52790_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
58{ 73{
59 struct m52790_state *state = i2c_get_clientdata(client); 74 struct m52790_state *state = to_state(sd);
60 struct v4l2_routing *route = arg; 75
61 76 state->input = route->input;
62 /* Note: audio and video are linked and cannot be switched separately. 77 state->output = route->output;
63 So audio and video routing commands are identical for this chip. 78 m52790_write(sd);
64 In theory the video amplifier and audio modes could be handled 79 return 0;
65 separately for the output, but that seems to be overkill right now. 80}
66 The same holds for implementing an audio mute control, this is now
67 part of the audio output routing. The normal case is that another
68 chip takes care of the actual muting so making it part of the
69 output routing seems to be the right thing to do for now. */
70 switch (cmd) {
71 case VIDIOC_INT_G_AUDIO_ROUTING:
72 case VIDIOC_INT_G_VIDEO_ROUTING:
73 route->input = state->input;
74 route->output = state->output;
75 break;
76
77 case VIDIOC_INT_S_AUDIO_ROUTING:
78 case VIDIOC_INT_S_VIDEO_ROUTING:
79 state->input = route->input;
80 state->output = route->output;
81 m52790_write(client);
82 break;
83 81
84#ifdef CONFIG_VIDEO_ADV_DEBUG 82#ifdef CONFIG_VIDEO_ADV_DEBUG
85 case VIDIOC_DBG_G_REGISTER: 83static int m52790_g_register(struct v4l2_subdev *sd, struct v4l2_register *reg)
86 case VIDIOC_DBG_S_REGISTER: 84{
87 { 85 struct m52790_state *state = to_state(sd);
88 struct v4l2_register *reg = arg; 86 struct i2c_client *client = v4l2_get_subdevdata(sd);
89
90 if (!v4l2_chip_match_i2c_client(client,
91 reg->match_type, reg->match_chip))
92 return -EINVAL;
93 if (!capable(CAP_SYS_ADMIN))
94 return -EPERM;
95 if (reg->reg != 0)
96 return -EINVAL;
97 if (cmd == VIDIOC_DBG_G_REGISTER)
98 reg->val = state->input | state->output;
99 else {
100 state->input = reg->val & 0x0303;
101 state->output = reg->val & ~0x0303;
102 m52790_write(client);
103 }
104 break;
105 }
106#endif
107 87
108 case VIDIOC_G_CHIP_IDENT: 88 if (!v4l2_chip_match_i2c_client(client,
109 return v4l2_chip_ident_i2c_client(client, arg, 89 reg->match_type, reg->match_chip))
110 V4L2_IDENT_M52790, 0); 90 return -EINVAL;
91 if (!capable(CAP_SYS_ADMIN))
92 return -EPERM;
93 if (reg->reg != 0)
94 return -EINVAL;
95 reg->val = state->input | state->output;
96 return 0;
97}
111 98
112 case VIDIOC_LOG_STATUS: 99static int m52790_s_register(struct v4l2_subdev *sd, struct v4l2_register *reg)
113 v4l_info(client, "Switch 1: %02x\n", 100{
114 (state->input | state->output) & 0xff); 101 struct m52790_state *state = to_state(sd);
115 v4l_info(client, "Switch 2: %02x\n", 102 struct i2c_client *client = v4l2_get_subdevdata(sd);
116 (state->input | state->output) >> 8);
117 break;
118 103
119 default: 104 if (!v4l2_chip_match_i2c_client(client,
105 reg->match_type, reg->match_chip))
120 return -EINVAL; 106 return -EINVAL;
121 } 107 if (!capable(CAP_SYS_ADMIN))
108 return -EPERM;
109 if (reg->reg != 0)
110 return -EINVAL;
111 state->input = reg->val & 0x0303;
112 state->output = reg->val & ~0x0303;
113 m52790_write(sd);
122 return 0; 114 return 0;
123} 115}
116#endif
117
118static int m52790_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip)
119{
120 struct i2c_client *client = v4l2_get_subdevdata(sd);
121
122 return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_M52790, 0);
123}
124
125static int m52790_log_status(struct v4l2_subdev *sd)
126{
127 struct m52790_state *state = to_state(sd);
128
129 v4l2_info(sd, "Switch 1: %02x\n",
130 (state->input | state->output) & 0xff);
131 v4l2_info(sd, "Switch 2: %02x\n",
132 (state->input | state->output) >> 8);
133 return 0;
134}
135
136static int m52790_command(struct i2c_client *client, unsigned cmd, void *arg)
137{
138 return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
139}
140
141/* ----------------------------------------------------------------------- */
142
143static const struct v4l2_subdev_core_ops m52790_core_ops = {
144 .log_status = m52790_log_status,
145 .g_chip_ident = m52790_g_chip_ident,
146#ifdef CONFIG_VIDEO_ADV_DEBUG
147 .g_register = m52790_g_register,
148 .s_register = m52790_s_register,
149#endif
150};
151
152static const struct v4l2_subdev_audio_ops m52790_audio_ops = {
153 .s_routing = m52790_s_routing,
154};
155
156static const struct v4l2_subdev_video_ops m52790_video_ops = {
157 .s_routing = m52790_s_routing,
158};
159
160static const struct v4l2_subdev_ops m52790_ops = {
161 .core = &m52790_core_ops,
162 .audio = &m52790_audio_ops,
163 .video = &m52790_video_ops,
164};
124 165
125/* ----------------------------------------------------------------------- */ 166/* ----------------------------------------------------------------------- */
126 167
@@ -130,6 +171,7 @@ static int m52790_probe(struct i2c_client *client,
130 const struct i2c_device_id *id) 171 const struct i2c_device_id *id)
131{ 172{
132 struct m52790_state *state; 173 struct m52790_state *state;
174 struct v4l2_subdev *sd;
133 175
134 /* Check if the adapter supports the needed features */ 176 /* Check if the adapter supports the needed features */
135 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 177 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -142,16 +184,20 @@ static int m52790_probe(struct i2c_client *client,
142 if (state == NULL) 184 if (state == NULL)
143 return -ENOMEM; 185 return -ENOMEM;
144 186
187 sd = &state->sd;
188 v4l2_i2c_subdev_init(sd, client, &m52790_ops);
145 state->input = M52790_IN_TUNER; 189 state->input = M52790_IN_TUNER;
146 state->output = M52790_OUT_STEREO; 190 state->output = M52790_OUT_STEREO;
147 i2c_set_clientdata(client, state); 191 m52790_write(sd);
148 m52790_write(client);
149 return 0; 192 return 0;
150} 193}
151 194
152static int m52790_remove(struct i2c_client *client) 195static int m52790_remove(struct i2c_client *client)
153{ 196{
154 kfree(i2c_get_clientdata(client)); 197 struct v4l2_subdev *sd = i2c_get_clientdata(client);
198
199 v4l2_device_unregister_subdev(sd);
200 kfree(to_state(sd));
155 return 0; 201 return 0;
156} 202}
157 203