diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/vp27smpx.c | 126 |
1 files changed, 86 insertions, 40 deletions
diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c index 577956c5410b..f72b859486ad 100644 --- a/drivers/media/video/vp27smpx.c +++ b/drivers/media/video/vp27smpx.c | |||
@@ -28,7 +28,7 @@ | |||
28 | #include <linux/i2c.h> | 28 | #include <linux/i2c.h> |
29 | #include <linux/i2c-id.h> | 29 | #include <linux/i2c-id.h> |
30 | #include <linux/videodev2.h> | 30 | #include <linux/videodev2.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 | ||
@@ -40,13 +40,20 @@ MODULE_LICENSE("GPL"); | |||
40 | /* ----------------------------------------------------------------------- */ | 40 | /* ----------------------------------------------------------------------- */ |
41 | 41 | ||
42 | struct vp27smpx_state { | 42 | struct vp27smpx_state { |
43 | struct v4l2_subdev sd; | ||
43 | int radio; | 44 | int radio; |
44 | u32 audmode; | 45 | u32 audmode; |
45 | }; | 46 | }; |
46 | 47 | ||
47 | static void vp27smpx_set_audmode(struct i2c_client *client, u32 audmode) | 48 | static inline struct vp27smpx_state *to_state(struct v4l2_subdev *sd) |
48 | { | 49 | { |
49 | struct vp27smpx_state *state = i2c_get_clientdata(client); | 50 | return container_of(sd, struct vp27smpx_state, sd); |
51 | } | ||
52 | |||
53 | static void vp27smpx_set_audmode(struct v4l2_subdev *sd, u32 audmode) | ||
54 | { | ||
55 | struct vp27smpx_state *state = to_state(sd); | ||
56 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
50 | u8 data[3] = { 0x00, 0x00, 0x04 }; | 57 | u8 data[3] = { 0x00, 0x00, 0x04 }; |
51 | 58 | ||
52 | switch (audmode) { | 59 | switch (audmode) { |
@@ -63,55 +70,89 @@ static void vp27smpx_set_audmode(struct i2c_client *client, u32 audmode) | |||
63 | } | 70 | } |
64 | 71 | ||
65 | if (i2c_master_send(client, data, sizeof(data)) != sizeof(data)) | 72 | if (i2c_master_send(client, data, sizeof(data)) != sizeof(data)) |
66 | v4l_err(client, "%s: I/O error setting audmode\n", | 73 | v4l2_err(sd, "I/O error setting audmode\n"); |
67 | client->name); | ||
68 | else | 74 | else |
69 | state->audmode = audmode; | 75 | state->audmode = audmode; |
70 | } | 76 | } |
71 | 77 | ||
72 | static int vp27smpx_command(struct i2c_client *client, unsigned cmd, void *arg) | 78 | static int vp27smpx_s_radio(struct v4l2_subdev *sd) |
73 | { | 79 | { |
74 | struct vp27smpx_state *state = i2c_get_clientdata(client); | 80 | struct vp27smpx_state *state = to_state(sd); |
75 | struct v4l2_tuner *vt = arg; | ||
76 | 81 | ||
77 | switch (cmd) { | 82 | state->radio = 1; |
78 | case AUDC_SET_RADIO: | 83 | return 0; |
79 | state->radio = 1; | 84 | } |
80 | break; | ||
81 | 85 | ||
82 | case VIDIOC_S_STD: | 86 | static int vp27smpx_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) |
83 | state->radio = 0; | 87 | { |
84 | break; | 88 | struct vp27smpx_state *state = to_state(sd); |
85 | 89 | ||
86 | case VIDIOC_S_TUNER: | 90 | state->radio = 0; |
87 | if (!state->radio) | 91 | return 0; |
88 | vp27smpx_set_audmode(client, vt->audmode); | 92 | } |
89 | break; | ||
90 | 93 | ||
91 | case VIDIOC_G_TUNER: | 94 | static int vp27smpx_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) |
92 | if (state->radio) | 95 | { |
93 | break; | 96 | struct vp27smpx_state *state = to_state(sd); |
94 | vt->audmode = state->audmode; | ||
95 | vt->capability = V4L2_TUNER_CAP_STEREO | | ||
96 | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; | ||
97 | vt->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
98 | break; | ||
99 | 97 | ||
100 | case VIDIOC_G_CHIP_IDENT: | 98 | if (!state->radio) |
101 | return v4l2_chip_ident_i2c_client(client, arg, | 99 | vp27smpx_set_audmode(sd, vt->audmode); |
102 | V4L2_IDENT_VP27SMPX, 0); | 100 | return 0; |
101 | } | ||
103 | 102 | ||
104 | case VIDIOC_LOG_STATUS: | 103 | static int vp27smpx_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) |
105 | v4l_info(client, "Audio Mode: %u%s\n", state->audmode, | 104 | { |
106 | state->radio ? " (Radio)" : ""); | 105 | struct vp27smpx_state *state = to_state(sd); |
107 | break; | 106 | |
107 | if (state->radio) | ||
108 | return 0; | ||
109 | vt->audmode = state->audmode; | ||
110 | vt->capability = V4L2_TUNER_CAP_STEREO | | ||
111 | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; | ||
112 | vt->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
113 | return 0; | ||
114 | } | ||
108 | 115 | ||
109 | default: | 116 | static int vp27smpx_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip) |
110 | return -EINVAL; | 117 | { |
111 | } | 118 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
119 | |||
120 | return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_VP27SMPX, 0); | ||
121 | } | ||
122 | |||
123 | static int vp27smpx_log_status(struct v4l2_subdev *sd) | ||
124 | { | ||
125 | struct vp27smpx_state *state = to_state(sd); | ||
126 | |||
127 | v4l2_info(sd, "Audio Mode: %u%s\n", state->audmode, | ||
128 | state->radio ? " (Radio)" : ""); | ||
112 | return 0; | 129 | return 0; |
113 | } | 130 | } |
114 | 131 | ||
132 | static int vp27smpx_command(struct i2c_client *client, unsigned cmd, void *arg) | ||
133 | { | ||
134 | return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg); | ||
135 | } | ||
136 | |||
137 | /* ----------------------------------------------------------------------- */ | ||
138 | |||
139 | static const struct v4l2_subdev_core_ops vp27smpx_core_ops = { | ||
140 | .log_status = vp27smpx_log_status, | ||
141 | .g_chip_ident = vp27smpx_g_chip_ident, | ||
142 | }; | ||
143 | |||
144 | static const struct v4l2_subdev_tuner_ops vp27smpx_tuner_ops = { | ||
145 | .s_radio = vp27smpx_s_radio, | ||
146 | .s_std = vp27smpx_s_std, | ||
147 | .s_tuner = vp27smpx_s_tuner, | ||
148 | .g_tuner = vp27smpx_g_tuner, | ||
149 | }; | ||
150 | |||
151 | static const struct v4l2_subdev_ops vp27smpx_ops = { | ||
152 | .core = &vp27smpx_core_ops, | ||
153 | .tuner = &vp27smpx_tuner_ops, | ||
154 | }; | ||
155 | |||
115 | /* ----------------------------------------------------------------------- */ | 156 | /* ----------------------------------------------------------------------- */ |
116 | 157 | ||
117 | /* i2c implementation */ | 158 | /* i2c implementation */ |
@@ -125,6 +166,7 @@ static int vp27smpx_probe(struct i2c_client *client, | |||
125 | const struct i2c_device_id *id) | 166 | const struct i2c_device_id *id) |
126 | { | 167 | { |
127 | struct vp27smpx_state *state; | 168 | struct vp27smpx_state *state; |
169 | struct v4l2_subdev *sd; | ||
128 | 170 | ||
129 | /* Check if the adapter supports the needed features */ | 171 | /* Check if the adapter supports the needed features */ |
130 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | 172 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) |
@@ -136,17 +178,21 @@ static int vp27smpx_probe(struct i2c_client *client, | |||
136 | state = kzalloc(sizeof(struct vp27smpx_state), GFP_KERNEL); | 178 | state = kzalloc(sizeof(struct vp27smpx_state), GFP_KERNEL); |
137 | if (state == NULL) | 179 | if (state == NULL) |
138 | return -ENOMEM; | 180 | return -ENOMEM; |
181 | sd = &state->sd; | ||
182 | v4l2_i2c_subdev_init(sd, client, &vp27smpx_ops); | ||
139 | state->audmode = V4L2_TUNER_MODE_STEREO; | 183 | state->audmode = V4L2_TUNER_MODE_STEREO; |
140 | i2c_set_clientdata(client, state); | ||
141 | 184 | ||
142 | /* initialize vp27smpx */ | 185 | /* initialize vp27smpx */ |
143 | vp27smpx_set_audmode(client, state->audmode); | 186 | vp27smpx_set_audmode(sd, state->audmode); |
144 | return 0; | 187 | return 0; |
145 | } | 188 | } |
146 | 189 | ||
147 | static int vp27smpx_remove(struct i2c_client *client) | 190 | static int vp27smpx_remove(struct i2c_client *client) |
148 | { | 191 | { |
149 | kfree(i2c_get_clientdata(client)); | 192 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
193 | |||
194 | v4l2_device_unregister_subdev(sd); | ||
195 | kfree(to_state(sd)); | ||
150 | return 0; | 196 | return 0; |
151 | } | 197 | } |
152 | 198 | ||