diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2009-03-13 05:08:20 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-03-30 11:43:22 -0400 |
commit | e958e27adeade7fa085dd396a8a0dfaef7e338c1 (patch) | |
tree | 3bba3d91531f778e54d380ec4ba099c7e86ccf8c /drivers/media/video/mt9v022.c | |
parent | 36034dc325ecab63c8cfb992fbf9a1a8e94738a2 (diff) |
V4L/DVB (11033): mt9v022: allow setting of bus width from board code
This patch removes the phytec specific setting of the bus width
and switches to the more generic query_bus_param/set_bus_param
hooks
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/mt9v022.c')
-rw-r--r-- | drivers/media/video/mt9v022.c | 141 |
1 files changed, 42 insertions, 99 deletions
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index 3871d4a2d8ff..4d3b4813c322 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c | |||
@@ -13,7 +13,6 @@ | |||
13 | #include <linux/i2c.h> | 13 | #include <linux/i2c.h> |
14 | #include <linux/delay.h> | 14 | #include <linux/delay.h> |
15 | #include <linux/log2.h> | 15 | #include <linux/log2.h> |
16 | #include <linux/gpio.h> | ||
17 | 16 | ||
18 | #include <media/v4l2-common.h> | 17 | #include <media/v4l2-common.h> |
19 | #include <media/v4l2-chip-ident.h> | 18 | #include <media/v4l2-chip-ident.h> |
@@ -89,9 +88,7 @@ struct mt9v022 { | |||
89 | struct i2c_client *client; | 88 | struct i2c_client *client; |
90 | struct soc_camera_device icd; | 89 | struct soc_camera_device icd; |
91 | int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */ | 90 | int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */ |
92 | int switch_gpio; | ||
93 | u16 chip_control; | 91 | u16 chip_control; |
94 | unsigned char datawidth; | ||
95 | }; | 92 | }; |
96 | 93 | ||
97 | static int reg_read(struct soc_camera_device *icd, const u8 reg) | 94 | static int reg_read(struct soc_camera_device *icd, const u8 reg) |
@@ -209,66 +206,6 @@ static int mt9v022_stop_capture(struct soc_camera_device *icd) | |||
209 | return 0; | 206 | return 0; |
210 | } | 207 | } |
211 | 208 | ||
212 | static int bus_switch_request(struct mt9v022 *mt9v022, struct soc_camera_link *icl) | ||
213 | { | ||
214 | #ifdef CONFIG_MT9V022_PCA9536_SWITCH | ||
215 | int ret; | ||
216 | unsigned int gpio = icl->gpio; | ||
217 | |||
218 | if (gpio_is_valid(gpio)) { | ||
219 | /* We have a data bus switch. */ | ||
220 | ret = gpio_request(gpio, "mt9v022"); | ||
221 | if (ret < 0) { | ||
222 | dev_err(&mt9v022->client->dev, "Cannot get GPIO %u\n", gpio); | ||
223 | return ret; | ||
224 | } | ||
225 | |||
226 | ret = gpio_direction_output(gpio, 0); | ||
227 | if (ret < 0) { | ||
228 | dev_err(&mt9v022->client->dev, | ||
229 | "Cannot set GPIO %u to output\n", gpio); | ||
230 | gpio_free(gpio); | ||
231 | return ret; | ||
232 | } | ||
233 | } | ||
234 | |||
235 | mt9v022->switch_gpio = gpio; | ||
236 | #else | ||
237 | mt9v022->switch_gpio = -EINVAL; | ||
238 | #endif | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static void bus_switch_release(struct mt9v022 *mt9v022) | ||
243 | { | ||
244 | #ifdef CONFIG_MT9V022_PCA9536_SWITCH | ||
245 | if (gpio_is_valid(mt9v022->switch_gpio)) | ||
246 | gpio_free(mt9v022->switch_gpio); | ||
247 | #endif | ||
248 | } | ||
249 | |||
250 | static int bus_switch_act(struct mt9v022 *mt9v022, int go8bit) | ||
251 | { | ||
252 | #ifdef CONFIG_MT9V022_PCA9536_SWITCH | ||
253 | if (!gpio_is_valid(mt9v022->switch_gpio)) | ||
254 | return -ENODEV; | ||
255 | |||
256 | gpio_set_value_cansleep(mt9v022->switch_gpio, go8bit); | ||
257 | return 0; | ||
258 | #else | ||
259 | return -ENODEV; | ||
260 | #endif | ||
261 | } | ||
262 | |||
263 | static int bus_switch_possible(struct mt9v022 *mt9v022) | ||
264 | { | ||
265 | #ifdef CONFIG_MT9V022_PCA9536_SWITCH | ||
266 | return gpio_is_valid(mt9v022->switch_gpio); | ||
267 | #else | ||
268 | return 0; | ||
269 | #endif | ||
270 | } | ||
271 | |||
272 | static int mt9v022_set_bus_param(struct soc_camera_device *icd, | 209 | static int mt9v022_set_bus_param(struct soc_camera_device *icd, |
273 | unsigned long flags) | 210 | unsigned long flags) |
274 | { | 211 | { |
@@ -282,19 +219,17 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd, | |||
282 | if (!is_power_of_2(width_flag)) | 219 | if (!is_power_of_2(width_flag)) |
283 | return -EINVAL; | 220 | return -EINVAL; |
284 | 221 | ||
285 | if ((mt9v022->datawidth != 10 && (width_flag == SOCAM_DATAWIDTH_10)) || | 222 | if (icl->set_bus_param) { |
286 | (mt9v022->datawidth != 9 && (width_flag == SOCAM_DATAWIDTH_9)) || | 223 | ret = icl->set_bus_param(icl, width_flag); |
287 | (mt9v022->datawidth != 8 && (width_flag == SOCAM_DATAWIDTH_8))) { | 224 | if (ret) |
288 | /* Well, we actually only can do 10 or 8 bits... */ | ||
289 | if (width_flag == SOCAM_DATAWIDTH_9) | ||
290 | return -EINVAL; | ||
291 | |||
292 | ret = bus_switch_act(mt9v022, | ||
293 | width_flag == SOCAM_DATAWIDTH_8); | ||
294 | if (ret < 0) | ||
295 | return ret; | 225 | return ret; |
296 | 226 | } else { | |
297 | mt9v022->datawidth = width_flag == SOCAM_DATAWIDTH_8 ? 8 : 10; | 227 | /* |
228 | * Without board specific bus width settings we only support the | ||
229 | * sensors native bus width | ||
230 | */ | ||
231 | if (width_flag != SOCAM_DATAWIDTH_10) | ||
232 | return -EINVAL; | ||
298 | } | 233 | } |
299 | 234 | ||
300 | flags = soc_camera_apply_sensor_flags(icl, flags); | 235 | flags = soc_camera_apply_sensor_flags(icl, flags); |
@@ -328,10 +263,14 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd, | |||
328 | static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd) | 263 | static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd) |
329 | { | 264 | { |
330 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); | 265 | struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); |
331 | unsigned int width_flag = SOCAM_DATAWIDTH_10; | 266 | struct soc_camera_link *icl = mt9v022->client->dev.platform_data; |
267 | unsigned int width_flag; | ||
332 | 268 | ||
333 | if (bus_switch_possible(mt9v022)) | 269 | if (icl->query_bus_param) |
334 | width_flag |= SOCAM_DATAWIDTH_8; | 270 | width_flag = icl->query_bus_param(icl) & |
271 | SOCAM_DATAWIDTH_MASK; | ||
272 | else | ||
273 | width_flag = SOCAM_DATAWIDTH_10; | ||
335 | 274 | ||
336 | return SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | | 275 | return SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | |
337 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW | | 276 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW | |
@@ -715,6 +654,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd) | |||
715 | struct soc_camera_link *icl = mt9v022->client->dev.platform_data; | 654 | struct soc_camera_link *icl = mt9v022->client->dev.platform_data; |
716 | s32 data; | 655 | s32 data; |
717 | int ret; | 656 | int ret; |
657 | unsigned long flags; | ||
718 | 658 | ||
719 | if (!icd->dev.parent || | 659 | if (!icd->dev.parent || |
720 | to_soc_camera_host(icd->dev.parent)->nr != icd->iface) | 660 | to_soc_camera_host(icd->dev.parent)->nr != icd->iface) |
@@ -748,22 +688,36 @@ static int mt9v022_video_probe(struct soc_camera_device *icd) | |||
748 | ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11); | 688 | ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11); |
749 | mt9v022->model = V4L2_IDENT_MT9V022IX7ATC; | 689 | mt9v022->model = V4L2_IDENT_MT9V022IX7ATC; |
750 | icd->formats = mt9v022_colour_formats; | 690 | icd->formats = mt9v022_colour_formats; |
751 | if (gpio_is_valid(icl->gpio)) | ||
752 | icd->num_formats = ARRAY_SIZE(mt9v022_colour_formats); | ||
753 | else | ||
754 | icd->num_formats = 1; | ||
755 | } else { | 691 | } else { |
756 | ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 0x11); | 692 | ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 0x11); |
757 | mt9v022->model = V4L2_IDENT_MT9V022IX7ATM; | 693 | mt9v022->model = V4L2_IDENT_MT9V022IX7ATM; |
758 | icd->formats = mt9v022_monochrome_formats; | 694 | icd->formats = mt9v022_monochrome_formats; |
759 | if (gpio_is_valid(icl->gpio)) | ||
760 | icd->num_formats = ARRAY_SIZE(mt9v022_monochrome_formats); | ||
761 | else | ||
762 | icd->num_formats = 1; | ||
763 | } | 695 | } |
764 | 696 | ||
765 | if (!ret) | 697 | if (ret < 0) |
766 | ret = soc_camera_video_start(icd); | 698 | goto eisis; |
699 | |||
700 | icd->num_formats = 0; | ||
701 | |||
702 | /* | ||
703 | * This is a 10bit sensor, so by default we only allow 10bit. | ||
704 | * The platform may support different bus widths due to | ||
705 | * different routing of the data lines. | ||
706 | */ | ||
707 | if (icl->query_bus_param) | ||
708 | flags = icl->query_bus_param(icl); | ||
709 | else | ||
710 | flags = SOCAM_DATAWIDTH_10; | ||
711 | |||
712 | if (flags & SOCAM_DATAWIDTH_10) | ||
713 | icd->num_formats++; | ||
714 | else | ||
715 | icd->formats++; | ||
716 | |||
717 | if (flags & SOCAM_DATAWIDTH_8) | ||
718 | icd->num_formats++; | ||
719 | |||
720 | ret = soc_camera_video_start(icd); | ||
767 | if (ret < 0) | 721 | if (ret < 0) |
768 | goto eisis; | 722 | goto eisis; |
769 | 723 | ||
@@ -828,14 +782,6 @@ static int mt9v022_probe(struct i2c_client *client, | |||
828 | icd->height_max = 480; | 782 | icd->height_max = 480; |
829 | icd->y_skip_top = 1; | 783 | icd->y_skip_top = 1; |
830 | icd->iface = icl->bus_id; | 784 | icd->iface = icl->bus_id; |
831 | /* Default datawidth - this is the only width this camera (normally) | ||
832 | * supports. It is only with extra logic that it can support | ||
833 | * other widths. Therefore it seems to be a sensible default. */ | ||
834 | mt9v022->datawidth = 10; | ||
835 | |||
836 | ret = bus_switch_request(mt9v022, icl); | ||
837 | if (ret) | ||
838 | goto eswinit; | ||
839 | 785 | ||
840 | ret = soc_camera_device_register(icd); | 786 | ret = soc_camera_device_register(icd); |
841 | if (ret) | 787 | if (ret) |
@@ -844,8 +790,6 @@ static int mt9v022_probe(struct i2c_client *client, | |||
844 | return 0; | 790 | return 0; |
845 | 791 | ||
846 | eisdr: | 792 | eisdr: |
847 | bus_switch_release(mt9v022); | ||
848 | eswinit: | ||
849 | kfree(mt9v022); | 793 | kfree(mt9v022); |
850 | return ret; | 794 | return ret; |
851 | } | 795 | } |
@@ -855,7 +799,6 @@ static int mt9v022_remove(struct i2c_client *client) | |||
855 | struct mt9v022 *mt9v022 = i2c_get_clientdata(client); | 799 | struct mt9v022 *mt9v022 = i2c_get_clientdata(client); |
856 | 800 | ||
857 | soc_camera_device_unregister(&mt9v022->icd); | 801 | soc_camera_device_unregister(&mt9v022->icd); |
858 | bus_switch_release(mt9v022); | ||
859 | kfree(mt9v022); | 802 | kfree(mt9v022); |
860 | 803 | ||
861 | return 0; | 804 | return 0; |