diff options
author | Koen Kooi <koen@dominion.thruhere.net> | 2011-05-25 09:32:34 +0200 |
---|---|---|
committer | Koen Kooi <koen@dominion.thruhere.net> | 2011-05-25 09:32:34 +0200 |
commit | dd301f06bddd9527185f51a3cf6859495923e64e (patch) | |
tree | f1324f3fddcf9a7bcc4c6c41f79141194acc369d /recipes-kernel/linux/linux-omap-2.6.39 | |
parent | cf911bc4329a2fada6d8b4ba4b7d8865b41a9f92 (diff) | |
download | meta-ti-dd301f06bddd9527185f51a3cf6859495923e64e.tar.gz |
linux-omap 2.6.39: add sensor driver for aptina 5MP and 1GHz hack for beagle
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
Diffstat (limited to 'recipes-kernel/linux/linux-omap-2.6.39')
7 files changed, 1060 insertions, 38 deletions
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/beagle/0001-OMAP3-beagle-add-support-for-beagleboard-xM-revision.patch b/recipes-kernel/linux/linux-omap-2.6.39/beagle/0001-OMAP3-beagle-add-support-for-beagleboard-xM-revision.patch index 0744729b..30063f9d 100644 --- a/recipes-kernel/linux/linux-omap-2.6.39/beagle/0001-OMAP3-beagle-add-support-for-beagleboard-xM-revision.patch +++ b/recipes-kernel/linux/linux-omap-2.6.39/beagle/0001-OMAP3-beagle-add-support-for-beagleboard-xM-revision.patch | |||
@@ -1,17 +1,17 @@ | |||
1 | From 8fc22425fa39908fd4a9a0f1954b66fecaf2058a Mon Sep 17 00:00:00 2001 | 1 | From 2dd4bf287ad066e3d9e82c239782fb649c6f7fe7 Mon Sep 17 00:00:00 2001 |
2 | From: Koen Kooi <koen@dominion.thruhere.net> | 2 | From: Koen Kooi <koen@dominion.thruhere.net> |
3 | Date: Fri, 20 May 2011 12:48:37 +0200 | 3 | Date: Fri, 20 May 2011 12:48:37 +0200 |
4 | Subject: [PATCH 1/3] OMAP3: beagle: add support for beagleboard xM revision C | 4 | Subject: [PATCH 1/5] OMAP3: beagle: add support for beagleboard xM revision C |
5 | 5 | ||
6 | The USB enable GPIO has been inverted and the USER button moved. | 6 | The USB enable GPIO has been inverted and the USER button moved. |
7 | 7 | ||
8 | Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> | 8 | Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> |
9 | --- | 9 | --- |
10 | arch/arm/mach-omap2/board-omap3beagle.c | 32 +++++++++++++++++++++++------- | 10 | arch/arm/mach-omap2/board-omap3beagle.c | 34 +++++++++++++++++++++++------- |
11 | 1 files changed, 24 insertions(+), 8 deletions(-) | 11 | 1 files changed, 26 insertions(+), 8 deletions(-) |
12 | 12 | ||
13 | diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c | 13 | diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c |
14 | index 2de4b02..1eb1e8e 100644 | 14 | index 2de4b02..77bafa8 100644 |
15 | --- a/arch/arm/mach-omap2/board-omap3beagle.c | 15 | --- a/arch/arm/mach-omap2/board-omap3beagle.c |
16 | +++ b/arch/arm/mach-omap2/board-omap3beagle.c | 16 | +++ b/arch/arm/mach-omap2/board-omap3beagle.c |
17 | @@ -62,7 +62,9 @@ | 17 | @@ -62,7 +62,9 @@ |
@@ -33,7 +33,7 @@ index 2de4b02..1eb1e8e 100644 | |||
33 | }; | 33 | }; |
34 | 34 | ||
35 | static u8 omap3_beagle_version; | 35 | static u8 omap3_beagle_version; |
36 | @@ -124,9 +127,17 @@ static void __init omap3_beagle_init_rev(void) | 36 | @@ -124,9 +127,18 @@ static void __init omap3_beagle_init_rev(void) |
37 | printk(KERN_INFO "OMAP3 Beagle Rev: xM\n"); | 37 | printk(KERN_INFO "OMAP3 Beagle Rev: xM\n"); |
38 | omap3_beagle_version = OMAP3BEAGLE_BOARD_XM; | 38 | omap3_beagle_version = OMAP3BEAGLE_BOARD_XM; |
39 | break; | 39 | break; |
@@ -48,57 +48,59 @@ index 2de4b02..1eb1e8e 100644 | |||
48 | default: | 48 | default: |
49 | - printk(KERN_INFO "OMAP3 Beagle Rev: unknown %hd\n", beagle_rev); | 49 | - printk(KERN_INFO "OMAP3 Beagle Rev: unknown %hd\n", beagle_rev); |
50 | - omap3_beagle_version = OMAP3BEAGLE_BOARD_UNKN; | 50 | - omap3_beagle_version = OMAP3BEAGLE_BOARD_UNKN; |
51 | + printk(KERN_INFO "OMAP3 Beagle Rev: unknown %hd, assuming xM C or newer\n", beagle_rev); | 51 | + printk(KERN_INFO |
52 | + "OMAP3 Beagle Rev: unknown %hd, assuming xM C or newer\n", beagle_rev); | ||
52 | + omap3_beagle_version = OMAP3BEAGLE_BOARD_XMC; | 53 | + omap3_beagle_version = OMAP3BEAGLE_BOARD_XMC; |
53 | } | 54 | } |
54 | 55 | ||
55 | return; | 56 | return; |
56 | @@ -278,7 +289,7 @@ static int beagle_twl_gpio_setup(struct device *dev, | 57 | @@ -278,7 +290,7 @@ static int beagle_twl_gpio_setup(struct device *dev, |
57 | { | 58 | { |
58 | int r; | 59 | int r; |
59 | 60 | ||
60 | - if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) { | 61 | - if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) { |
61 | + if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM || omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XMC) { | 62 | + if (cpu_is_omap3630()) { |
62 | mmc[0].gpio_wp = -EINVAL; | 63 | mmc[0].gpio_wp = -EINVAL; |
63 | } else if ((omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_C1_3) || | 64 | } else if ((omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_C1_3) || |
64 | (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_C4)) { | 65 | (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_C4)) { |
65 | @@ -298,7 +309,7 @@ static int beagle_twl_gpio_setup(struct device *dev, | 66 | @@ -298,7 +310,8 @@ static int beagle_twl_gpio_setup(struct device *dev, |
66 | /* REVISIT: need ehci-omap hooks for external VBUS | 67 | /* REVISIT: need ehci-omap hooks for external VBUS |
67 | * power switch and overcurrent detect | 68 | * power switch and overcurrent detect |
68 | */ | 69 | */ |
69 | - if (omap3_beagle_get_rev() != OMAP3BEAGLE_BOARD_XM) { | 70 | - if (omap3_beagle_get_rev() != OMAP3BEAGLE_BOARD_XM) { |
70 | + if (omap3_beagle_get_rev() != OMAP3BEAGLE_BOARD_XM && omap3_beagle_get_rev() != OMAP3BEAGLE_BOARD_XMC) { | 71 | + if (omap3_beagle_get_rev() != OMAP3BEAGLE_BOARD_XM |
72 | + && omap3_beagle_get_rev() != OMAP3BEAGLE_BOARD_XMC) { | ||
71 | r = gpio_request(gpio + 1, "EHCI_nOC"); | 73 | r = gpio_request(gpio + 1, "EHCI_nOC"); |
72 | if (!r) { | 74 | if (!r) { |
73 | r = gpio_direction_input(gpio + 1); | 75 | r = gpio_direction_input(gpio + 1); |
74 | @@ -320,7 +331,7 @@ static int beagle_twl_gpio_setup(struct device *dev, | 76 | @@ -320,7 +333,7 @@ static int beagle_twl_gpio_setup(struct device *dev, |
75 | gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0); | 77 | gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0); |
76 | 78 | ||
77 | /* DVI reset GPIO is different between beagle revisions */ | 79 | /* DVI reset GPIO is different between beagle revisions */ |
78 | - if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) | 80 | - if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) |
79 | + if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM || omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XMC) | 81 | + if (cpu_is_omap3630()) |
80 | beagle_dvi_device.reset_gpio = 129; | 82 | beagle_dvi_device.reset_gpio = 129; |
81 | else | 83 | else |
82 | beagle_dvi_device.reset_gpio = 170; | 84 | beagle_dvi_device.reset_gpio = 170; |
83 | @@ -334,7 +345,7 @@ static int beagle_twl_gpio_setup(struct device *dev, | 85 | @@ -334,7 +347,7 @@ static int beagle_twl_gpio_setup(struct device *dev, |
84 | * P7/P8 revisions(prototype): Camera EN | 86 | * P7/P8 revisions(prototype): Camera EN |
85 | * A2+ revisions (production): LDO (supplies DVI, serial, led blocks) | 87 | * A2+ revisions (production): LDO (supplies DVI, serial, led blocks) |
86 | */ | 88 | */ |
87 | - if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) { | 89 | - if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) { |
88 | + if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM || omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XMC) { | 90 | + if (cpu_is_omap3630()) { |
89 | r = gpio_request(gpio + 1, "nDVI_PWR_EN"); | 91 | r = gpio_request(gpio + 1, "nDVI_PWR_EN"); |
90 | if (!r) { | 92 | if (!r) { |
91 | r = gpio_direction_output(gpio + 1, 0); | 93 | r = gpio_direction_output(gpio + 1, 0); |
92 | @@ -625,7 +636,7 @@ static void __init beagle_opp_init(void) | 94 | @@ -625,7 +638,7 @@ static void __init beagle_opp_init(void) |
93 | } | 95 | } |
94 | 96 | ||
95 | /* Custom OPP enabled for XM */ | 97 | /* Custom OPP enabled for XM */ |
96 | - if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) { | 98 | - if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) { |
97 | + if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM || omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XMC) { | 99 | + if (cpu_is_omap3630()) { |
98 | struct omap_hwmod *mh = omap_hwmod_lookup("mpu"); | 100 | struct omap_hwmod *mh = omap_hwmod_lookup("mpu"); |
99 | struct omap_hwmod *dh = omap_hwmod_lookup("iva"); | 101 | struct omap_hwmod *dh = omap_hwmod_lookup("iva"); |
100 | struct device *dev; | 102 | struct device *dev; |
101 | @@ -665,6 +676,11 @@ static void __init omap3_beagle_init(void) | 103 | @@ -665,6 +678,11 @@ static void __init omap3_beagle_init(void) |
102 | omap3_mux_init(board_mux, OMAP_PACKAGE_CBB); | 104 | omap3_mux_init(board_mux, OMAP_PACKAGE_CBB); |
103 | omap3_beagle_init_rev(); | 105 | omap3_beagle_init_rev(); |
104 | omap3_beagle_i2c_init(); | 106 | omap3_beagle_i2c_init(); |
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/beagle/0002-OMAP3-beagle-add-support-for-expansionboards.patch b/recipes-kernel/linux/linux-omap-2.6.39/beagle/0002-OMAP3-beagle-add-support-for-expansionboards.patch index 74c731f9..f815a58a 100644 --- a/recipes-kernel/linux/linux-omap-2.6.39/beagle/0002-OMAP3-beagle-add-support-for-expansionboards.patch +++ b/recipes-kernel/linux/linux-omap-2.6.39/beagle/0002-OMAP3-beagle-add-support-for-expansionboards.patch | |||
@@ -1,7 +1,7 @@ | |||
1 | From 4757e98441d91244c5b1429bdc3d8771e78bb478 Mon Sep 17 00:00:00 2001 | 1 | From 258a21a495a9ba2238081cd473b4796cd61a60e7 Mon Sep 17 00:00:00 2001 |
2 | From: Koen Kooi <koen@dominion.thruhere.net> | 2 | From: Koen Kooi <koen@dominion.thruhere.net> |
3 | Date: Fri, 20 May 2011 13:06:24 +0200 | 3 | Date: Fri, 20 May 2011 13:06:24 +0200 |
4 | Subject: [PATCH 2/3] OMAP3: beagle: add support for expansionboards | 4 | Subject: [PATCH 2/5] OMAP3: beagle: add support for expansionboards |
5 | 5 | ||
6 | Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> | 6 | Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> |
7 | --- | 7 | --- |
@@ -9,7 +9,7 @@ Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> | |||
9 | 1 files changed, 269 insertions(+), 3 deletions(-) | 9 | 1 files changed, 269 insertions(+), 3 deletions(-) |
10 | 10 | ||
11 | diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c | 11 | diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c |
12 | index 1eb1e8e..70ed6f3 100644 | 12 | index 77bafa8..db285e1 100644 |
13 | --- a/arch/arm/mach-omap2/board-omap3beagle.c | 13 | --- a/arch/arm/mach-omap2/board-omap3beagle.c |
14 | +++ b/arch/arm/mach-omap2/board-omap3beagle.c | 14 | +++ b/arch/arm/mach-omap2/board-omap3beagle.c |
15 | @@ -21,6 +21,7 @@ | 15 | @@ -21,6 +21,7 @@ |
@@ -20,7 +20,7 @@ index 1eb1e8e..70ed6f3 100644 | |||
20 | #include <linux/input.h> | 20 | #include <linux/input.h> |
21 | #include <linux/gpio_keys.h> | 21 | #include <linux/gpio_keys.h> |
22 | #include <linux/opp.h> | 22 | #include <linux/opp.h> |
23 | @@ -153,6 +154,167 @@ fail0: | 23 | @@ -154,6 +155,167 @@ fail0: |
24 | return; | 24 | return; |
25 | } | 25 | } |
26 | 26 | ||
@@ -188,7 +188,7 @@ index 1eb1e8e..70ed6f3 100644 | |||
188 | static struct mtd_partition omap3beagle_nand_partitions[] = { | 188 | static struct mtd_partition omap3beagle_nand_partitions[] = { |
189 | /* All the partition sizes are listed in terms of NAND block size */ | 189 | /* All the partition sizes are listed in terms of NAND block size */ |
190 | { | 190 | { |
191 | @@ -271,6 +433,12 @@ static struct omap2_hsmmc_info mmc[] = { | 191 | @@ -272,6 +434,12 @@ static struct omap2_hsmmc_info mmc[] = { |
192 | .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA, | 192 | .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA, |
193 | .gpio_wp = 29, | 193 | .gpio_wp = 29, |
194 | }, | 194 | }, |
@@ -201,7 +201,7 @@ index 1eb1e8e..70ed6f3 100644 | |||
201 | {} /* Terminator */ | 201 | {} /* Terminator */ |
202 | }; | 202 | }; |
203 | 203 | ||
204 | @@ -300,11 +468,25 @@ static int beagle_twl_gpio_setup(struct device *dev, | 204 | @@ -301,11 +469,25 @@ static int beagle_twl_gpio_setup(struct device *dev, |
205 | } | 205 | } |
206 | /* gpio + 0 is "mmc0_cd" (input/IRQ) */ | 206 | /* gpio + 0 is "mmc0_cd" (input/IRQ) */ |
207 | mmc[0].gpio_cd = gpio + 0; | 207 | mmc[0].gpio_cd = gpio + 0; |
@@ -227,7 +227,7 @@ index 1eb1e8e..70ed6f3 100644 | |||
227 | 227 | ||
228 | /* REVISIT: need ehci-omap hooks for external VBUS | 228 | /* REVISIT: need ehci-omap hooks for external VBUS |
229 | * power switch and overcurrent detect | 229 | * power switch and overcurrent detect |
230 | @@ -464,7 +646,7 @@ static struct twl4030_platform_data beagle_twldata = { | 230 | @@ -466,7 +648,7 @@ static struct twl4030_platform_data beagle_twldata = { |
231 | .vpll2 = &beagle_vpll2, | 231 | .vpll2 = &beagle_vpll2, |
232 | }; | 232 | }; |
233 | 233 | ||
@@ -236,7 +236,7 @@ index 1eb1e8e..70ed6f3 100644 | |||
236 | { | 236 | { |
237 | I2C_BOARD_INFO("twl4030", 0x48), | 237 | I2C_BOARD_INFO("twl4030", 0x48), |
238 | .flags = I2C_CLIENT_WAKE, | 238 | .flags = I2C_CLIENT_WAKE, |
239 | @@ -479,10 +661,24 @@ static struct i2c_board_info __initdata beagle_i2c_eeprom[] = { | 239 | @@ -481,10 +663,24 @@ static struct i2c_board_info __initdata beagle_i2c_eeprom[] = { |
240 | }, | 240 | }, |
241 | }; | 241 | }; |
242 | 242 | ||
@@ -263,7 +263,7 @@ index 1eb1e8e..70ed6f3 100644 | |||
263 | /* Bus 3 is attached to the DVI port where devices like the pico DLP | 263 | /* Bus 3 is attached to the DVI port where devices like the pico DLP |
264 | * projector don't work reliably with 400kHz */ | 264 | * projector don't work reliably with 400kHz */ |
265 | omap_register_i2c_bus(3, 100, beagle_i2c_eeprom, ARRAY_SIZE(beagle_i2c_eeprom)); | 265 | omap_register_i2c_bus(3, 100, beagle_i2c_eeprom, ARRAY_SIZE(beagle_i2c_eeprom)); |
266 | @@ -625,6 +821,15 @@ static struct omap_musb_board_data musb_board_data = { | 266 | @@ -627,6 +823,15 @@ static struct omap_musb_board_data musb_board_data = { |
267 | .power = 100, | 267 | .power = 100, |
268 | }; | 268 | }; |
269 | 269 | ||
@@ -279,7 +279,7 @@ index 1eb1e8e..70ed6f3 100644 | |||
279 | static void __init beagle_opp_init(void) | 279 | static void __init beagle_opp_init(void) |
280 | { | 280 | { |
281 | int r = 0; | 281 | int r = 0; |
282 | @@ -691,6 +896,65 @@ static void __init omap3_beagle_init(void) | 282 | @@ -693,6 +898,65 @@ static void __init omap3_beagle_init(void) |
283 | /* REVISIT leave DVI powered down until it's needed ... */ | 283 | /* REVISIT leave DVI powered down until it's needed ... */ |
284 | gpio_direction_output(170, true); | 284 | gpio_direction_output(170, true); |
285 | 285 | ||
@@ -345,7 +345,7 @@ index 1eb1e8e..70ed6f3 100644 | |||
345 | usb_musb_init(&musb_board_data); | 345 | usb_musb_init(&musb_board_data); |
346 | usbhs_init(&usbhs_bdata); | 346 | usbhs_init(&usbhs_bdata); |
347 | omap3beagle_flash_init(); | 347 | omap3beagle_flash_init(); |
348 | @@ -703,6 +967,8 @@ static void __init omap3_beagle_init(void) | 348 | @@ -705,6 +969,8 @@ static void __init omap3_beagle_init(void) |
349 | beagle_opp_init(); | 349 | beagle_opp_init(); |
350 | } | 350 | } |
351 | 351 | ||
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/beagle/0003-OMAP3-beagle-add-MADC-support.patch b/recipes-kernel/linux/linux-omap-2.6.39/beagle/0003-OMAP3-beagle-add-MADC-support.patch index 80a47e68..0f5c0bd5 100644 --- a/recipes-kernel/linux/linux-omap-2.6.39/beagle/0003-OMAP3-beagle-add-MADC-support.patch +++ b/recipes-kernel/linux/linux-omap-2.6.39/beagle/0003-OMAP3-beagle-add-MADC-support.patch | |||
@@ -1,7 +1,7 @@ | |||
1 | From cfa62e807901f04bfd0e9f38a283ac974ff3d888 Mon Sep 17 00:00:00 2001 | 1 | From b6deb9a9c3a0c8b9afc981cbca20ff73fa7a8d8c Mon Sep 17 00:00:00 2001 |
2 | From: Koen Kooi <koen@dominion.thruhere.net> | 2 | From: Koen Kooi <koen@dominion.thruhere.net> |
3 | Date: Sat, 21 May 2011 16:18:30 +0200 | 3 | Date: Sat, 21 May 2011 16:18:30 +0200 |
4 | Subject: [PATCH 3/3] OMAP3: beagle: add MADC support | 4 | Subject: [PATCH 3/5] OMAP3: beagle: add MADC support |
5 | 5 | ||
6 | Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> | 6 | Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> |
7 | --- | 7 | --- |
@@ -9,10 +9,10 @@ Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> | |||
9 | 1 files changed, 5 insertions(+), 0 deletions(-) | 9 | 1 files changed, 5 insertions(+), 0 deletions(-) |
10 | 10 | ||
11 | diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c | 11 | diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c |
12 | index 70ed6f3..aa7849a 100644 | 12 | index db285e1..da4ba50 100644 |
13 | --- a/arch/arm/mach-omap2/board-omap3beagle.c | 13 | --- a/arch/arm/mach-omap2/board-omap3beagle.c |
14 | +++ b/arch/arm/mach-omap2/board-omap3beagle.c | 14 | +++ b/arch/arm/mach-omap2/board-omap3beagle.c |
15 | @@ -632,6 +632,10 @@ static struct twl4030_codec_data beagle_codec_data = { | 15 | @@ -634,6 +634,10 @@ static struct twl4030_codec_data beagle_codec_data = { |
16 | .audio = &beagle_audio_data, | 16 | .audio = &beagle_audio_data, |
17 | }; | 17 | }; |
18 | 18 | ||
@@ -23,7 +23,7 @@ index 70ed6f3..aa7849a 100644 | |||
23 | static struct twl4030_platform_data beagle_twldata = { | 23 | static struct twl4030_platform_data beagle_twldata = { |
24 | .irq_base = TWL4030_IRQ_BASE, | 24 | .irq_base = TWL4030_IRQ_BASE, |
25 | .irq_end = TWL4030_IRQ_END, | 25 | .irq_end = TWL4030_IRQ_END, |
26 | @@ -640,6 +644,7 @@ static struct twl4030_platform_data beagle_twldata = { | 26 | @@ -642,6 +646,7 @@ static struct twl4030_platform_data beagle_twldata = { |
27 | .usb = &beagle_usb_data, | 27 | .usb = &beagle_usb_data, |
28 | .gpio = &beagle_gpio_data, | 28 | .gpio = &beagle_gpio_data, |
29 | .codec = &beagle_codec_data, | 29 | .codec = &beagle_codec_data, |
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/beagle/0004-OMAP3-beagle-add-regulators-for-camera-interface.patch b/recipes-kernel/linux/linux-omap-2.6.39/beagle/0004-OMAP3-beagle-add-regulators-for-camera-interface.patch new file mode 100644 index 00000000..900502d2 --- /dev/null +++ b/recipes-kernel/linux/linux-omap-2.6.39/beagle/0004-OMAP3-beagle-add-regulators-for-camera-interface.patch | |||
@@ -0,0 +1,71 @@ | |||
1 | From 0ba8b335b9dd023784ef493b524d6335bfcd453a Mon Sep 17 00:00:00 2001 | ||
2 | From: Koen Kooi <koen@dominion.thruhere.net> | ||
3 | Date: Wed, 25 May 2011 08:56:06 +0200 | ||
4 | Subject: [PATCH 4/5] OMAP3: beagle: add regulators for camera interface | ||
5 | |||
6 | Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> | ||
7 | --- | ||
8 | arch/arm/mach-omap2/board-omap3beagle.c | 40 +++++++++++++++++++++++++++++++ | ||
9 | 1 files changed, 40 insertions(+), 0 deletions(-) | ||
10 | |||
11 | diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c | ||
12 | index da4ba50..52ea11a 100644 | ||
13 | --- a/arch/arm/mach-omap2/board-omap3beagle.c | ||
14 | +++ b/arch/arm/mach-omap2/board-omap3beagle.c | ||
15 | @@ -453,6 +453,44 @@ static struct regulator_consumer_supply beagle_vsim_supply = { | ||
16 | |||
17 | static struct gpio_led gpio_leds[]; | ||
18 | |||
19 | +static struct regulator_consumer_supply beagle_vaux3_supply = { | ||
20 | + .supply = "cam_1v8", | ||
21 | +}; | ||
22 | + | ||
23 | +static struct regulator_consumer_supply beagle_vaux4_supply = { | ||
24 | + .supply = "cam_2v8", | ||
25 | +}; | ||
26 | + | ||
27 | +/* VAUX3 for CAM_1V8 */ | ||
28 | +static struct regulator_init_data beagle_vaux3 = { | ||
29 | + .constraints = { | ||
30 | + .min_uV = 1800000, | ||
31 | + .max_uV = 1800000, | ||
32 | + .apply_uV = true, | ||
33 | + .valid_modes_mask = REGULATOR_MODE_NORMAL | ||
34 | + | REGULATOR_MODE_STANDBY, | ||
35 | + .valid_ops_mask = REGULATOR_CHANGE_MODE | ||
36 | + | REGULATOR_CHANGE_STATUS, | ||
37 | + }, | ||
38 | + .num_consumer_supplies = 1, | ||
39 | + .consumer_supplies = &beagle_vaux3_supply, | ||
40 | +}; | ||
41 | + | ||
42 | +/* VAUX4 for CAM_2V8 */ | ||
43 | +static struct regulator_init_data beagle_vaux4 = { | ||
44 | + .constraints = { | ||
45 | + .min_uV = 1800000, | ||
46 | + .max_uV = 1800000, | ||
47 | + .apply_uV = true, | ||
48 | + .valid_modes_mask = REGULATOR_MODE_NORMAL | ||
49 | + | REGULATOR_MODE_STANDBY, | ||
50 | + .valid_ops_mask = REGULATOR_CHANGE_MODE | ||
51 | + | REGULATOR_CHANGE_STATUS, | ||
52 | + }, | ||
53 | + .num_consumer_supplies = 1, | ||
54 | + .consumer_supplies = &beagle_vaux4_supply, | ||
55 | +}; | ||
56 | + | ||
57 | static int beagle_twl_gpio_setup(struct device *dev, | ||
58 | unsigned gpio, unsigned ngpio) | ||
59 | { | ||
60 | @@ -651,6 +689,8 @@ static struct twl4030_platform_data beagle_twldata = { | ||
61 | .vsim = &beagle_vsim, | ||
62 | .vdac = &beagle_vdac, | ||
63 | .vpll2 = &beagle_vpll2, | ||
64 | + .vaux3 = &beagle_vaux3, | ||
65 | + .vaux4 = &beagle_vaux4, | ||
66 | }; | ||
67 | |||
68 | static struct i2c_board_info __initdata beagle_i2c1_boardinfo[] = { | ||
69 | -- | ||
70 | 1.6.6.1 | ||
71 | |||
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/beagle/0005-OMAP3-beagle-HACK-add-in-1GHz-OPP.patch b/recipes-kernel/linux/linux-omap-2.6.39/beagle/0005-OMAP3-beagle-HACK-add-in-1GHz-OPP.patch new file mode 100644 index 00000000..a555c931 --- /dev/null +++ b/recipes-kernel/linux/linux-omap-2.6.39/beagle/0005-OMAP3-beagle-HACK-add-in-1GHz-OPP.patch | |||
@@ -0,0 +1,31 @@ | |||
1 | From 5b0f364b7e017d422b01c0e3297d0b68119f95f0 Mon Sep 17 00:00:00 2001 | ||
2 | From: Koen Kooi <koen@dominion.thruhere.net> | ||
3 | Date: Wed, 25 May 2011 08:57:40 +0200 | ||
4 | Subject: [PATCH 5/5] OMAP3: beagle: HACK! add in 1GHz OPP | ||
5 | |||
6 | Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> | ||
7 | --- | ||
8 | arch/arm/mach-omap2/board-omap3beagle.c | 2 ++ | ||
9 | 1 files changed, 2 insertions(+), 0 deletions(-) | ||
10 | |||
11 | diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c | ||
12 | index 52ea11a..cf95173 100644 | ||
13 | --- a/arch/arm/mach-omap2/board-omap3beagle.c | ||
14 | +++ b/arch/arm/mach-omap2/board-omap3beagle.c | ||
15 | @@ -901,11 +901,13 @@ static void __init beagle_opp_init(void) | ||
16 | /* Enable MPU 1GHz and lower opps */ | ||
17 | dev = &mh->od->pdev.dev; | ||
18 | r = opp_enable(dev, 800000000); | ||
19 | + r |= opp_enable(dev, 1000000000); | ||
20 | /* TODO: MPU 1GHz needs SR and ABB */ | ||
21 | |||
22 | /* Enable IVA 800MHz and lower opps */ | ||
23 | dev = &dh->od->pdev.dev; | ||
24 | r |= opp_enable(dev, 660000000); | ||
25 | + r |= opp_enable(dev, 800000000); | ||
26 | /* TODO: DSP 800MHz needs SR and ABB */ | ||
27 | if (r) { | ||
28 | pr_err("%s: failed to enable higher opp %d\n", | ||
29 | -- | ||
30 | 1.6.6.1 | ||
31 | |||
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/beagleboard/defconfig b/recipes-kernel/linux/linux-omap-2.6.39/beagleboard/defconfig index ad327cac..e2502650 100644 --- a/recipes-kernel/linux/linux-omap-2.6.39/beagleboard/defconfig +++ b/recipes-kernel/linux/linux-omap-2.6.39/beagleboard/defconfig | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Automatically generated make config: don't edit | 2 | # Automatically generated make config: don't edit |
3 | # Linux/arm 2.6.39 Kernel Configuration | 3 | # Linux/arm 2.6.39 Kernel Configuration |
4 | # Mon May 23 13:05:03 2011 | 4 | # Wed May 25 09:25:56 2011 |
5 | # | 5 | # |
6 | CONFIG_ARM=y | 6 | CONFIG_ARM=y |
7 | CONFIG_HAVE_PWM=y | 7 | CONFIG_HAVE_PWM=y |
@@ -460,13 +460,13 @@ CONFIG_AUTO_ZRELADDR=y | |||
460 | # | 460 | # |
461 | CONFIG_CPU_FREQ=y | 461 | CONFIG_CPU_FREQ=y |
462 | CONFIG_CPU_FREQ_TABLE=y | 462 | CONFIG_CPU_FREQ_TABLE=y |
463 | CONFIG_CPU_FREQ_DEBUG=y | 463 | # CONFIG_CPU_FREQ_DEBUG is not set |
464 | CONFIG_CPU_FREQ_STAT=y | 464 | CONFIG_CPU_FREQ_STAT=y |
465 | CONFIG_CPU_FREQ_STAT_DETAILS=y | 465 | CONFIG_CPU_FREQ_STAT_DETAILS=y |
466 | CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y | 466 | # CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set |
467 | # CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set | 467 | # CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set |
468 | # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set | 468 | # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set |
469 | # CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set | 469 | CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y |
470 | # CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set | 470 | # CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set |
471 | # CONFIG_CPU_FREQ_DEFAULT_GOV_HOTPLUG is not set | 471 | # CONFIG_CPU_FREQ_DEFAULT_GOV_HOTPLUG is not set |
472 | CONFIG_CPU_FREQ_GOV_PERFORMANCE=y | 472 | CONFIG_CPU_FREQ_GOV_PERFORMANCE=y |
@@ -2041,6 +2041,7 @@ CONFIG_VIDEO_ADV7180=m | |||
2041 | # CONFIG_VIDEO_BT866 is not set | 2041 | # CONFIG_VIDEO_BT866 is not set |
2042 | # CONFIG_VIDEO_KS0127 is not set | 2042 | # CONFIG_VIDEO_KS0127 is not set |
2043 | CONFIG_VIDEO_OV7670=m | 2043 | CONFIG_VIDEO_OV7670=m |
2044 | CONFIG_VIDEO_MT9P031=m | ||
2044 | CONFIG_VIDEO_MT9V011=m | 2045 | CONFIG_VIDEO_MT9V011=m |
2045 | # CONFIG_VIDEO_TCM825X is not set | 2046 | # CONFIG_VIDEO_TCM825X is not set |
2046 | # CONFIG_VIDEO_SAA7110 is not set | 2047 | # CONFIG_VIDEO_SAA7110 is not set |
diff --git a/recipes-kernel/linux/linux-omap-2.6.39/camera/0001-Add-mt9p031-sensor-support.patch b/recipes-kernel/linux/linux-omap-2.6.39/camera/0001-Add-mt9p031-sensor-support.patch new file mode 100644 index 00000000..2d7ee7ae --- /dev/null +++ b/recipes-kernel/linux/linux-omap-2.6.39/camera/0001-Add-mt9p031-sensor-support.patch | |||
@@ -0,0 +1,917 @@ | |||
1 | From 69f7b0ee14f046e469d616611ee87836e04219b4 Mon Sep 17 00:00:00 2001 | ||
2 | From: Javier Martin <javier.martin@vista-silicon.com> | ||
3 | Date: Tue, 24 May 2011 16:30:43 +0200 | ||
4 | Subject: [PATCH] Add mt9p031 sensor support. | ||
5 | |||
6 | This RFC includes a power management implementation that causes | ||
7 | the sensor to show images with horizontal artifacts (usually | ||
8 | monochrome lines that appear on the image randomly). | ||
9 | |||
10 | Signed-off-by: Javier Martin <javier.martin@vista-silicon.com> | ||
11 | Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> | ||
12 | --- | ||
13 | drivers/media/video/Kconfig | 7 + | ||
14 | drivers/media/video/Makefile | 1 + | ||
15 | drivers/media/video/mt9p031.c | 841 +++++++++++++++++++++++++++++++++++++++++ | ||
16 | include/media/mt9p031.h | 11 + | ||
17 | 4 files changed, 860 insertions(+), 0 deletions(-) | ||
18 | create mode 100644 drivers/media/video/mt9p031.c | ||
19 | create mode 100644 include/media/mt9p031.h | ||
20 | |||
21 | diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig | ||
22 | index 00f51dd..8a596cc 100644 | ||
23 | --- a/drivers/media/video/Kconfig | ||
24 | +++ b/drivers/media/video/Kconfig | ||
25 | @@ -329,6 +329,13 @@ config VIDEO_OV7670 | ||
26 | OV7670 VGA camera. It currently only works with the M88ALP01 | ||
27 | controller. | ||
28 | |||
29 | +config VIDEO_MT9P031 | ||
30 | + tristate "Aptina MT9P031 support" | ||
31 | + depends on I2C && VIDEO_V4L2 | ||
32 | + ---help--- | ||
33 | + This is a Video4Linux2 sensor-level driver for the Aptina | ||
34 | + (Micron) mt9p031 5 Mpixel camera. | ||
35 | + | ||
36 | config VIDEO_MT9V011 | ||
37 | tristate "Micron mt9v011 sensor support" | ||
38 | depends on I2C && VIDEO_V4L2 | ||
39 | diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile | ||
40 | index ace5d8b..912b29b 100644 | ||
41 | --- a/drivers/media/video/Makefile | ||
42 | +++ b/drivers/media/video/Makefile | ||
43 | @@ -65,6 +65,7 @@ obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o | ||
44 | obj-$(CONFIG_VIDEO_OV7670) += ov7670.o | ||
45 | obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o | ||
46 | obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o | ||
47 | +obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o | ||
48 | obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o | ||
49 | obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o | ||
50 | obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o | ||
51 | diff --git a/drivers/media/video/mt9p031.c b/drivers/media/video/mt9p031.c | ||
52 | new file mode 100644 | ||
53 | index 0000000..04d8812 | ||
54 | --- /dev/null | ||
55 | +++ b/drivers/media/video/mt9p031.c | ||
56 | @@ -0,0 +1,841 @@ | ||
57 | +/* | ||
58 | + * Driver for MT9P031 CMOS Image Sensor from Aptina | ||
59 | + * | ||
60 | + * Copyright (C) 2011, Javier Martin <javier.martin@vista-silicon.com> | ||
61 | + * | ||
62 | + * Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de> | ||
63 | + * | ||
64 | + * Based on the MT9V032 driver and Bastian Hecht's code. | ||
65 | + * | ||
66 | + * This program is free software; you can redistribute it and/or modify | ||
67 | + * it under the terms of the GNU General Public License version 2 as | ||
68 | + * published by the Free Software Foundation. | ||
69 | + */ | ||
70 | + | ||
71 | +#include <linux/delay.h> | ||
72 | +#include <linux/device.h> | ||
73 | +#include <linux/i2c.h> | ||
74 | +#include <linux/log2.h> | ||
75 | +#include <linux/pm.h> | ||
76 | +#include <linux/regulator/consumer.h> | ||
77 | +#include <linux/slab.h> | ||
78 | +#include <media/v4l2-subdev.h> | ||
79 | +#include <linux/videodev2.h> | ||
80 | + | ||
81 | +#include <media/mt9p031.h> | ||
82 | +#include <media/v4l2-chip-ident.h> | ||
83 | +#include <media/v4l2-subdev.h> | ||
84 | +#include <media/v4l2-device.h> | ||
85 | + | ||
86 | +#define MT9P031_PIXCLK_FREQ 54000000 | ||
87 | + | ||
88 | +/* mt9p031 selected register addresses */ | ||
89 | +#define MT9P031_CHIP_VERSION 0x00 | ||
90 | +#define MT9P031_CHIP_VERSION_VALUE 0x1801 | ||
91 | +#define MT9P031_ROW_START 0x01 | ||
92 | +#define MT9P031_ROW_START_DEF 54 | ||
93 | +#define MT9P031_COLUMN_START 0x02 | ||
94 | +#define MT9P031_COLUMN_START_DEF 16 | ||
95 | +#define MT9P031_WINDOW_HEIGHT 0x03 | ||
96 | +#define MT9P031_WINDOW_WIDTH 0x04 | ||
97 | +#define MT9P031_H_BLANKING 0x05 | ||
98 | +#define MT9P031_H_BLANKING_VALUE 0 | ||
99 | +#define MT9P031_V_BLANKING 0x06 | ||
100 | +#define MT9P031_V_BLANKING_VALUE 25 | ||
101 | +#define MT9P031_OUTPUT_CONTROL 0x07 | ||
102 | +#define MT9P031_OUTPUT_CONTROL_CEN 2 | ||
103 | +#define MT9P031_OUTPUT_CONTROL_SYN 1 | ||
104 | +#define MT9P031_SHUTTER_WIDTH_UPPER 0x08 | ||
105 | +#define MT9P031_SHUTTER_WIDTH 0x09 | ||
106 | +#define MT9P031_PIXEL_CLOCK_CONTROL 0x0a | ||
107 | +#define MT9P031_FRAME_RESTART 0x0b | ||
108 | +#define MT9P031_SHUTTER_DELAY 0x0c | ||
109 | +#define MT9P031_RST 0x0d | ||
110 | +#define MT9P031_RST_ENABLE 1 | ||
111 | +#define MT9P031_RST_DISABLE 0 | ||
112 | +#define MT9P031_READ_MODE_1 0x1e | ||
113 | +#define MT9P031_READ_MODE_2 0x20 | ||
114 | +#define MT9P031_READ_MODE_2_ROW_MIR 0x8000 | ||
115 | +#define MT9P031_READ_MODE_2_COL_MIR 0x4000 | ||
116 | +#define MT9P031_ROW_ADDRESS_MODE 0x22 | ||
117 | +#define MT9P031_COLUMN_ADDRESS_MODE 0x23 | ||
118 | +#define MT9P031_GLOBAL_GAIN 0x35 | ||
119 | + | ||
120 | +#define MT9P031_WINDOW_HEIGHT_MAX 1944 | ||
121 | +#define MT9P031_WINDOW_WIDTH_MAX 2592 | ||
122 | +#define MT9P031_WINDOW_HEIGHT_MIN 2 | ||
123 | +#define MT9P031_WINDOW_WIDTH_MIN 18 | ||
124 | + | ||
125 | +struct mt9p031 { | ||
126 | + struct v4l2_subdev subdev; | ||
127 | + struct media_pad pad; | ||
128 | + struct v4l2_rect rect; /* Sensor window */ | ||
129 | + struct v4l2_mbus_framefmt format; | ||
130 | + struct mt9p031_platform_data *pdata; | ||
131 | + struct mutex power_lock; /* lock to protect power_count */ | ||
132 | + int power_count; | ||
133 | + u16 xskip; | ||
134 | + u16 yskip; | ||
135 | + /* cache register values */ | ||
136 | + u16 output_control; | ||
137 | + u16 h_blanking; | ||
138 | + u16 v_blanking; | ||
139 | + u16 column_address_mode; | ||
140 | + u16 row_address_mode; | ||
141 | + u16 column_start; | ||
142 | + u16 row_start; | ||
143 | + u16 window_width; | ||
144 | + u16 window_height; | ||
145 | + struct regulator *reg_1v8; | ||
146 | + struct regulator *reg_2v8; | ||
147 | +}; | ||
148 | + | ||
149 | +static struct mt9p031 *to_mt9p031(const struct i2c_client *client) | ||
150 | +{ | ||
151 | + return container_of(i2c_get_clientdata(client), struct mt9p031, subdev); | ||
152 | +} | ||
153 | + | ||
154 | +static int reg_read(struct i2c_client *client, const u8 reg) | ||
155 | +{ | ||
156 | + s32 data = i2c_smbus_read_word_data(client, reg); | ||
157 | + return data < 0 ? data : swab16(data); | ||
158 | +} | ||
159 | + | ||
160 | +static int reg_write(struct i2c_client *client, const u8 reg, | ||
161 | + const u16 data) | ||
162 | +{ | ||
163 | + return i2c_smbus_write_word_data(client, reg, swab16(data)); | ||
164 | +} | ||
165 | + | ||
166 | +static int reg_write_cached(struct i2c_client *client, const u8 reg, | ||
167 | + const u16 data, u16 *cache) | ||
168 | +{ | ||
169 | + int ret; | ||
170 | + | ||
171 | + ret = reg_write(client, reg, data); | ||
172 | + if (ret < 0) | ||
173 | + return ret; | ||
174 | + *cache = data; | ||
175 | + return 0; | ||
176 | +} | ||
177 | + | ||
178 | +static int mt9p031_set_output_control(struct mt9p031 *mt9p031, u16 clear, | ||
179 | + u16 set) | ||
180 | +{ | ||
181 | + struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev); | ||
182 | + u16 value = (mt9p031->output_control & ~clear) | set; | ||
183 | + | ||
184 | + return reg_write_cached(client, MT9P031_OUTPUT_CONTROL, value, | ||
185 | + &mt9p031->output_control); | ||
186 | +} | ||
187 | + | ||
188 | +static int restore_registers(struct i2c_client *client) | ||
189 | +{ | ||
190 | + int ret; | ||
191 | + struct mt9p031 *mt9p031 = to_mt9p031(client); | ||
192 | + | ||
193 | + /* Disable register update, reconfigure atomically */ | ||
194 | + ret = mt9p031_set_output_control(mt9p031, 0, | ||
195 | + MT9P031_OUTPUT_CONTROL_SYN); | ||
196 | + if (ret < 0) | ||
197 | + return ret; | ||
198 | + | ||
199 | + /* Blanking and start values - default... */ | ||
200 | + ret = reg_write(client, MT9P031_H_BLANKING, mt9p031->h_blanking); | ||
201 | + if (ret < 0) | ||
202 | + return ret; | ||
203 | + | ||
204 | + ret = reg_write(client, MT9P031_V_BLANKING, mt9p031->v_blanking); | ||
205 | + if (ret < 0) | ||
206 | + return ret; | ||
207 | + | ||
208 | + ret = reg_write(client, MT9P031_COLUMN_ADDRESS_MODE, | ||
209 | + mt9p031->column_address_mode); | ||
210 | + if (ret < 0) | ||
211 | + return ret; | ||
212 | + | ||
213 | + ret = reg_write(client, MT9P031_ROW_ADDRESS_MODE, | ||
214 | + mt9p031->row_address_mode); | ||
215 | + if (ret < 0) | ||
216 | + return ret; | ||
217 | + | ||
218 | + ret = reg_write(client, MT9P031_COLUMN_START, | ||
219 | + mt9p031->column_start); | ||
220 | + if (ret < 0) | ||
221 | + return ret; | ||
222 | + | ||
223 | + ret = reg_write(client, MT9P031_ROW_START, | ||
224 | + mt9p031->row_start); | ||
225 | + if (ret < 0) | ||
226 | + return ret; | ||
227 | + | ||
228 | + ret = reg_write(client, MT9P031_WINDOW_WIDTH, | ||
229 | + mt9p031->window_width); | ||
230 | + if (ret < 0) | ||
231 | + return ret; | ||
232 | + | ||
233 | + ret = reg_write(client, MT9P031_WINDOW_HEIGHT, | ||
234 | + mt9p031->window_height); | ||
235 | + if (ret < 0) | ||
236 | + return ret; | ||
237 | + | ||
238 | + /* Re-enable register update, commit all changes */ | ||
239 | + ret = mt9p031_set_output_control(mt9p031, | ||
240 | + MT9P031_OUTPUT_CONTROL_SYN, 0); | ||
241 | + if (ret < 0) | ||
242 | + return ret; | ||
243 | + return 0; | ||
244 | +} | ||
245 | + | ||
246 | +static int mt9p031_reset(struct i2c_client *client) | ||
247 | +{ | ||
248 | + struct mt9p031 *mt9p031 = to_mt9p031(client); | ||
249 | + int ret; | ||
250 | + | ||
251 | + /* Disable chip output, synchronous option update */ | ||
252 | + ret = reg_write(client, MT9P031_RST, MT9P031_RST_ENABLE); | ||
253 | + if (ret < 0) | ||
254 | + return ret; | ||
255 | + ret = reg_write(client, MT9P031_RST, MT9P031_RST_DISABLE); | ||
256 | + if (ret < 0) | ||
257 | + return ret; | ||
258 | + return mt9p031_set_output_control(mt9p031, | ||
259 | + MT9P031_OUTPUT_CONTROL_CEN, 0); | ||
260 | +} | ||
261 | + | ||
262 | +static int mt9p031_power_on(struct mt9p031 *mt9p031) | ||
263 | +{ | ||
264 | + struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev); | ||
265 | + int ret; | ||
266 | + | ||
267 | + /* Ensure RESET_BAR is low */ | ||
268 | + if (mt9p031->pdata->reset) | ||
269 | + mt9p031->pdata->reset(&mt9p031->subdev, 1); | ||
270 | + /* turn on digital supply first */ | ||
271 | + ret = regulator_enable(mt9p031->reg_1v8); | ||
272 | + if (ret) { | ||
273 | + dev_err(&client->dev, | ||
274 | + "Failed to enable 1.8v regulator: %d\n", ret); | ||
275 | + goto err_1v8; | ||
276 | + } | ||
277 | + /* now turn on analog supply */ | ||
278 | + ret = regulator_enable(mt9p031->reg_2v8); | ||
279 | + if (ret) { | ||
280 | + dev_err(&client->dev, | ||
281 | + "Failed to enable 2.8v regulator: %d\n", ret); | ||
282 | + goto err_rst; | ||
283 | + } | ||
284 | + /* Now RESET_BAR must be high */ | ||
285 | + if (mt9p031->pdata->reset) | ||
286 | + mt9p031->pdata->reset(&mt9p031->subdev, 0); | ||
287 | + | ||
288 | + if (mt9p031->pdata->set_xclk) | ||
289 | + mt9p031->pdata->set_xclk(&mt9p031->subdev, MT9P031_PIXCLK_FREQ); | ||
290 | + | ||
291 | + /* soft reset */ | ||
292 | + ret = mt9p031_reset(client); | ||
293 | + if (ret < 0) { | ||
294 | + dev_err(&client->dev, "Failed to reset the camera\n"); | ||
295 | + goto err_rst; | ||
296 | + } | ||
297 | + | ||
298 | + ret = restore_registers(client); | ||
299 | + if (ret < 0) { | ||
300 | + dev_err(&client->dev, "Failed to restore registers\n"); | ||
301 | + goto err_rst; | ||
302 | + } | ||
303 | + | ||
304 | + return 0; | ||
305 | +err_rst: | ||
306 | + regulator_disable(mt9p031->reg_1v8); | ||
307 | +err_1v8: | ||
308 | + return ret; | ||
309 | + | ||
310 | +} | ||
311 | + | ||
312 | +static void mt9p031_power_off(struct mt9p031 *mt9p031) | ||
313 | +{ | ||
314 | + if (mt9p031->pdata->set_xclk) | ||
315 | + mt9p031->pdata->set_xclk(&mt9p031->subdev, 0); | ||
316 | + if (mt9p031->pdata->reset) | ||
317 | + mt9p031->pdata->reset(&mt9p031->subdev, 1); | ||
318 | + regulator_disable(mt9p031->reg_1v8); | ||
319 | + regulator_disable(mt9p031->reg_2v8); | ||
320 | +} | ||
321 | + | ||
322 | +static int mt9p031_enum_mbus_code(struct v4l2_subdev *sd, | ||
323 | + struct v4l2_subdev_fh *fh, | ||
324 | + struct v4l2_subdev_mbus_code_enum *code) | ||
325 | +{ | ||
326 | + struct mt9p031 *mt9p031 = container_of(sd, struct mt9p031, subdev); | ||
327 | + | ||
328 | + if (code->pad || code->index) | ||
329 | + return -EINVAL; | ||
330 | + | ||
331 | + code->code = mt9p031->format.code; | ||
332 | + | ||
333 | + return 0; | ||
334 | +} | ||
335 | + | ||
336 | +static struct v4l2_mbus_framefmt *mt9p031_get_pad_format( | ||
337 | + struct mt9p031 *mt9p031, | ||
338 | + struct v4l2_subdev_fh *fh, | ||
339 | + unsigned int pad, u32 which) | ||
340 | +{ | ||
341 | + switch (which) { | ||
342 | + case V4L2_SUBDEV_FORMAT_TRY: | ||
343 | + return v4l2_subdev_get_try_format(fh, pad); | ||
344 | + case V4L2_SUBDEV_FORMAT_ACTIVE: | ||
345 | + return &mt9p031->format; | ||
346 | + default: | ||
347 | + return NULL; | ||
348 | + } | ||
349 | +} | ||
350 | + | ||
351 | +static struct v4l2_rect *mt9p031_get_pad_crop(struct mt9p031 *mt9p031, | ||
352 | + struct v4l2_subdev_fh *fh, unsigned int pad, u32 which) | ||
353 | +{ | ||
354 | + switch (which) { | ||
355 | + case V4L2_SUBDEV_FORMAT_TRY: | ||
356 | + return v4l2_subdev_get_try_crop(fh, pad); | ||
357 | + case V4L2_SUBDEV_FORMAT_ACTIVE: | ||
358 | + return &mt9p031->rect; | ||
359 | + default: | ||
360 | + return NULL; | ||
361 | + } | ||
362 | +} | ||
363 | + | ||
364 | +static int mt9p031_get_crop(struct v4l2_subdev *sd, | ||
365 | + struct v4l2_subdev_fh *fh, | ||
366 | + struct v4l2_subdev_crop *crop) | ||
367 | +{ | ||
368 | + struct mt9p031 *mt9p031 = container_of(sd, struct mt9p031, subdev); | ||
369 | + struct v4l2_rect *rect = mt9p031_get_pad_crop(mt9p031, fh, crop->pad, | ||
370 | + crop->which); | ||
371 | + if (!rect) | ||
372 | + return -EINVAL; | ||
373 | + | ||
374 | + crop->rect = *rect; | ||
375 | + | ||
376 | + return 0; | ||
377 | +} | ||
378 | + | ||
379 | +static u16 mt9p031_skip_for_crop(s32 source, s32 *target, s32 max_skip) | ||
380 | +{ | ||
381 | + unsigned int skip; | ||
382 | + | ||
383 | + if (source - source / 4 < *target) { | ||
384 | + *target = source; | ||
385 | + return 1; | ||
386 | + } | ||
387 | + | ||
388 | + skip = DIV_ROUND_CLOSEST(source, *target); | ||
389 | + if (skip > max_skip) | ||
390 | + skip = max_skip; | ||
391 | + *target = 2 * DIV_ROUND_UP(source, 2 * skip); | ||
392 | + | ||
393 | + return skip; | ||
394 | +} | ||
395 | + | ||
396 | +static int mt9p031_set_params(struct i2c_client *client, | ||
397 | + struct v4l2_rect *rect, u16 xskip, u16 yskip) | ||
398 | +{ | ||
399 | + struct mt9p031 *mt9p031 = to_mt9p031(client); | ||
400 | + int ret; | ||
401 | + u16 xbin, ybin; | ||
402 | + const u16 hblank = MT9P031_H_BLANKING_VALUE, | ||
403 | + vblank = MT9P031_V_BLANKING_VALUE; | ||
404 | + __s32 left, top, width, height; | ||
405 | + | ||
406 | + /* | ||
407 | + * TODO: Attention! When implementing horizontal flipping, adjust | ||
408 | + * alignment according to R2 "Column Start" description in the datasheet | ||
409 | + */ | ||
410 | + if (xskip & 1) { | ||
411 | + xbin = 1; | ||
412 | + left = rect->left & (~3); | ||
413 | + } else if (xskip & 2) { | ||
414 | + xbin = 2; | ||
415 | + left = rect->left & (~7); | ||
416 | + } else { | ||
417 | + xbin = 4; | ||
418 | + left = rect->left & (~15); | ||
419 | + } | ||
420 | + top = rect->top & (~1); | ||
421 | + width = rect->width; | ||
422 | + height = rect->height; | ||
423 | + | ||
424 | + ybin = min(yskip, (u16)4); | ||
425 | + | ||
426 | + /* Disable register update, reconfigure atomically */ | ||
427 | + ret = mt9p031_set_output_control(mt9p031, 0, | ||
428 | + MT9P031_OUTPUT_CONTROL_SYN); | ||
429 | + if (ret < 0) | ||
430 | + return ret; | ||
431 | + | ||
432 | + dev_dbg(&client->dev, "skip %u:%u, rect %ux%u@%u:%u\n", | ||
433 | + xskip, yskip, rect->width, rect->height, rect->left, rect->top); | ||
434 | + | ||
435 | + /* Blanking and start values - default... */ | ||
436 | + ret = reg_write_cached(client, MT9P031_H_BLANKING, hblank, | ||
437 | + &mt9p031->h_blanking); | ||
438 | + if (ret < 0) | ||
439 | + return ret; | ||
440 | + ret = reg_write_cached(client, MT9P031_V_BLANKING, vblank, | ||
441 | + &mt9p031->v_blanking); | ||
442 | + if (ret < 0) | ||
443 | + return ret; | ||
444 | + | ||
445 | + ret = reg_write_cached(client, MT9P031_COLUMN_ADDRESS_MODE, | ||
446 | + ((xbin - 1) << 4) | (xskip - 1), | ||
447 | + &mt9p031->column_address_mode); | ||
448 | + if (ret < 0) | ||
449 | + return ret; | ||
450 | + ret = reg_write_cached(client, MT9P031_ROW_ADDRESS_MODE, | ||
451 | + ((ybin - 1) << 4) | (yskip - 1), | ||
452 | + &mt9p031->row_address_mode); | ||
453 | + if (ret < 0) | ||
454 | + return ret; | ||
455 | + | ||
456 | + dev_dbg(&client->dev, "new physical left %u, top %u\n", | ||
457 | + rect->left, rect->top); | ||
458 | + | ||
459 | + ret = reg_write_cached(client, MT9P031_COLUMN_START, | ||
460 | + rect->left + MT9P031_COLUMN_START_DEF, | ||
461 | + &mt9p031->column_start); | ||
462 | + if (ret < 0) | ||
463 | + return ret; | ||
464 | + ret = reg_write_cached(client, MT9P031_ROW_START, | ||
465 | + rect->top + MT9P031_ROW_START_DEF, | ||
466 | + &mt9p031->row_start); | ||
467 | + if (ret < 0) | ||
468 | + return ret; | ||
469 | + ret = reg_write_cached(client, MT9P031_WINDOW_WIDTH, | ||
470 | + rect->width - 1, | ||
471 | + &mt9p031->window_width); | ||
472 | + if (ret < 0) | ||
473 | + return ret; | ||
474 | + ret = reg_write_cached(client, MT9P031_WINDOW_HEIGHT, | ||
475 | + rect->height - 1, | ||
476 | + &mt9p031->window_height); | ||
477 | + if (ret < 0) | ||
478 | + return ret; | ||
479 | + | ||
480 | + /* Re-enable register update, commit all changes */ | ||
481 | + ret = mt9p031_set_output_control(mt9p031, | ||
482 | + MT9P031_OUTPUT_CONTROL_SYN, 0); | ||
483 | + if (ret < 0) | ||
484 | + return ret; | ||
485 | + | ||
486 | + mt9p031->xskip = xskip; | ||
487 | + mt9p031->yskip = yskip; | ||
488 | + return ret; | ||
489 | +} | ||
490 | + | ||
491 | +static int mt9p031_set_crop(struct v4l2_subdev *sd, | ||
492 | + struct v4l2_subdev_fh *fh, | ||
493 | + struct v4l2_subdev_crop *crop) | ||
494 | +{ | ||
495 | + struct mt9p031 *mt9p031 = container_of(sd, struct mt9p031, subdev); | ||
496 | + struct v4l2_mbus_framefmt *f; | ||
497 | + struct v4l2_rect *c; | ||
498 | + struct v4l2_rect rect; | ||
499 | + u16 xskip, yskip; | ||
500 | + s32 width, height; | ||
501 | + | ||
502 | + dev_dbg(mt9p031->subdev.v4l2_dev->dev, "%s(%ux%u@%u:%u : %u)\n", | ||
503 | + __func__, crop->rect.width, crop->rect.height, | ||
504 | + crop->rect.left, crop->rect.top, crop->which); | ||
505 | + | ||
506 | + /* | ||
507 | + * Clamp the crop rectangle boundaries and align them to a multiple of 2 | ||
508 | + * pixels. | ||
509 | + */ | ||
510 | + rect.width = ALIGN(clamp(crop->rect.width, | ||
511 | + MT9P031_WINDOW_WIDTH_MIN, MT9P031_WINDOW_WIDTH_MAX), 2); | ||
512 | + rect.height = ALIGN(clamp(crop->rect.height, | ||
513 | + MT9P031_WINDOW_HEIGHT_MIN, MT9P031_WINDOW_HEIGHT_MAX), 2); | ||
514 | + rect.left = ALIGN(clamp(crop->rect.left, | ||
515 | + 0, MT9P031_WINDOW_WIDTH_MAX - rect.width), 2); | ||
516 | + rect.top = ALIGN(clamp(crop->rect.top, | ||
517 | + 0, MT9P031_WINDOW_HEIGHT_MAX - rect.height), 2); | ||
518 | + | ||
519 | + c = mt9p031_get_pad_crop(mt9p031, fh, crop->pad, crop->which); | ||
520 | + | ||
521 | + if (rect.width != c->width || rect.height != c->height) { | ||
522 | + /* | ||
523 | + * Reset the output image size if the crop rectangle size has | ||
524 | + * been modified. | ||
525 | + */ | ||
526 | + f = mt9p031_get_pad_format(mt9p031, fh, crop->pad, | ||
527 | + crop->which); | ||
528 | + width = f->width; | ||
529 | + height = f->height; | ||
530 | + | ||
531 | + xskip = mt9p031_skip_for_crop(rect.width, &width, 7); | ||
532 | + yskip = mt9p031_skip_for_crop(rect.height, &height, 8); | ||
533 | + } else { | ||
534 | + xskip = mt9p031->xskip; | ||
535 | + yskip = mt9p031->yskip; | ||
536 | + f = NULL; | ||
537 | + } | ||
538 | + if (f) { | ||
539 | + f->width = width; | ||
540 | + f->height = height; | ||
541 | + } | ||
542 | + | ||
543 | + *c = rect; | ||
544 | + crop->rect = rect; | ||
545 | + | ||
546 | + mt9p031->xskip = xskip; | ||
547 | + mt9p031->yskip = yskip; | ||
548 | + mt9p031->rect = *c; | ||
549 | + return 0; | ||
550 | +} | ||
551 | + | ||
552 | +static int mt9p031_get_format(struct v4l2_subdev *sd, | ||
553 | + struct v4l2_subdev_fh *fh, | ||
554 | + struct v4l2_subdev_format *fmt) | ||
555 | +{ | ||
556 | + struct mt9p031 *mt9p031 = container_of(sd, struct mt9p031, subdev); | ||
557 | + | ||
558 | + fmt->format = | ||
559 | + *mt9p031_get_pad_format(mt9p031, fh, fmt->pad, fmt->which); | ||
560 | + return 0; | ||
561 | +} | ||
562 | + | ||
563 | +static u16 mt9p031_skip_for_scale(s32 *source, s32 target, | ||
564 | + s32 max_skip, s32 max) | ||
565 | +{ | ||
566 | + unsigned int skip; | ||
567 | + | ||
568 | + if (*source - *source / 4 < target) { | ||
569 | + *source = target; | ||
570 | + return 1; | ||
571 | + } | ||
572 | + | ||
573 | + skip = min(max, *source + target / 2) / target; | ||
574 | + if (skip > max_skip) | ||
575 | + skip = max_skip; | ||
576 | + *source = target * skip; | ||
577 | + | ||
578 | + return skip; | ||
579 | +} | ||
580 | + | ||
581 | +static int mt9p031_fmt_validate(struct v4l2_subdev *sd, | ||
582 | + struct v4l2_subdev_format *fmt) | ||
583 | +{ | ||
584 | + struct v4l2_mbus_framefmt *format = &fmt->format; | ||
585 | + | ||
586 | + /* Hardcode code and colorspace as sensor only supports one */ | ||
587 | + format->code = V4L2_MBUS_FMT_SGRBG12_1X12; | ||
588 | + format->colorspace = V4L2_COLORSPACE_SRGB; | ||
589 | + | ||
590 | + format->width = clamp_t(int, ALIGN(format->width, 2), 2, | ||
591 | + MT9P031_WINDOW_WIDTH_MAX); | ||
592 | + format->height = clamp_t(int, ALIGN(format->height, 2), 2, | ||
593 | + MT9P031_WINDOW_HEIGHT_MAX); | ||
594 | + format->field = V4L2_FIELD_NONE; | ||
595 | + | ||
596 | + return 0; | ||
597 | +} | ||
598 | + | ||
599 | +static int mt9p031_set_format(struct v4l2_subdev *sd, | ||
600 | + struct v4l2_subdev_fh *fh, | ||
601 | + struct v4l2_subdev_format *format) | ||
602 | +{ | ||
603 | + struct v4l2_subdev_format sdf = *format; | ||
604 | + struct v4l2_mbus_framefmt *__format, *format_bak = &sdf.format; | ||
605 | + struct v4l2_rect *__crop, rect; | ||
606 | + struct mt9p031 *mt9p031 = container_of(sd, struct mt9p031, subdev); | ||
607 | + u16 xskip, yskip; | ||
608 | + int ret; | ||
609 | + | ||
610 | + __crop = mt9p031_get_pad_crop(mt9p031, fh, format->pad, format->which); | ||
611 | + | ||
612 | + ret = mt9p031_fmt_validate(sd, &sdf); | ||
613 | + if (ret < 0) | ||
614 | + return ret; | ||
615 | + rect.width = __crop->width; | ||
616 | + rect.height = __crop->height; | ||
617 | + | ||
618 | + xskip = mt9p031_skip_for_scale(&rect.width, format_bak->width, 7, | ||
619 | + MT9P031_WINDOW_WIDTH_MAX); | ||
620 | + if (rect.width + __crop->left > MT9P031_WINDOW_WIDTH_MAX) | ||
621 | + rect.left = (MT9P031_WINDOW_WIDTH_MAX - rect.width) / 2; | ||
622 | + else | ||
623 | + rect.left = __crop->left; | ||
624 | + yskip = mt9p031_skip_for_scale(&rect.height, format_bak->height, 8, | ||
625 | + MT9P031_WINDOW_HEIGHT_MAX); | ||
626 | + if (rect.height + __crop->top > MT9P031_WINDOW_HEIGHT_MAX) | ||
627 | + rect.top = (MT9P031_WINDOW_HEIGHT_MAX - rect.height) / 2; | ||
628 | + else | ||
629 | + rect.top = __crop->top; | ||
630 | + | ||
631 | + dev_dbg(mt9p031->subdev.v4l2_dev->dev, "%s(%ux%u : %u)\n", __func__, | ||
632 | + format_bak->width, format_bak->height, format->which); | ||
633 | + if (__crop) | ||
634 | + *__crop = rect; | ||
635 | + | ||
636 | + __format = mt9p031_get_pad_format(mt9p031, fh, format->pad, format->which); | ||
637 | + *__format = *format_bak; | ||
638 | + format->format = *format_bak; | ||
639 | + | ||
640 | + mt9p031->xskip = xskip; | ||
641 | + mt9p031->yskip = yskip; | ||
642 | + mt9p031->rect = *__crop; | ||
643 | + return 0; | ||
644 | +} | ||
645 | + | ||
646 | +static int mt9p031_s_stream(struct v4l2_subdev *sd, int enable) | ||
647 | +{ | ||
648 | + struct mt9p031 *mt9p031 = container_of(sd, struct mt9p031, subdev); | ||
649 | + struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev); | ||
650 | + struct v4l2_rect rect = mt9p031->rect; | ||
651 | + u16 xskip = mt9p031->xskip; | ||
652 | + u16 yskip = mt9p031->yskip; | ||
653 | + int ret; | ||
654 | + | ||
655 | + if (enable) { | ||
656 | + ret = mt9p031_set_params(client, &rect, xskip, yskip); | ||
657 | + if (ret < 0) | ||
658 | + return ret; | ||
659 | + /* Switch to master "normal" mode */ | ||
660 | + ret = mt9p031_set_output_control(mt9p031, 0, | ||
661 | + MT9P031_OUTPUT_CONTROL_CEN); | ||
662 | + } else { | ||
663 | + /* Stop sensor readout */ | ||
664 | + ret = mt9p031_set_output_control(mt9p031, | ||
665 | + MT9P031_OUTPUT_CONTROL_CEN, 0); | ||
666 | + } | ||
667 | + return ret; | ||
668 | +} | ||
669 | + | ||
670 | +static int mt9p031_video_probe(struct i2c_client *client) | ||
671 | +{ | ||
672 | + s32 data; | ||
673 | + | ||
674 | + /* Read out the chip version register */ | ||
675 | + data = reg_read(client, MT9P031_CHIP_VERSION); | ||
676 | + if (data != MT9P031_CHIP_VERSION_VALUE) { | ||
677 | + dev_err(&client->dev, | ||
678 | + "No MT9P031 chip detected, register read %x\n", data); | ||
679 | + return -ENODEV; | ||
680 | + } | ||
681 | + | ||
682 | + dev_info(&client->dev, "Detected a MT9P031 chip ID %x\n", data); | ||
683 | + | ||
684 | + return 0; | ||
685 | +} | ||
686 | + | ||
687 | +static int mt9p031_set_power(struct v4l2_subdev *sd, int on) | ||
688 | +{ | ||
689 | + struct mt9p031 *mt9p031 = container_of(sd, struct mt9p031, subdev); | ||
690 | + int ret = 0; | ||
691 | + | ||
692 | + mutex_lock(&mt9p031->power_lock); | ||
693 | + | ||
694 | + /* | ||
695 | + * If the power count is modified from 0 to != 0 or from != 0 to 0, | ||
696 | + * update the power state. | ||
697 | + */ | ||
698 | + if (mt9p031->power_count == !on) { | ||
699 | + if (on) { | ||
700 | + ret = mt9p031_power_on(mt9p031); | ||
701 | + if (ret) { | ||
702 | + dev_err(mt9p031->subdev.v4l2_dev->dev, | ||
703 | + "Failed to enable 2.8v regulator: %d\n", ret); | ||
704 | + goto out; | ||
705 | + } | ||
706 | + } else { | ||
707 | + mt9p031_power_off(mt9p031); | ||
708 | + } | ||
709 | + } | ||
710 | + | ||
711 | + /* Update the power count. */ | ||
712 | + mt9p031->power_count += on ? 1 : -1; | ||
713 | + WARN_ON(mt9p031->power_count < 0); | ||
714 | + | ||
715 | +out: | ||
716 | + mutex_unlock(&mt9p031->power_lock); | ||
717 | + return ret; | ||
718 | +} | ||
719 | + | ||
720 | +static int mt9p031_registered(struct v4l2_subdev *sd) | ||
721 | +{ | ||
722 | + struct mt9p031 *mt9p031 = container_of(sd, struct mt9p031, subdev); | ||
723 | + struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev); | ||
724 | + int ret; | ||
725 | + | ||
726 | + ret = mt9p031_set_power(&mt9p031->subdev, 1); | ||
727 | + if (ret) { | ||
728 | + dev_err(&client->dev, | ||
729 | + "Failed to power on device: %d\n", ret); | ||
730 | + goto err_pwron; | ||
731 | + } | ||
732 | + | ||
733 | + ret = mt9p031_video_probe(client); | ||
734 | + if (ret) | ||
735 | + goto err_evprobe; | ||
736 | + | ||
737 | + mt9p031->pad.flags = MEDIA_PAD_FL_SOURCE; | ||
738 | + ret = media_entity_init(&mt9p031->subdev.entity, 1, &mt9p031->pad, 0); | ||
739 | + if (ret) | ||
740 | + goto err_evprobe; | ||
741 | + | ||
742 | + mt9p031->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
743 | + mt9p031_set_power(&mt9p031->subdev, 0); | ||
744 | + | ||
745 | + return 0; | ||
746 | +err_evprobe: | ||
747 | + mt9p031_set_power(&mt9p031->subdev, 0); | ||
748 | +err_pwron: | ||
749 | + return ret; | ||
750 | +} | ||
751 | + | ||
752 | +static int mt9p031_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | ||
753 | +{ | ||
754 | + struct mt9p031 *mt9p031; | ||
755 | + mt9p031 = container_of(sd, struct mt9p031, subdev); | ||
756 | + | ||
757 | + mt9p031->rect.width = MT9P031_WINDOW_WIDTH_MAX; | ||
758 | + mt9p031->rect.height = MT9P031_WINDOW_HEIGHT_MAX; | ||
759 | + mt9p031->rect.left = MT9P031_COLUMN_START_DEF; | ||
760 | + mt9p031->rect.top = MT9P031_ROW_START_DEF; | ||
761 | + | ||
762 | + mt9p031->format.code = V4L2_MBUS_FMT_SGRBG12_1X12; | ||
763 | + mt9p031->format.width = MT9P031_WINDOW_WIDTH_MAX; | ||
764 | + mt9p031->format.height = MT9P031_WINDOW_HEIGHT_MAX; | ||
765 | + mt9p031->format.field = V4L2_FIELD_NONE; | ||
766 | + mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB; | ||
767 | + | ||
768 | + mt9p031->xskip = 1; | ||
769 | + mt9p031->yskip = 1; | ||
770 | + return mt9p031_set_power(sd, 1); | ||
771 | +} | ||
772 | + | ||
773 | +static int mt9p031_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | ||
774 | +{ | ||
775 | + return mt9p031_set_power(sd, 0); | ||
776 | +} | ||
777 | + | ||
778 | +static struct v4l2_subdev_core_ops mt9p031_subdev_core_ops = { | ||
779 | + .s_power = mt9p031_set_power, | ||
780 | +}; | ||
781 | + | ||
782 | +static struct v4l2_subdev_video_ops mt9p031_subdev_video_ops = { | ||
783 | + .s_stream = mt9p031_s_stream, | ||
784 | +}; | ||
785 | + | ||
786 | +static struct v4l2_subdev_pad_ops mt9p031_subdev_pad_ops = { | ||
787 | + .enum_mbus_code = mt9p031_enum_mbus_code, | ||
788 | + .get_fmt = mt9p031_get_format, | ||
789 | + .set_fmt = mt9p031_set_format, | ||
790 | + .get_crop = mt9p031_get_crop, | ||
791 | + .set_crop = mt9p031_set_crop, | ||
792 | +}; | ||
793 | + | ||
794 | +static struct v4l2_subdev_ops mt9p031_subdev_ops = { | ||
795 | + .core = &mt9p031_subdev_core_ops, | ||
796 | + .video = &mt9p031_subdev_video_ops, | ||
797 | + .pad = &mt9p031_subdev_pad_ops, | ||
798 | +}; | ||
799 | + | ||
800 | +static const struct v4l2_subdev_internal_ops mt9p031_subdev_internal_ops = { | ||
801 | + .registered = mt9p031_registered, | ||
802 | + .open = mt9p031_open, | ||
803 | + .close = mt9p031_close, | ||
804 | +}; | ||
805 | + | ||
806 | +static int mt9p031_probe(struct i2c_client *client, | ||
807 | + const struct i2c_device_id *did) | ||
808 | +{ | ||
809 | + struct mt9p031 *mt9p031; | ||
810 | + struct mt9p031_platform_data *pdata = client->dev.platform_data; | ||
811 | + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | ||
812 | + int ret; | ||
813 | + | ||
814 | + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { | ||
815 | + dev_warn(&adapter->dev, | ||
816 | + "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); | ||
817 | + return -EIO; | ||
818 | + } | ||
819 | + | ||
820 | + mt9p031 = kzalloc(sizeof(struct mt9p031), GFP_KERNEL); | ||
821 | + if (!mt9p031) | ||
822 | + return -ENOMEM; | ||
823 | + | ||
824 | + mutex_init(&mt9p031->power_lock); | ||
825 | + v4l2_i2c_subdev_init(&mt9p031->subdev, client, &mt9p031_subdev_ops); | ||
826 | + mt9p031->subdev.internal_ops = &mt9p031_subdev_internal_ops; | ||
827 | + | ||
828 | + mt9p031->pdata = pdata; | ||
829 | + | ||
830 | + mt9p031->reg_1v8 = regulator_get(NULL, "cam_1v8"); | ||
831 | + if (IS_ERR(mt9p031->reg_1v8)) { | ||
832 | + ret = PTR_ERR(mt9p031->reg_1v8); | ||
833 | + dev_err(mt9p031->subdev.v4l2_dev->dev, | ||
834 | + "Failed 1.8v regulator: %d\n", ret); | ||
835 | + goto err_e1v8; | ||
836 | + } | ||
837 | + | ||
838 | + mt9p031->reg_2v8 = regulator_get(NULL, "cam_2v8"); | ||
839 | + if (IS_ERR(mt9p031->reg_2v8)) { | ||
840 | + ret = PTR_ERR(mt9p031->reg_2v8); | ||
841 | + dev_err(mt9p031->subdev.v4l2_dev->dev, | ||
842 | + "Failed 2.8v regulator: %d\n", ret); | ||
843 | + goto err_e2v8; | ||
844 | + } | ||
845 | + return 0; | ||
846 | +err_e2v8: | ||
847 | + regulator_put(mt9p031->reg_1v8); | ||
848 | +err_e1v8: | ||
849 | + kfree(mt9p031); | ||
850 | + return ret; | ||
851 | +} | ||
852 | + | ||
853 | +static int mt9p031_remove(struct i2c_client *client) | ||
854 | +{ | ||
855 | + struct v4l2_subdev *sd = i2c_get_clientdata(client); | ||
856 | + struct mt9p031 *mt9p031 = container_of(sd, struct mt9p031, subdev); | ||
857 | + | ||
858 | + v4l2_device_unregister_subdev(sd); | ||
859 | + media_entity_cleanup(&sd->entity); | ||
860 | + regulator_put(mt9p031->reg_2v8); | ||
861 | + regulator_put(mt9p031->reg_1v8); | ||
862 | + kfree(mt9p031); | ||
863 | + | ||
864 | + return 0; | ||
865 | +} | ||
866 | + | ||
867 | +static const struct i2c_device_id mt9p031_id[] = { | ||
868 | + { "mt9p031", 0 }, | ||
869 | + { } | ||
870 | +}; | ||
871 | +MODULE_DEVICE_TABLE(i2c, mt9p031_id); | ||
872 | + | ||
873 | +static struct i2c_driver mt9p031_i2c_driver = { | ||
874 | + .driver = { | ||
875 | + .name = "mt9p031", | ||
876 | + }, | ||
877 | + .probe = mt9p031_probe, | ||
878 | + .remove = mt9p031_remove, | ||
879 | + .id_table = mt9p031_id, | ||
880 | +}; | ||
881 | + | ||
882 | +static int __init mt9p031_mod_init(void) | ||
883 | +{ | ||
884 | + return i2c_add_driver(&mt9p031_i2c_driver); | ||
885 | +} | ||
886 | + | ||
887 | +static void __exit mt9p031_mod_exit(void) | ||
888 | +{ | ||
889 | + i2c_del_driver(&mt9p031_i2c_driver); | ||
890 | +} | ||
891 | + | ||
892 | +module_init(mt9p031_mod_init); | ||
893 | +module_exit(mt9p031_mod_exit); | ||
894 | + | ||
895 | +MODULE_DESCRIPTION("Aptina MT9P031 Camera driver"); | ||
896 | +MODULE_AUTHOR("Bastian Hecht <hechtb@gmail.com>"); | ||
897 | +MODULE_LICENSE("GPL v2"); | ||
898 | diff --git a/include/media/mt9p031.h b/include/media/mt9p031.h | ||
899 | new file mode 100644 | ||
900 | index 0000000..ad37eb3 | ||
901 | --- /dev/null | ||
902 | +++ b/include/media/mt9p031.h | ||
903 | @@ -0,0 +1,11 @@ | ||
904 | +#ifndef MT9P031_H | ||
905 | +#define MT9P031_H | ||
906 | + | ||
907 | +struct v4l2_subdev; | ||
908 | + | ||
909 | +struct mt9p031_platform_data { | ||
910 | + int (*set_xclk)(struct v4l2_subdev *subdev, int hz); | ||
911 | + int (*reset)(struct v4l2_subdev *subdev, int active); | ||
912 | +}; | ||
913 | + | ||
914 | +#endif | ||
915 | -- | ||
916 | 1.6.6.1 | ||
917 | |||