diff options
Diffstat (limited to 'drivers/input/touchscreen/sur40.c')
-rw-r--r-- | drivers/input/touchscreen/sur40.c | 178 |
1 files changed, 177 insertions, 1 deletions
diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c index f16f8358c70a..894843a7ec7b 100644 --- a/drivers/input/touchscreen/sur40.c +++ b/drivers/input/touchscreen/sur40.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <media/v4l2-device.h> | 38 | #include <media/v4l2-device.h> |
39 | #include <media/v4l2-dev.h> | 39 | #include <media/v4l2-dev.h> |
40 | #include <media/v4l2-ioctl.h> | 40 | #include <media/v4l2-ioctl.h> |
41 | #include <media/v4l2-ctrls.h> | ||
41 | #include <media/videobuf2-v4l2.h> | 42 | #include <media/videobuf2-v4l2.h> |
42 | #include <media/videobuf2-dma-sg.h> | 43 | #include <media/videobuf2-dma-sg.h> |
43 | 44 | ||
@@ -81,7 +82,10 @@ struct sur40_blob { | |||
81 | 82 | ||
82 | __le32 area; /* size in pixels/pressure (?) */ | 83 | __le32 area; /* size in pixels/pressure (?) */ |
83 | 84 | ||
84 | u8 padding[32]; | 85 | u8 padding[24]; |
86 | |||
87 | __le32 tag_id; /* valid when type == 0x04 (SUR40_TAG) */ | ||
88 | __le32 unknown; | ||
85 | 89 | ||
86 | } __packed; | 90 | } __packed; |
87 | 91 | ||
@@ -146,6 +150,40 @@ struct sur40_image_header { | |||
146 | #define SUR40_TOUCH 0x02 | 150 | #define SUR40_TOUCH 0x02 |
147 | #define SUR40_TAG 0x04 | 151 | #define SUR40_TAG 0x04 |
148 | 152 | ||
153 | /* video controls */ | ||
154 | #define SUR40_BRIGHTNESS_MAX 0xff | ||
155 | #define SUR40_BRIGHTNESS_MIN 0x00 | ||
156 | #define SUR40_BRIGHTNESS_DEF 0xff | ||
157 | |||
158 | #define SUR40_CONTRAST_MAX 0x0f | ||
159 | #define SUR40_CONTRAST_MIN 0x00 | ||
160 | #define SUR40_CONTRAST_DEF 0x0a | ||
161 | |||
162 | #define SUR40_GAIN_MAX 0x09 | ||
163 | #define SUR40_GAIN_MIN 0x00 | ||
164 | #define SUR40_GAIN_DEF 0x08 | ||
165 | |||
166 | #define SUR40_BACKLIGHT_MAX 0x01 | ||
167 | #define SUR40_BACKLIGHT_MIN 0x00 | ||
168 | #define SUR40_BACKLIGHT_DEF 0x01 | ||
169 | |||
170 | #define sur40_str(s) #s | ||
171 | #define SUR40_PARAM_RANGE(lo, hi) " (range " sur40_str(lo) "-" sur40_str(hi) ")" | ||
172 | |||
173 | /* module parameters */ | ||
174 | static uint brightness = SUR40_BRIGHTNESS_DEF; | ||
175 | module_param(brightness, uint, 0644); | ||
176 | MODULE_PARM_DESC(brightness, "set initial brightness" | ||
177 | SUR40_PARAM_RANGE(SUR40_BRIGHTNESS_MIN, SUR40_BRIGHTNESS_MAX)); | ||
178 | static uint contrast = SUR40_CONTRAST_DEF; | ||
179 | module_param(contrast, uint, 0644); | ||
180 | MODULE_PARM_DESC(contrast, "set initial contrast" | ||
181 | SUR40_PARAM_RANGE(SUR40_CONTRAST_MIN, SUR40_CONTRAST_MAX)); | ||
182 | static uint gain = SUR40_GAIN_DEF; | ||
183 | module_param(gain, uint, 0644); | ||
184 | MODULE_PARM_DESC(gain, "set initial gain" | ||
185 | SUR40_PARAM_RANGE(SUR40_GAIN_MIN, SUR40_GAIN_MAX)); | ||
186 | |||
149 | static const struct v4l2_pix_format sur40_pix_format[] = { | 187 | static const struct v4l2_pix_format sur40_pix_format[] = { |
150 | { | 188 | { |
151 | .pixelformat = V4L2_TCH_FMT_TU08, | 189 | .pixelformat = V4L2_TCH_FMT_TU08, |
@@ -178,6 +216,7 @@ struct sur40_state { | |||
178 | struct video_device vdev; | 216 | struct video_device vdev; |
179 | struct mutex lock; | 217 | struct mutex lock; |
180 | struct v4l2_pix_format pix_fmt; | 218 | struct v4l2_pix_format pix_fmt; |
219 | struct v4l2_ctrl_handler hdl; | ||
181 | 220 | ||
182 | struct vb2_queue queue; | 221 | struct vb2_queue queue; |
183 | struct list_head buf_list; | 222 | struct list_head buf_list; |
@@ -187,6 +226,7 @@ struct sur40_state { | |||
187 | struct sur40_data *bulk_in_buffer; | 226 | struct sur40_data *bulk_in_buffer; |
188 | size_t bulk_in_size; | 227 | size_t bulk_in_size; |
189 | u8 bulk_in_epaddr; | 228 | u8 bulk_in_epaddr; |
229 | u8 vsvideo; | ||
190 | 230 | ||
191 | char phys[64]; | 231 | char phys[64]; |
192 | }; | 232 | }; |
@@ -200,6 +240,11 @@ struct sur40_buffer { | |||
200 | static const struct video_device sur40_video_device; | 240 | static const struct video_device sur40_video_device; |
201 | static const struct vb2_queue sur40_queue; | 241 | static const struct vb2_queue sur40_queue; |
202 | static void sur40_process_video(struct sur40_state *sur40); | 242 | static void sur40_process_video(struct sur40_state *sur40); |
243 | static int sur40_s_ctrl(struct v4l2_ctrl *ctrl); | ||
244 | |||
245 | static const struct v4l2_ctrl_ops sur40_ctrl_ops = { | ||
246 | .s_ctrl = sur40_s_ctrl, | ||
247 | }; | ||
203 | 248 | ||
204 | /* | 249 | /* |
205 | * Note: an earlier, non-public version of this driver used USB_RECIP_ENDPOINT | 250 | * Note: an earlier, non-public version of this driver used USB_RECIP_ENDPOINT |
@@ -220,6 +265,81 @@ static int sur40_command(struct sur40_state *dev, | |||
220 | 0x00, index, buffer, size, 1000); | 265 | 0x00, index, buffer, size, 1000); |
221 | } | 266 | } |
222 | 267 | ||
268 | /* poke a byte in the panel register space */ | ||
269 | static int sur40_poke(struct sur40_state *dev, u8 offset, u8 value) | ||
270 | { | ||
271 | int result; | ||
272 | u8 index = 0x96; // 0xae for permanent write | ||
273 | |||
274 | result = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0), | ||
275 | SUR40_POKE, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, | ||
276 | 0x32, index, NULL, 0, 1000); | ||
277 | if (result < 0) | ||
278 | goto error; | ||
279 | msleep(5); | ||
280 | |||
281 | result = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0), | ||
282 | SUR40_POKE, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, | ||
283 | 0x72, offset, NULL, 0, 1000); | ||
284 | if (result < 0) | ||
285 | goto error; | ||
286 | msleep(5); | ||
287 | |||
288 | result = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0), | ||
289 | SUR40_POKE, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, | ||
290 | 0xb2, value, NULL, 0, 1000); | ||
291 | if (result < 0) | ||
292 | goto error; | ||
293 | msleep(5); | ||
294 | |||
295 | error: | ||
296 | return result; | ||
297 | } | ||
298 | |||
299 | static int sur40_set_preprocessor(struct sur40_state *dev, u8 value) | ||
300 | { | ||
301 | u8 setting_07[2] = { 0x01, 0x00 }; | ||
302 | u8 setting_17[2] = { 0x85, 0x80 }; | ||
303 | int result; | ||
304 | |||
305 | if (value > 1) | ||
306 | return -ERANGE; | ||
307 | |||
308 | result = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0), | ||
309 | SUR40_POKE, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, | ||
310 | 0x07, setting_07[value], NULL, 0, 1000); | ||
311 | if (result < 0) | ||
312 | goto error; | ||
313 | msleep(5); | ||
314 | |||
315 | result = usb_control_msg(dev->usbdev, usb_sndctrlpipe(dev->usbdev, 0), | ||
316 | SUR40_POKE, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, | ||
317 | 0x17, setting_17[value], NULL, 0, 1000); | ||
318 | if (result < 0) | ||
319 | goto error; | ||
320 | msleep(5); | ||
321 | |||
322 | error: | ||
323 | return result; | ||
324 | } | ||
325 | |||
326 | static void sur40_set_vsvideo(struct sur40_state *handle, u8 value) | ||
327 | { | ||
328 | int i; | ||
329 | |||
330 | for (i = 0; i < 4; i++) | ||
331 | sur40_poke(handle, 0x1c+i, value); | ||
332 | handle->vsvideo = value; | ||
333 | } | ||
334 | |||
335 | static void sur40_set_irlevel(struct sur40_state *handle, u8 value) | ||
336 | { | ||
337 | int i; | ||
338 | |||
339 | for (i = 0; i < 8; i++) | ||
340 | sur40_poke(handle, 0x08+(2*i), value); | ||
341 | } | ||
342 | |||
223 | /* Initialization routine, called from sur40_open */ | 343 | /* Initialization routine, called from sur40_open */ |
224 | static int sur40_init(struct sur40_state *dev) | 344 | static int sur40_init(struct sur40_state *dev) |
225 | { | 345 | { |
@@ -631,6 +751,36 @@ static int sur40_probe(struct usb_interface *interface, | |||
631 | sur40->vdev.queue = &sur40->queue; | 751 | sur40->vdev.queue = &sur40->queue; |
632 | video_set_drvdata(&sur40->vdev, sur40); | 752 | video_set_drvdata(&sur40->vdev, sur40); |
633 | 753 | ||
754 | /* initialize the control handler for 4 controls */ | ||
755 | v4l2_ctrl_handler_init(&sur40->hdl, 4); | ||
756 | sur40->v4l2.ctrl_handler = &sur40->hdl; | ||
757 | sur40->vsvideo = (SUR40_CONTRAST_DEF << 4) | SUR40_GAIN_DEF; | ||
758 | |||
759 | v4l2_ctrl_new_std(&sur40->hdl, &sur40_ctrl_ops, V4L2_CID_BRIGHTNESS, | ||
760 | SUR40_BRIGHTNESS_MIN, SUR40_BRIGHTNESS_MAX, 1, clamp(brightness, | ||
761 | (uint)SUR40_BRIGHTNESS_MIN, (uint)SUR40_BRIGHTNESS_MAX)); | ||
762 | |||
763 | v4l2_ctrl_new_std(&sur40->hdl, &sur40_ctrl_ops, V4L2_CID_CONTRAST, | ||
764 | SUR40_CONTRAST_MIN, SUR40_CONTRAST_MAX, 1, clamp(contrast, | ||
765 | (uint)SUR40_CONTRAST_MIN, (uint)SUR40_CONTRAST_MAX)); | ||
766 | |||
767 | v4l2_ctrl_new_std(&sur40->hdl, &sur40_ctrl_ops, V4L2_CID_GAIN, | ||
768 | SUR40_GAIN_MIN, SUR40_GAIN_MAX, 1, clamp(gain, | ||
769 | (uint)SUR40_GAIN_MIN, (uint)SUR40_GAIN_MAX)); | ||
770 | |||
771 | v4l2_ctrl_new_std(&sur40->hdl, &sur40_ctrl_ops, | ||
772 | V4L2_CID_BACKLIGHT_COMPENSATION, SUR40_BACKLIGHT_MIN, | ||
773 | SUR40_BACKLIGHT_MAX, 1, SUR40_BACKLIGHT_DEF); | ||
774 | |||
775 | v4l2_ctrl_handler_setup(&sur40->hdl); | ||
776 | |||
777 | if (sur40->hdl.error) { | ||
778 | dev_err(&interface->dev, | ||
779 | "Unable to register video controls."); | ||
780 | v4l2_ctrl_handler_free(&sur40->hdl); | ||
781 | goto err_unreg_v4l2; | ||
782 | } | ||
783 | |||
634 | error = video_register_device(&sur40->vdev, VFL_TYPE_TOUCH, -1); | 784 | error = video_register_device(&sur40->vdev, VFL_TYPE_TOUCH, -1); |
635 | if (error) { | 785 | if (error) { |
636 | dev_err(&interface->dev, | 786 | dev_err(&interface->dev, |
@@ -663,6 +813,7 @@ static void sur40_disconnect(struct usb_interface *interface) | |||
663 | { | 813 | { |
664 | struct sur40_state *sur40 = usb_get_intfdata(interface); | 814 | struct sur40_state *sur40 = usb_get_intfdata(interface); |
665 | 815 | ||
816 | v4l2_ctrl_handler_free(&sur40->hdl); | ||
666 | video_unregister_device(&sur40->vdev); | 817 | video_unregister_device(&sur40->vdev); |
667 | v4l2_device_unregister(&sur40->v4l2); | 818 | v4l2_device_unregister(&sur40->v4l2); |
668 | 819 | ||
@@ -856,6 +1007,31 @@ static int sur40_vidioc_g_fmt(struct file *file, void *priv, | |||
856 | return 0; | 1007 | return 0; |
857 | } | 1008 | } |
858 | 1009 | ||
1010 | static int sur40_s_ctrl(struct v4l2_ctrl *ctrl) | ||
1011 | { | ||
1012 | struct sur40_state *sur40 = container_of(ctrl->handler, | ||
1013 | struct sur40_state, hdl); | ||
1014 | u8 value = sur40->vsvideo; | ||
1015 | |||
1016 | switch (ctrl->id) { | ||
1017 | case V4L2_CID_BRIGHTNESS: | ||
1018 | sur40_set_irlevel(sur40, ctrl->val); | ||
1019 | break; | ||
1020 | case V4L2_CID_CONTRAST: | ||
1021 | value = (value & 0x0f) | (ctrl->val << 4); | ||
1022 | sur40_set_vsvideo(sur40, value); | ||
1023 | break; | ||
1024 | case V4L2_CID_GAIN: | ||
1025 | value = (value & 0xf0) | (ctrl->val); | ||
1026 | sur40_set_vsvideo(sur40, value); | ||
1027 | break; | ||
1028 | case V4L2_CID_BACKLIGHT_COMPENSATION: | ||
1029 | sur40_set_preprocessor(sur40, ctrl->val); | ||
1030 | break; | ||
1031 | } | ||
1032 | return 0; | ||
1033 | } | ||
1034 | |||
859 | static int sur40_ioctl_parm(struct file *file, void *priv, | 1035 | static int sur40_ioctl_parm(struct file *file, void *priv, |
860 | struct v4l2_streamparm *p) | 1036 | struct v4l2_streamparm *p) |
861 | { | 1037 | { |