diff options
author | Koen Kooi <koen@dominion.thruhere.net> | 2012-07-13 12:19:44 +0200 |
---|---|---|
committer | Denys Dmytriyenko <denys@ti.com> | 2012-07-25 20:35:56 -0400 |
commit | cb872e3786ec7c08375257c534a38a5eff0bfff9 (patch) | |
tree | 2e04ad637010907fdf0c3711f717aaab2623bd6f /recipes-kernel | |
parent | e1b4ab72cfb3ea4599701d1600c44fe3c5f8ba66 (diff) | |
download | meta-ti-cb872e3786ec7c08375257c534a38a5eff0bfff9.tar.gz |
linux-ti33x-psp 3.2: add fixed for cssp, fbset and OPP50
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
Signed-off-by: Denys Dmytriyenko <denys@ti.com>
Diffstat (limited to 'recipes-kernel')
8 files changed, 1936 insertions, 30 deletions
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.2/beaglebone/0066-beaglebone-disable-OPP-for-275MHz-due-to-silicon-err.patch b/recipes-kernel/linux/linux-ti33x-psp-3.2/beaglebone/0066-beaglebone-disable-OPP-for-275MHz-due-to-silicon-err.patch deleted file mode 100644 index aae97bbe..00000000 --- a/recipes-kernel/linux/linux-ti33x-psp-3.2/beaglebone/0066-beaglebone-disable-OPP-for-275MHz-due-to-silicon-err.patch +++ /dev/null | |||
@@ -1,28 +0,0 @@ | |||
1 | From 954d199a0e9aaa4d7dbc7215cea0225cd3ffe186 Mon Sep 17 00:00:00 2001 | ||
2 | From: Koen Kooi <koen@dominion.thruhere.net> | ||
3 | Date: Mon, 28 May 2012 18:54:57 +0200 | ||
4 | Subject: [PATCH 66/68] beaglebone: disable OPP for 275MHz due to silicon | ||
5 | errata | ||
6 | |||
7 | Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> | ||
8 | --- | ||
9 | arch/arm/mach-omap2/board-am335xevm.c | 3 +++ | ||
10 | 1 files changed, 3 insertions(+), 0 deletions(-) | ||
11 | |||
12 | diff --git a/arch/arm/mach-omap2/board-am335xevm.c b/arch/arm/mach-omap2/board-am335xevm.c | ||
13 | index da6020b..58c2754 100644 | ||
14 | --- a/arch/arm/mach-omap2/board-am335xevm.c | ||
15 | +++ b/arch/arm/mach-omap2/board-am335xevm.c | ||
16 | @@ -2975,6 +2975,9 @@ static void tps65217_init(int evm_id, int profile) | ||
17 | return; | ||
18 | } | ||
19 | |||
20 | + pr_info("Disabling OPP for 275MHz due to silicon errata"); | ||
21 | + opp_disable(mpu_dev, 275000000); | ||
22 | + | ||
23 | if (!(val & TPS65217_STATUS_ACPWR)) { | ||
24 | /* If powered by USB then disable OPP120 and OPPTURBO */ | ||
25 | pr_info("Maximum current provided by the USB port is 500mA" | ||
26 | -- | ||
27 | 1.7.7.6 | ||
28 | |||
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.2/beaglebone/0073-beaglebone-add-support-for-QuickLogic-Camera-interfa.patch b/recipes-kernel/linux/linux-ti33x-psp-3.2/beaglebone/0073-beaglebone-add-support-for-QuickLogic-Camera-interfa.patch new file mode 100644 index 00000000..48ac34b9 --- /dev/null +++ b/recipes-kernel/linux/linux-ti33x-psp-3.2/beaglebone/0073-beaglebone-add-support-for-QuickLogic-Camera-interfa.patch | |||
@@ -0,0 +1,1612 @@ | |||
1 | From cf35e6b861c3c7d4d9c9db1557ba27b5578e8aa2 Mon Sep 17 00:00:00 2001 | ||
2 | From: Dan Aizenstros <daizenstros@quicklogic.com> | ||
3 | Date: Fri, 29 Jun 2012 13:57:49 -0400 | ||
4 | Subject: [PATCH] beaglebone: add support for QuickLogic Camera interface on | ||
5 | camera cape | ||
6 | |||
7 | Signed-off-by: Dan Aizenstros <daizenstros@quicklogic.com> | ||
8 | --- | ||
9 | arch/arm/mach-omap2/board-am335xevm.c | 205 ++++- | ||
10 | arch/arm/mach-omap2/devices.c | 2 +- | ||
11 | arch/arm/plat-omap/include/plat/dma-33xx.h | 1 + | ||
12 | drivers/media/video/Kconfig | 7 + | ||
13 | drivers/media/video/Makefile | 2 + | ||
14 | drivers/media/video/cssp_camera/Makefile | 3 + | ||
15 | drivers/media/video/cssp_camera/cssp_camera.c | 1119 +++++++++++++++++++++++++ | ||
16 | drivers/media/video/cssp_camera/cssp_camera.h | 148 ++++ | ||
17 | 8 files changed, 1478 insertions(+), 9 deletions(-) | ||
18 | create mode 100644 drivers/media/video/cssp_camera/Makefile | ||
19 | create mode 100644 drivers/media/video/cssp_camera/cssp_camera.c | ||
20 | create mode 100644 drivers/media/video/cssp_camera/cssp_camera.h | ||
21 | |||
22 | diff --git a/arch/arm/mach-omap2/board-am335xevm.c b/arch/arm/mach-omap2/board-am335xevm.c | ||
23 | index dc78b4a..1680612 100644 | ||
24 | --- a/arch/arm/mach-omap2/board-am335xevm.c | ||
25 | +++ b/arch/arm/mach-omap2/board-am335xevm.c | ||
26 | @@ -66,6 +66,10 @@ | ||
27 | #include <plat/mmc.h> | ||
28 | #include <plat/emif.h> | ||
29 | #include <plat/nand.h> | ||
30 | +#include <plat/dma-33xx.h> | ||
31 | + | ||
32 | +#include <media/soc_camera.h> | ||
33 | +#include <media/mt9t112.h> | ||
34 | |||
35 | #include "board-flash.h" | ||
36 | #include "cpuidle33xx.h" | ||
37 | @@ -804,6 +808,42 @@ static struct pinmux_config i2c1_pin_mux[] = { | ||
38 | {NULL, 0}, | ||
39 | }; | ||
40 | |||
41 | +/* Pin mux for GPMC bus */ | ||
42 | +static struct pinmux_config gpmc_pin_mux[] = { | ||
43 | + {"gpmc_ad0.gpmc_ad0", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, | ||
44 | + {"gpmc_ad1.gpmc_ad1", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, | ||
45 | + {"gpmc_ad2.gpmc_ad2", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, | ||
46 | + {"gpmc_ad3.gpmc_ad3", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, | ||
47 | + {"gpmc_ad4.gpmc_ad4", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, | ||
48 | + {"gpmc_ad5.gpmc_ad5", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, | ||
49 | + {"gpmc_ad6.gpmc_ad6", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, | ||
50 | + {"gpmc_ad7.gpmc_ad7", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, | ||
51 | + {"gpmc_ad8.gpmc_ad8", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, | ||
52 | + {"gpmc_ad9.gpmc_ad9", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, | ||
53 | + {"gpmc_ad10.gpmc_ad10", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, | ||
54 | + {"gpmc_ad11.gpmc_ad11", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, | ||
55 | + {"gpmc_ad12.gpmc_ad12", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, | ||
56 | + {"gpmc_ad13.gpmc_ad13", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, | ||
57 | + {"gpmc_ad14.gpmc_ad14", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, | ||
58 | + {"gpmc_ad15.gpmc_ad15", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, | ||
59 | + {"gpmc_wait0.gpmc_wait0", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP}, | ||
60 | + {"gpmc_wpn.gpmc_wpn", OMAP_MUX_MODE7 | AM33XX_PIN_INPUT_PULLUP}, | ||
61 | + {"gpmc_csn1.gpmc_csn1", OMAP_MUX_MODE0 | AM33XX_PULL_DISA}, | ||
62 | + {"gpmc_advn_ale.gpmc_advn_ale", OMAP_MUX_MODE0 | AM33XX_PULL_DISA}, | ||
63 | + {"gpmc_oen_ren.gpmc_oen_ren", OMAP_MUX_MODE0 | AM33XX_PULL_DISA}, | ||
64 | + {"gpmc_wen.gpmc_wen", OMAP_MUX_MODE0 | AM33XX_PULL_DISA}, | ||
65 | + {"gpmc_ben0_cle.gpmc_ben0_cle", OMAP_MUX_MODE0 | AM33XX_PULL_DISA}, | ||
66 | + {"gpmc_clk.gpmc_clk", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT}, | ||
67 | + {"ecap0_in_pwm0_out.xdma_event_intr2", OMAP_MUX_MODE6 | AM33XX_PIN_INPUT}, // DMAREQ | ||
68 | + {NULL, 0}, | ||
69 | +}; | ||
70 | + | ||
71 | +static struct pinmux_config camera_cape_pin_mux[] = { | ||
72 | + {"spi0_d1.gpio0_4", OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT }, // QL CSSP and Camera Sensor Reset | ||
73 | + {"spi0_cs0.gpio0_5", OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT_PULLUP }, // 1V8 and 2V8 Power Enable | ||
74 | + {NULL, 0}, | ||
75 | +}; | ||
76 | + | ||
77 | static struct pinmux_config i2c2_pin_mux[] = { | ||
78 | {"uart1_ctsn.i2c2_sda", OMAP_MUX_MODE3 | AM33XX_SLEWCTRL_SLOW | | ||
79 | AM33XX_PIN_INPUT_PULLUP}, | ||
80 | @@ -1803,6 +1843,156 @@ static void dvileds_init(int evm_id, int profile ) | ||
81 | pr_err("failed to register BeagleBone DVI cape LEDS\n"); | ||
82 | } | ||
83 | |||
84 | +static struct resource cssp_camera_resources[] = { | ||
85 | + { | ||
86 | + .name = "gpmc_phys_mem_slot", | ||
87 | + .flags = IORESOURCE_MEM, | ||
88 | + }, | ||
89 | +}; | ||
90 | + | ||
91 | +static struct mt9t112_camera_info mt9t111_cam_info = { | ||
92 | + /* divider calculated for 32Mhz CAM_MCLK */ | ||
93 | + .divider = { | ||
94 | + .m = 24, .n = 1, | ||
95 | + .p1 = 0, .p2 = 7, .p3 = 0, .p4 = 11, .p5 = 15, .p6 = 7, .p7 = 0, | ||
96 | + }, | ||
97 | +}; | ||
98 | + | ||
99 | +static struct soc_camera_link mt9t111_camera_link = { | ||
100 | + .priv = &mt9t111_cam_info, | ||
101 | + .i2c_adapter_id = 3, | ||
102 | +}; | ||
103 | + | ||
104 | +static struct i2c_board_info i2c_camera = { | ||
105 | + I2C_BOARD_INFO("mt9t112", 0x3c), | ||
106 | + .platform_data = &mt9t111_camera_link, | ||
107 | +}; | ||
108 | + | ||
109 | +struct cssp_cam_platform_data { | ||
110 | + struct i2c_board_info *cam_i2c_board_info; | ||
111 | + const char *cam_clk_name; | ||
112 | + int dma_ch; | ||
113 | + int cssp_reset_pin; | ||
114 | +}; | ||
115 | + | ||
116 | +static struct cssp_cam_platform_data cssp_cam_platform_data = { | ||
117 | + .cam_i2c_board_info = &i2c_camera, | ||
118 | + .cam_clk_name = "clkout2_ck", | ||
119 | + .dma_ch = AM33XX_DMA_XDMA_EVENT_INTR2, | ||
120 | + .cssp_reset_pin = GPIO_TO_PIN(0, 4), | ||
121 | +}; | ||
122 | + | ||
123 | +static struct platform_device cssp_camera = { | ||
124 | + .name = "cssp-camera", | ||
125 | + .id = -1, | ||
126 | + .dev = { | ||
127 | + .platform_data = &cssp_cam_platform_data, | ||
128 | + }, | ||
129 | + .num_resources = sizeof(cssp_camera_resources) / sizeof(cssp_camera_resources[0]), | ||
130 | + .resource = cssp_camera_resources, | ||
131 | +}; | ||
132 | + | ||
133 | +static struct gpmc_timings cssp_timings = { | ||
134 | + /* Minimum clock period for synchronous mode (in picoseconds) */ | ||
135 | + .sync_clk = 10000, | ||
136 | + | ||
137 | + .cs_on = 0, | ||
138 | + .cs_rd_off = 23 * 10, /* Read deassertion time */ | ||
139 | + .cs_wr_off = 23 * 10, /* Write deassertion time */ | ||
140 | + | ||
141 | + /* ADV signal timings corresponding to GPMC_CONFIG3 */ | ||
142 | + .adv_on = 0, /* Assertion time */ | ||
143 | + .adv_rd_off = 2 * 10, /* Read deassertion time */ | ||
144 | + .adv_wr_off = 2 * 10, /* Write deassertion time */ | ||
145 | + | ||
146 | + /* WE signals timings corresponding to GPMC_CONFIG4 */ | ||
147 | + .we_on = 3 * 10, /* WE assertion time */ | ||
148 | + .we_off = 23 * 10, /* WE deassertion time */ | ||
149 | + | ||
150 | + /* OE signals timings corresponding to GPMC_CONFIG4 */ | ||
151 | + .oe_on = 3 * 10, /* OE assertion time */ | ||
152 | + .oe_off = 23 * 10, /* OE deassertion time */ | ||
153 | + | ||
154 | + /* Access time and cycle time timings corresponding to GPMC_CONFIG5 */ | ||
155 | + .page_burst_access = 1 * 10, /* Multiple access word delay */ | ||
156 | + .access = 7 * 10, /* Start-cycle to first data valid delay */ | ||
157 | + .rd_cycle = 23 * 10, /* Total read cycle time */ | ||
158 | + .wr_cycle = 23 * 10, /* Total write cycle time */ | ||
159 | + | ||
160 | + /* The following are only on OMAP3430 */ | ||
161 | + .wr_access = 7 * 10, /* WRACCESSTIME */ | ||
162 | + .wr_data_mux_bus = 3 * 10, /* WRDATAONADMUXBUS */ | ||
163 | +}; | ||
164 | + | ||
165 | +static int gpmc_cssp_init(void) | ||
166 | +{ | ||
167 | + int cs = 1; /* Chip Select on GPMC bus */ | ||
168 | + int val; | ||
169 | + long unsigned int cssp_gpmc_mem_base_phys; | ||
170 | + | ||
171 | + if (gpmc_cs_request(cs, SZ_16M, &cssp_gpmc_mem_base_phys) < 0) { | ||
172 | + printk(KERN_ERR "[cssp_cam platform init]: gpmc_cs_request failed\n"); | ||
173 | + return -1; | ||
174 | + } | ||
175 | + | ||
176 | + cssp_camera_resources[0].start = cssp_gpmc_mem_base_phys; | ||
177 | + cssp_camera_resources[0].end = cssp_gpmc_mem_base_phys + 0x1ffff; | ||
178 | + | ||
179 | + if (gpmc_cs_configure(cs, GPMC_CONFIG_DEV_TYPE, GPMC_DEVICETYPE_NOR) < 0) { | ||
180 | + printk(KERN_ERR "[cssp_cam platform init]: gpmc_cs_configure failed\n"); | ||
181 | + return -1; | ||
182 | + } | ||
183 | + | ||
184 | + val = GPMC_CONFIG1_READMULTIPLE_SUPP; | ||
185 | + val |= GPMC_CONFIG1_READTYPE_SYNC; | ||
186 | + val |= GPMC_CONFIG1_WRITETYPE_SYNC; | ||
187 | + val |= GPMC_CONFIG1_CLKACTIVATIONTIME(1); | ||
188 | + val |= GPMC_CONFIG1_PAGE_LEN(2); | ||
189 | + val |= GPMC_CONFIG1_DEVICESIZE_16; | ||
190 | + val |= GPMC_CONFIG1_DEVICETYPE_NOR; | ||
191 | + val |= GPMC_CONFIG1_MUXADDDATA; | ||
192 | + gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, val); | ||
193 | + | ||
194 | + if (gpmc_cs_set_timings(cs, &cssp_timings) < 0) { | ||
195 | + printk(KERN_ERR "Failed gpmc_cs_set_timings for QuickLogic CAMIF device\n"); | ||
196 | + goto free; | ||
197 | + } | ||
198 | + | ||
199 | + val = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG6); | ||
200 | + val &= 0xe0f0f030; | ||
201 | + val |= 0x07030481; | ||
202 | + gpmc_cs_write_reg(cs, GPMC_CS_CONFIG6, val); | ||
203 | + | ||
204 | + printk(KERN_INFO "gpmc_cssp_init for QuickLogic CAMIF device succeeded\n"); | ||
205 | + | ||
206 | + return 0; | ||
207 | + | ||
208 | +free: | ||
209 | + gpmc_cs_free(cs); | ||
210 | + | ||
211 | + printk(KERN_ERR "Could not initialize QuickLogic CAMIF device\n"); | ||
212 | + | ||
213 | + return -1; | ||
214 | +} | ||
215 | + | ||
216 | +static void cssp_gpmc_init(void) | ||
217 | +{ | ||
218 | + struct gpmc_devices_info gpmc_device[2] = { | ||
219 | + { NULL, GPMC_DEVICE_NOR }, | ||
220 | + }; | ||
221 | + | ||
222 | + setup_pin_mux(camera_cape_pin_mux); | ||
223 | + setup_pin_mux(gpmc_pin_mux); | ||
224 | + | ||
225 | + omap_init_gpmc(gpmc_device, sizeof(gpmc_device)); | ||
226 | + gpmc_cssp_init(); | ||
227 | + | ||
228 | + platform_device_register(&cssp_camera); | ||
229 | + | ||
230 | + printk(KERN_INFO "[cssp_cam platform init]: cssp_gpmc_init: DONE\n"); | ||
231 | +} | ||
232 | + | ||
233 | + | ||
234 | static void lcd3leds_init(int evm_id, int profile ) | ||
235 | { | ||
236 | int err; | ||
237 | @@ -2851,6 +3041,7 @@ static void beaglebone_cape_setup(struct memory_accessor *mem_acc, void *context | ||
238 | if (!strncmp("BB-BONE-CAM-01", cape_config.partnumber, 14)) { | ||
239 | pr_info("BeagleBone cape: recognized Camera cape\n"); | ||
240 | beaglebone_w1gpio_free = 0; | ||
241 | + cssp_gpmc_init(); | ||
242 | } | ||
243 | |||
244 | goto out2; | ||
245 | @@ -3762,15 +3953,13 @@ static struct pinmux_config clkout2_pin_mux[] = { | ||
246 | |||
247 | static void __init clkout2_enable(void) | ||
248 | { | ||
249 | - struct clk *ck_32; | ||
250 | - | ||
251 | - ck_32 = clk_get(NULL, "clkout2_ck"); | ||
252 | - if (IS_ERR(ck_32)) { | ||
253 | - pr_err("Cannot clk_get ck_32\n"); | ||
254 | - return; | ||
255 | - } | ||
256 | + void __iomem *base; | ||
257 | + unsigned int val; | ||
258 | |||
259 | - clk_enable(ck_32); | ||
260 | + base = ioremap(0x44E00700, SZ_4K); | ||
261 | + val = (5 << 3) | (3 << 0); //32 MHz | ||
262 | + writel(val, base); | ||
263 | + iounmap(base); | ||
264 | |||
265 | setup_pin_mux(clkout2_pin_mux); | ||
266 | } | ||
267 | diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c | ||
268 | index 41c9b0f..3ef045e 100644 | ||
269 | --- a/arch/arm/mach-omap2/devices.c | ||
270 | +++ b/arch/arm/mach-omap2/devices.c | ||
271 | @@ -968,7 +968,7 @@ static struct event_to_channel_map am33xx_xbar_event_mapping[] = { | ||
272 | {27, -1}, | ||
273 | {28, -1}, | ||
274 | {29, -1}, | ||
275 | - {30, -1}, | ||
276 | + {30, 20}, /* XDMA_EVENT_INTR2 */ | ||
277 | {31, -1}, | ||
278 | {-1, -1} | ||
279 | }; | ||
280 | diff --git a/arch/arm/plat-omap/include/plat/dma-33xx.h b/arch/arm/plat-omap/include/plat/dma-33xx.h | ||
281 | index bebdaa7..ded00aa 100644 | ||
282 | --- a/arch/arm/plat-omap/include/plat/dma-33xx.h | ||
283 | +++ b/arch/arm/plat-omap/include/plat/dma-33xx.h | ||
284 | @@ -83,5 +83,6 @@ | ||
285 | #define AM33XX_DMA_PWMSS2_EPW 63 | ||
286 | #define AM33XX_DMA_MMCHS2_W 64 /* xBar */ | ||
287 | #define AM33XX_DMA_MMCHS2_R 65 /* xBar */ | ||
288 | +#define AM33XX_DMA_XDMA_EVENT_INTR2 93 /* xBar */ | ||
289 | |||
290 | #endif | ||
291 | diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig | ||
292 | index b303a3f..a31723f 100644 | ||
293 | --- a/drivers/media/video/Kconfig | ||
294 | +++ b/drivers/media/video/Kconfig | ||
295 | @@ -1002,6 +1002,13 @@ config VIDEO_S5P_MIPI_CSIS | ||
296 | |||
297 | source "drivers/media/video/s5p-tv/Kconfig" | ||
298 | |||
299 | +config VIDEO_QL_CAMIF | ||
300 | + tristate "QuickLogic Camera Interface support (EXPERIMENTAL)" | ||
301 | + depends on VIDEO_DEV && SOC_CAMERA && SOC_OMAPAM33XX && EXPERIMENTAL | ||
302 | + select VIDEOBUF2_DMA_CONTIG | ||
303 | + ---help--- | ||
304 | + This is a v4l2 driver for the QuickLogic CAMIF controller. | ||
305 | + | ||
306 | # | ||
307 | # USB Multimedia device configuration | ||
308 | # | ||
309 | diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile | ||
310 | index 117f9c4..af7af692 100644 | ||
311 | --- a/drivers/media/video/Makefile | ||
312 | +++ b/drivers/media/video/Makefile | ||
313 | @@ -195,6 +195,8 @@ obj-y += davinci/ | ||
314 | |||
315 | obj-$(CONFIG_ARCH_OMAP) += omap/ | ||
316 | |||
317 | +obj-$(CONFIG_VIDEO_QL_CAMIF) += cssp_camera/ | ||
318 | + | ||
319 | ccflags-y += -Idrivers/media/dvb/dvb-core | ||
320 | ccflags-y += -Idrivers/media/dvb/frontends | ||
321 | ccflags-y += -Idrivers/media/common/tuners | ||
322 | diff --git a/drivers/media/video/cssp_camera/Makefile b/drivers/media/video/cssp_camera/Makefile | ||
323 | new file mode 100644 | ||
324 | index 0000000..d85a84e | ||
325 | --- /dev/null | ||
326 | +++ b/drivers/media/video/cssp_camera/Makefile | ||
327 | @@ -0,0 +1,3 @@ | ||
328 | +# cssp_camera | ||
329 | + | ||
330 | +obj-$(CONFIG_VIDEO_QL_CAMIF) += cssp_camera.o | ||
331 | diff --git a/drivers/media/video/cssp_camera/cssp_camera.c b/drivers/media/video/cssp_camera/cssp_camera.c | ||
332 | new file mode 100644 | ||
333 | index 0000000..39aa003 | ||
334 | --- /dev/null | ||
335 | +++ b/drivers/media/video/cssp_camera/cssp_camera.c | ||
336 | @@ -0,0 +1,1119 @@ | ||
337 | +/* | ||
338 | + * cssp-camera driver | ||
339 | + * | ||
340 | + * Based on Vivi driver | ||
341 | + * | ||
342 | + * Copyright (C) 2012 QuickLogic Corp. | ||
343 | + * | ||
344 | + * Developed for QuickLogic by: | ||
345 | + * Damian Eppel <damian.eppel@teleca.com> | ||
346 | + * Przemek Szewczyk <przemek.szewczyk@teleca.com> | ||
347 | + * Dan Aizenstros <daizenstros@quicklogic.com> | ||
348 | + * | ||
349 | + * This program is free software; you can redistribute it and/or modify | ||
350 | + * it under the terms of the GNU General Public License version 2 as | ||
351 | + * published by the Free Software Foundation. | ||
352 | + * | ||
353 | + */ | ||
354 | + | ||
355 | + | ||
356 | +#include <linux/init.h> | ||
357 | +#include <linux/module.h> | ||
358 | +#include <linux/gpio.h> | ||
359 | +#include <linux/i2c.h> | ||
360 | +#include <linux/delay.h> | ||
361 | +#include <linux/spinlock.h> | ||
362 | +#include <linux/dma-mapping.h> | ||
363 | +#include <linux/interrupt.h> | ||
364 | +#include <mach/edma.h> | ||
365 | +#include <linux/clk.h> | ||
366 | +// V4L2 Interface ********************* | ||
367 | +#include <media/soc_camera.h> | ||
368 | +#include <media/v4l2-mediabus.h> | ||
369 | +#include <media/videobuf2-dma-contig.h> | ||
370 | +#include <media/v4l2-ioctl.h> | ||
371 | +#include <media/v4l2-event.h> | ||
372 | +//************************************* | ||
373 | +#include "cssp_camera.h" | ||
374 | + | ||
375 | + | ||
376 | +/* | ||
377 | + * --------------------------------------------------------------------------- | ||
378 | + * QuickLoigc Camera Interface registers | ||
379 | + * --------------------------------------------------------------------------- | ||
380 | + */ | ||
381 | + | ||
382 | +#define REG_MODE 0x00000 | ||
383 | +#define REG_DATA 0x10000 | ||
384 | + | ||
385 | +/* MODE bit shifts */ | ||
386 | +#define FMT_2X8_EN BIT(15) /* Enable 2 byte format on CAMIF bus (0 - 10 bit, 1 - 16 bit 2x8) */ | ||
387 | +#define PCLK_POL BIT(14) /* PCLK polarity (0 - rising edge, 1 - falling edge */ | ||
388 | +#define HS_EN BIT(13) /* High speed bus (0 =< 50 MHz, 1 > 50 MHz) */ | ||
389 | +#define ENABLE BIT(12) | ||
390 | + | ||
391 | + | ||
392 | +static struct cssp_cam_fmt formats[] = { | ||
393 | + { | ||
394 | + .name = "4:2:2, packed, YUYV", | ||
395 | + .fourcc = V4L2_PIX_FMT_YUYV, | ||
396 | + .depth = 16, | ||
397 | + .code = V4L2_MBUS_FMT_YUYV8_2X8, | ||
398 | + }, | ||
399 | + { | ||
400 | + .name = "4:2:2, packed, UYVY", | ||
401 | + .fourcc = V4L2_PIX_FMT_UYVY, | ||
402 | + .depth = 16, | ||
403 | + .code = V4L2_MBUS_FMT_UYVY8_2X8, | ||
404 | + }, | ||
405 | + { | ||
406 | + .name = "4:2:2, packed, VYUY", | ||
407 | + .fourcc = V4L2_PIX_FMT_VYUY, | ||
408 | + .depth = 16, | ||
409 | + .code = V4L2_MBUS_FMT_VYUY8_2X8, | ||
410 | + }, | ||
411 | + { | ||
412 | + .name = "4:2:2, packed, YVYU", | ||
413 | + .fourcc = V4L2_PIX_FMT_YVYU, | ||
414 | + .depth = 16, | ||
415 | + .code = V4L2_MBUS_FMT_YVYU8_2X8, | ||
416 | + }, | ||
417 | + { | ||
418 | + .name = "RGB565 (LE)", | ||
419 | + .fourcc = V4L2_PIX_FMT_RGB565, | ||
420 | + .depth = 16, | ||
421 | + .code = V4L2_MBUS_FMT_RGB565_2X8_LE, | ||
422 | + }, | ||
423 | + { | ||
424 | + .name = "RGB555 (LE)", | ||
425 | + .fourcc = V4L2_PIX_FMT_RGB555, | ||
426 | + .depth = 16, | ||
427 | + .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, | ||
428 | + }, | ||
429 | +}; | ||
430 | + | ||
431 | + | ||
432 | +/***************************************************************************/ | ||
433 | + | ||
434 | + | ||
435 | +static int configure_gpio(int nr, int val, const char *name) | ||
436 | +{ | ||
437 | + unsigned long flags = val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; | ||
438 | + int ret; | ||
439 | + if (!gpio_is_valid(nr)) | ||
440 | + return 0; | ||
441 | + ret = gpio_request_one(nr, flags, name); | ||
442 | + if (!ret) | ||
443 | + gpio_export(nr, 0); | ||
444 | + return ret; | ||
445 | +} | ||
446 | + | ||
447 | +static int reset_cssp(struct cssp_cam_dev *cam) | ||
448 | +{ | ||
449 | + struct platform_device *pdev = cam->pdev; | ||
450 | + int err; | ||
451 | + | ||
452 | + cam->reset_pin = ((struct cssp_cam_platform_data *)pdev->dev.platform_data)->gpio_reset_pin; | ||
453 | + | ||
454 | + err = configure_gpio(cam->reset_pin, 0, "cssp_reset"); | ||
455 | + if (err) { | ||
456 | + printk(KERN_ERR "[%s]: failed to configure cssp reset pin\n", pdev->name); | ||
457 | + return -1; | ||
458 | + } | ||
459 | + | ||
460 | + mdelay(1); | ||
461 | + | ||
462 | + gpio_direction_output(cam->reset_pin, 1); | ||
463 | + | ||
464 | + return err; | ||
465 | +} | ||
466 | + | ||
467 | +static int trigger_dma_transfer_to_buf(struct cssp_cam_dev *dev, struct vb2_buffer *vb) | ||
468 | +{ | ||
469 | + dma_addr_t dma_buf = vb2_dma_contig_plane_dma_addr(vb, 0); | ||
470 | + | ||
471 | + if (!dma_buf) { | ||
472 | + /* Is this possible? Release the vb2_buffer with an error here, */ | ||
473 | + vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); | ||
474 | + dev->current_vb = NULL; | ||
475 | + return -ENOMEM; | ||
476 | + } | ||
477 | + | ||
478 | + dev->dma_tr_params.dst = dma_buf; | ||
479 | + | ||
480 | + // Enable DMA | ||
481 | + edma_write_slot(dev->dma_ch, &dev->dma_tr_params); | ||
482 | + | ||
483 | + // Enable data capture | ||
484 | + dev->mode |= ENABLE; | ||
485 | + writew(dev->mode, dev->reg_base_virt + REG_MODE); | ||
486 | + readw(dev->reg_base_virt + REG_MODE); | ||
487 | + | ||
488 | + dev->current_vb = vb; | ||
489 | + | ||
490 | + return 0; | ||
491 | +} | ||
492 | + | ||
493 | +static void dequeue_buffer_for_dma(struct cssp_cam_dev *dev) | ||
494 | +{ | ||
495 | + struct cssp_cam_dmaqueue *dma_q = &dev->vidq; | ||
496 | + unsigned long flags = 0; | ||
497 | + | ||
498 | + spin_lock_irqsave(&dev->slock, flags); | ||
499 | + if (!list_empty(&dma_q->active)) { | ||
500 | + struct cssp_cam_buffer *buf; | ||
501 | + | ||
502 | + buf = list_entry(dma_q->active.next, struct cssp_cam_buffer, list); | ||
503 | + list_del(&buf->list); | ||
504 | + spin_unlock_irqrestore(&dev->slock, flags); | ||
505 | + | ||
506 | + buf->fmt = dev->fmt; | ||
507 | + | ||
508 | + trigger_dma_transfer_to_buf(dev, &buf->vb); | ||
509 | + } else { | ||
510 | + spin_unlock_irqrestore(&dev->slock, flags); | ||
511 | + } | ||
512 | +} | ||
513 | + | ||
514 | +static void dma_callback(unsigned lch, u16 ch_status, void *data) | ||
515 | +{ | ||
516 | + struct cssp_cam_dev *dev = (struct cssp_cam_dev *)data; | ||
517 | + | ||
518 | + // Disable data capture | ||
519 | + dev->mode &= ~ENABLE; | ||
520 | + writew(dev->mode, dev->reg_base_virt + REG_MODE); | ||
521 | + readw(dev->reg_base_virt + REG_MODE); | ||
522 | + | ||
523 | + if (ch_status == DMA_COMPLETE) { | ||
524 | + struct vb2_buffer *vb = dev->current_vb; | ||
525 | + struct timeval ts; | ||
526 | + | ||
527 | + vb->v4l2_buf.field = dev->field; | ||
528 | + dev->field_count++; | ||
529 | + vb->v4l2_buf.sequence = dev->field_count >> 1; | ||
530 | + do_gettimeofday(&ts); | ||
531 | + vb->v4l2_buf.timestamp = ts; | ||
532 | + vb2_buffer_done(vb, VB2_BUF_STATE_DONE); | ||
533 | + dev->current_vb = NULL; | ||
534 | + dev->frame_cnt++; | ||
535 | + | ||
536 | + /* check if we have new buffer queued */ | ||
537 | + dequeue_buffer_for_dma(dev); | ||
538 | + } else { | ||
539 | + printk(KERN_ERR "[cssp_camera]: EDMA error (ch_status = %d)\n", ch_status); | ||
540 | + /* we got a missed interrupt so just start a new DMA with the existing buffer */ | ||
541 | + if (dev->current_vb != NULL) | ||
542 | + trigger_dma_transfer_to_buf(dev, dev->current_vb); | ||
543 | + } | ||
544 | +} | ||
545 | + | ||
546 | +static int configure_edma(struct cssp_cam_dev *cam) | ||
547 | +{ | ||
548 | + struct platform_device *pdev = cam->pdev; | ||
549 | + int dma_channel; | ||
550 | + | ||
551 | + dma_channel = ((struct cssp_cam_platform_data *)pdev->dev.platform_data)->dma_ch; | ||
552 | + | ||
553 | + pdev->dev.dma_mask = &cam->dma_mask; | ||
554 | + | ||
555 | + pdev->dev.coherent_dma_mask = (u32)~0; | ||
556 | + | ||
557 | + if (dma_set_mask(&pdev->dev, (u32)~0)) { | ||
558 | + printk(KERN_ERR "[%s]: failed setting mask for DMA\n", pdev->name); | ||
559 | + return -1; | ||
560 | + } | ||
561 | + | ||
562 | + cam->dma_ch = edma_alloc_channel(dma_channel, dma_callback, cam, EVENTQ_1); | ||
563 | + if (cam->dma_ch < 0) { | ||
564 | + printk(KERN_ERR "[%s]: allocating channel for DMA failed\n", pdev->name); | ||
565 | + return -EBUSY; | ||
566 | + } else { | ||
567 | + printk(KERN_ERR "[%s]: allocating channel for DMA succeeded, chan=%d\n", pdev->name, cam->dma_ch); | ||
568 | + } | ||
569 | + | ||
570 | + cam->dma_tr_params.opt = TCINTEN | TCC(cam->dma_ch); | ||
571 | + cam->dma_tr_params.src = cam->reg_base_phys + REG_DATA; | ||
572 | + cam->dma_tr_params.a_b_cnt = ACNT(BYTES_PER_DMA_EVT) | BCNT((VGA_WIDTH * BYTES_PER_PIXEL) / BYTES_PER_DMA_EVT); | ||
573 | + cam->dma_tr_params.src_dst_bidx = SRCBIDX(0) | DSTBIDX(BYTES_PER_DMA_EVT); | ||
574 | + cam->dma_tr_params.link_bcntrld = BCNTRLD((VGA_WIDTH * BYTES_PER_PIXEL) / BYTES_PER_DMA_EVT) | LINK(0xffff); | ||
575 | + cam->dma_tr_params.src_dst_cidx = SRCCIDX(0) | DSTCIDX(BYTES_PER_DMA_EVT); | ||
576 | + cam->dma_tr_params.ccnt = CCNT(VGA_HEIGHT); | ||
577 | + | ||
578 | + return 0; | ||
579 | +} | ||
580 | + | ||
581 | +static int configure_cssp(struct cssp_cam_dev *cam) | ||
582 | +{ | ||
583 | + struct platform_device *pdev = cam->pdev; | ||
584 | + int ret = 0; | ||
585 | + unsigned int val; | ||
586 | + struct resource *res; | ||
587 | + | ||
588 | + ret = reset_cssp(cam); | ||
589 | + if (ret) | ||
590 | + return ret; | ||
591 | + | ||
592 | + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gpmc_phys_mem_slot"); | ||
593 | + if (res == NULL) { | ||
594 | + printk(KERN_ERR "[%s]: failed to get gpmc_phys_mem_slot resource\n", pdev->name); | ||
595 | + return -ENODEV; | ||
596 | + } | ||
597 | + | ||
598 | + /* | ||
599 | + * Request the region. | ||
600 | + */ | ||
601 | + if (!request_mem_region(res->start, resource_size(res), pdev->name)) { | ||
602 | + return -EBUSY; | ||
603 | + } | ||
604 | + | ||
605 | + cam->reg_base_phys = res->start; | ||
606 | + cam->reg_size = resource_size(res); | ||
607 | + | ||
608 | + cam->reg_base_virt = (unsigned int)ioremap(cam->reg_base_phys, cam->reg_size); | ||
609 | + if (cam->reg_base_virt == 0) { | ||
610 | + printk(KERN_ERR "[%s]: ioremap of registers region failed\n", pdev->name); | ||
611 | + release_mem_region(cam->reg_base_phys, cam->reg_size); | ||
612 | + return -ENOMEM; | ||
613 | + } | ||
614 | + | ||
615 | + printk(KERN_INFO "[%s]: reg_base_virt = 0x%x\n", pdev->name, cam->reg_base_virt); | ||
616 | + | ||
617 | + val = readw(cam->reg_base_virt + REG_MODE); | ||
618 | + printk(KERN_INFO "[%s]: reading register address=0x0 returns 0x%x\n", pdev->name, val); | ||
619 | + | ||
620 | + return 0; | ||
621 | +} | ||
622 | + | ||
623 | +static int configure_camera_sensor(struct cssp_cam_dev *cam) | ||
624 | +{ | ||
625 | + struct i2c_board_info *info = cam->camera_board_info; | ||
626 | + struct i2c_client *client; | ||
627 | + struct i2c_adapter *adapter; | ||
628 | + struct v4l2_subdev *subdev; | ||
629 | + struct v4l2_mbus_framefmt f_format = { | ||
630 | + .width = VGA_WIDTH, | ||
631 | + .height = VGA_HEIGHT, | ||
632 | + .code = V4L2_MBUS_FMT_YUYV8_2X8, | ||
633 | + .colorspace = V4L2_COLORSPACE_JPEG, | ||
634 | + }; | ||
635 | + | ||
636 | + /* Enable the clock just for the time of loading the camera driver and disable after that */ | ||
637 | + /* It is going to be be re-enabled later, when camera will be in use */ | ||
638 | + clk_enable(cam->camera_clk); | ||
639 | + udelay(5); // let the clock stabilize | ||
640 | + | ||
641 | + adapter = i2c_get_adapter(((struct soc_camera_link *)(info->platform_data))->i2c_adapter_id); | ||
642 | + if (!adapter) { | ||
643 | + printk(KERN_INFO "[%s]: failed to get adapter...\n", __func__); | ||
644 | + return -ENODEV; | ||
645 | + } | ||
646 | + | ||
647 | + client = i2c_new_device(adapter, info); | ||
648 | + i2c_put_adapter(adapter); | ||
649 | + | ||
650 | + if (client == NULL) { | ||
651 | + return -ENODEV; | ||
652 | + } | ||
653 | + | ||
654 | + printk(KERN_INFO "[%s]: client's name is: %s\n", __func__, client->name); | ||
655 | + | ||
656 | + subdev = (struct v4l2_subdev *)i2c_get_clientdata(client); | ||
657 | + if (subdev == NULL) { | ||
658 | + i2c_unregister_device(client); | ||
659 | + return -ENODEV; | ||
660 | + } | ||
661 | + | ||
662 | + cam->subdev = subdev; | ||
663 | + | ||
664 | + v4l2_subdev_call(subdev, video, s_mbus_fmt, &f_format); | ||
665 | + | ||
666 | + clk_disable(cam->camera_clk); | ||
667 | + | ||
668 | + return 0; | ||
669 | +} | ||
670 | + | ||
671 | +static int start_camera_sensor(struct cssp_cam_dev *cam) | ||
672 | +{ | ||
673 | + clk_enable(cam->camera_clk); | ||
674 | + udelay(5); /* let the clock stabilize */ | ||
675 | + | ||
676 | + v4l2_subdev_call(cam->subdev, video, s_stream, 1); | ||
677 | + | ||
678 | + return 0; | ||
679 | +} | ||
680 | + | ||
681 | +static void stop_camera_sensor(struct cssp_cam_dev *cam) | ||
682 | +{ | ||
683 | + v4l2_subdev_call(cam->subdev, video, s_stream, 0); | ||
684 | + | ||
685 | + clk_disable(cam->camera_clk); | ||
686 | + | ||
687 | + return; | ||
688 | +} | ||
689 | + | ||
690 | + | ||
691 | +/************************************************ | ||
692 | + * Video4Linux2 | ||
693 | + */ | ||
694 | + | ||
695 | +static struct cssp_cam_fmt *get_format(struct v4l2_format *f) | ||
696 | +{ | ||
697 | + struct cssp_cam_fmt *fmt; | ||
698 | + unsigned int k; | ||
699 | + | ||
700 | + for (k = 0; k < ARRAY_SIZE(formats); k++) { | ||
701 | + fmt = &formats[k]; | ||
702 | + if (fmt->fourcc == f->fmt.pix.pixelformat) | ||
703 | + break; | ||
704 | + } | ||
705 | + | ||
706 | + if (k == ARRAY_SIZE(formats)) | ||
707 | + return NULL; | ||
708 | + | ||
709 | + return &formats[k]; | ||
710 | +} | ||
711 | + | ||
712 | + | ||
713 | +/* ------------------------------------------------------------------ | ||
714 | + Videobuf operations | ||
715 | + ------------------------------------------------------------------*/ | ||
716 | + | ||
717 | +static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, | ||
718 | + unsigned int *nbuffers, unsigned int *nplanes, | ||
719 | + unsigned int sizes[], void *alloc_ctxs[]) | ||
720 | +{ | ||
721 | + struct cssp_cam_dev *dev = vb2_get_drv_priv(vq); | ||
722 | + unsigned long size; | ||
723 | + | ||
724 | + size = dev->sizeimage; | ||
725 | + | ||
726 | + if (0 == *nbuffers) | ||
727 | + *nbuffers = 32; | ||
728 | + | ||
729 | + while (size * *nbuffers > vid_limit * 1024 * 1024) | ||
730 | + (*nbuffers)--; | ||
731 | + | ||
732 | + *nplanes = 1; | ||
733 | + | ||
734 | + sizes[0] = size; | ||
735 | + | ||
736 | + alloc_ctxs[0] = dev->dma_cont_ctx; | ||
737 | + | ||
738 | + dprintk(dev, 1, "%s, count=%d, size=%ld\n", __func__, *nbuffers, size); | ||
739 | + | ||
740 | + return 0; | ||
741 | +} | ||
742 | + | ||
743 | +static int buffer_init(struct vb2_buffer *vb) | ||
744 | +{ | ||
745 | + struct cssp_cam_dev *dev = vb2_get_drv_priv(vb->vb2_queue); | ||
746 | + | ||
747 | + BUG_ON(NULL == dev->fmt); | ||
748 | + | ||
749 | + /* | ||
750 | + * This callback is called once per buffer, after its allocation. | ||
751 | + * | ||
752 | + * Vivi does not allow changing format during streaming, but it is | ||
753 | + * possible to do so when streaming is paused (i.e. in streamoff state). | ||
754 | + * Buffers however are not freed when going into streamoff and so | ||
755 | + * buffer size verification has to be done in buffer_prepare, on each | ||
756 | + * qbuf. | ||
757 | + * It would be best to move verification code here to buf_init and | ||
758 | + * s_fmt though. | ||
759 | + */ | ||
760 | + | ||
761 | + return 0; | ||
762 | +} | ||
763 | + | ||
764 | +static int buffer_prepare(struct vb2_buffer *vb) | ||
765 | +{ | ||
766 | + struct cssp_cam_dev *dev = vb2_get_drv_priv(vb->vb2_queue); | ||
767 | + struct cssp_cam_buffer *buf = container_of(vb, struct cssp_cam_buffer, vb); | ||
768 | + unsigned long size; | ||
769 | + | ||
770 | + dprintk(dev, 1, "%s, field=%d\n", __func__, vb->v4l2_buf.field); | ||
771 | + | ||
772 | + BUG_ON(NULL == dev->fmt); | ||
773 | + | ||
774 | + /* | ||
775 | + * Theses properties only change when queue is idle, see s_fmt. | ||
776 | + * The below checks should not be performed here, on each | ||
777 | + * buffer_prepare (i.e. on each qbuf). Most of the code in this function | ||
778 | + * should thus be moved to buffer_init and s_fmt. | ||
779 | + */ | ||
780 | + if (dev->width < 48 || dev->width > MAX_WIDTH || | ||
781 | + dev->height < 32 || dev->height > MAX_HEIGHT) | ||
782 | + return -EINVAL; | ||
783 | + | ||
784 | + size = dev->sizeimage; | ||
785 | + if (vb2_plane_size(vb, 0) < size) { | ||
786 | + dprintk(dev, 1, "%s data will not fit into plane (%lu < %lu)\n", | ||
787 | + __func__, vb2_plane_size(vb, 0), size); | ||
788 | + return -EINVAL; | ||
789 | + } | ||
790 | + | ||
791 | + vb2_set_plane_payload(&buf->vb, 0, size); | ||
792 | + | ||
793 | + buf->fmt = dev->fmt; | ||
794 | + | ||
795 | + return 0; | ||
796 | +} | ||
797 | + | ||
798 | +static int buffer_finish(struct vb2_buffer *vb) | ||
799 | +{ | ||
800 | + struct cssp_cam_dev *dev = vb2_get_drv_priv(vb->vb2_queue); | ||
801 | + dprintk(dev, 1, "%s\n", __func__); | ||
802 | + return 0; | ||
803 | +} | ||
804 | + | ||
805 | +static void buffer_cleanup(struct vb2_buffer *vb) | ||
806 | +{ | ||
807 | + struct cssp_cam_dev *dev = vb2_get_drv_priv(vb->vb2_queue); | ||
808 | + dprintk(dev, 1, "%s\n", __func__); | ||
809 | +} | ||
810 | + | ||
811 | +static void buffer_queue(struct vb2_buffer *vb) | ||
812 | +{ | ||
813 | + struct cssp_cam_dev *dev = vb2_get_drv_priv(vb->vb2_queue); | ||
814 | + struct cssp_cam_buffer *buf = container_of(vb, struct cssp_cam_buffer, vb); | ||
815 | + struct cssp_cam_dmaqueue *vidq = &dev->vidq; | ||
816 | + unsigned long flags = 0; | ||
817 | + | ||
818 | + dprintk(dev, 1, "%s\n", __func__); | ||
819 | + | ||
820 | + if (dev->streaming_started && !dev->current_vb) { | ||
821 | + trigger_dma_transfer_to_buf(dev, &buf->vb); | ||
822 | + } else { | ||
823 | + spin_lock_irqsave(&dev->slock, flags); | ||
824 | + list_add_tail(&buf->list, &vidq->active); | ||
825 | + spin_unlock_irqrestore(&dev->slock, flags); | ||
826 | + } | ||
827 | +} | ||
828 | + | ||
829 | +static int start_streaming(struct vb2_queue *vq, unsigned int count) | ||
830 | +{ | ||
831 | + struct cssp_cam_dev *dev = vb2_get_drv_priv(vq); | ||
832 | + int ret; | ||
833 | + | ||
834 | + dprintk(dev, 1, "%s\n", __func__); | ||
835 | + | ||
836 | + ret = start_camera_sensor(dev); | ||
837 | + if (ret != 0) | ||
838 | + return ret; | ||
839 | + | ||
840 | + // Enable DMA | ||
841 | + edma_start(dev->dma_ch); | ||
842 | + | ||
843 | + dev->streaming_started = 1; | ||
844 | + | ||
845 | + /* check if we have new buffer queued */ | ||
846 | + dequeue_buffer_for_dma(dev); | ||
847 | + | ||
848 | + return 0; | ||
849 | +} | ||
850 | + | ||
851 | +/* abort streaming and wait for last buffer */ | ||
852 | +static int stop_streaming(struct vb2_queue *vq) | ||
853 | +{ | ||
854 | + struct cssp_cam_dev *dev = vb2_get_drv_priv(vq); | ||
855 | + struct cssp_cam_dmaqueue *dma_q = &dev->vidq; | ||
856 | + | ||
857 | + dprintk(dev, 1, "%s\n", __func__); | ||
858 | + | ||
859 | + // Disable DMA | ||
860 | + edma_stop(dev->dma_ch); | ||
861 | + | ||
862 | + // Disable data capture | ||
863 | + dev->mode &= ~ENABLE; | ||
864 | + writew(dev->mode, dev->reg_base_virt + REG_MODE); | ||
865 | + readw(dev->reg_base_virt + REG_MODE); | ||
866 | + | ||
867 | + stop_camera_sensor(dev); | ||
868 | + | ||
869 | + dev->streaming_started = 0; | ||
870 | + | ||
871 | + /* Release all active buffers */ | ||
872 | + while (!list_empty(&dma_q->active)) { | ||
873 | + struct cssp_cam_buffer *buf; | ||
874 | + | ||
875 | + buf = list_entry(dma_q->active.next, struct cssp_cam_buffer, list); | ||
876 | + list_del(&buf->list); | ||
877 | + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); | ||
878 | + dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index); | ||
879 | + } | ||
880 | + | ||
881 | + dev->current_vb = NULL; | ||
882 | + | ||
883 | + return 0; | ||
884 | +} | ||
885 | + | ||
886 | +static void cssp_cam_lock(struct vb2_queue *vq) | ||
887 | +{ | ||
888 | + struct cssp_cam_dev *dev = vb2_get_drv_priv(vq); | ||
889 | + mutex_lock(&dev->mutex); | ||
890 | +} | ||
891 | + | ||
892 | +static void cssp_cam_unlock(struct vb2_queue *vq) | ||
893 | +{ | ||
894 | + struct cssp_cam_dev *dev = vb2_get_drv_priv(vq); | ||
895 | + mutex_unlock(&dev->mutex); | ||
896 | +} | ||
897 | + | ||
898 | +static struct vb2_ops cssp_cam_video_qops = { | ||
899 | + .queue_setup = queue_setup, | ||
900 | + .buf_init = buffer_init, | ||
901 | + .buf_prepare = buffer_prepare, | ||
902 | + .buf_finish = buffer_finish, | ||
903 | + .buf_cleanup = buffer_cleanup, | ||
904 | + .buf_queue = buffer_queue, | ||
905 | + .start_streaming = start_streaming, | ||
906 | + .stop_streaming = stop_streaming, | ||
907 | + .wait_prepare = cssp_cam_unlock, | ||
908 | + .wait_finish = cssp_cam_lock, | ||
909 | +}; | ||
910 | + | ||
911 | + | ||
912 | +/* ------------------------------------------------------------------ | ||
913 | + IOCTL vidioc handling | ||
914 | + ------------------------------------------------------------------*/ | ||
915 | + | ||
916 | +static int vidioc_querycap(struct file *file, void *priv, | ||
917 | + struct v4l2_capability *cap) | ||
918 | +{ | ||
919 | + struct cssp_cam_dev *dev = video_drvdata(file); | ||
920 | + | ||
921 | + strcpy(cap->driver, "cssp_camera"); | ||
922 | + strcpy(cap->card, "cssp_camera"); | ||
923 | + strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info)); | ||
924 | + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | | ||
925 | + V4L2_CAP_READWRITE; | ||
926 | + return 0; | ||
927 | +} | ||
928 | + | ||
929 | +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, | ||
930 | + struct v4l2_fmtdesc *f) | ||
931 | +{ | ||
932 | + struct cssp_cam_fmt *fmt; | ||
933 | + | ||
934 | + if (f->index >= ARRAY_SIZE(formats)) | ||
935 | + return -EINVAL; | ||
936 | + | ||
937 | + fmt = &formats[f->index]; | ||
938 | + | ||
939 | + strlcpy(f->description, fmt->name, sizeof(f->description)); | ||
940 | + f->pixelformat = fmt->fourcc; | ||
941 | + return 0; | ||
942 | +} | ||
943 | + | ||
944 | +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, | ||
945 | + struct v4l2_format *f) | ||
946 | +{ | ||
947 | + struct cssp_cam_dev *dev = video_drvdata(file); | ||
948 | + | ||
949 | + f->fmt.pix.width = dev->width; | ||
950 | + f->fmt.pix.height = dev->height; | ||
951 | + f->fmt.pix.field = dev->field; | ||
952 | + f->fmt.pix.pixelformat = dev->fmt->fourcc; | ||
953 | + f->fmt.pix.bytesperline = dev->bytesperline; | ||
954 | + f->fmt.pix.sizeimage = dev->sizeimage; | ||
955 | + f->fmt.pix.colorspace = dev->colorspace; | ||
956 | + | ||
957 | + return 0; | ||
958 | +} | ||
959 | + | ||
960 | +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, | ||
961 | + struct v4l2_format *f) | ||
962 | +{ | ||
963 | + struct cssp_cam_dev *dev = video_drvdata(file); | ||
964 | + struct cssp_cam_fmt *fmt; | ||
965 | + struct v4l2_mbus_framefmt mbus_fmt; | ||
966 | + struct v4l2_pix_format *pix = &f->fmt.pix; | ||
967 | + | ||
968 | + fmt = get_format(f); | ||
969 | + if (!fmt) { | ||
970 | + dprintk(dev, 1, "Fourcc format (0x%08x) invalid.\n", | ||
971 | + f->fmt.pix.pixelformat); | ||
972 | + return -EINVAL; | ||
973 | + } | ||
974 | + | ||
975 | + v4l2_fill_mbus_format(&mbus_fmt, pix, fmt->code); | ||
976 | + v4l2_subdev_call(dev->subdev, video, try_mbus_fmt, &mbus_fmt); | ||
977 | + v4l2_fill_pix_format(pix, &mbus_fmt); | ||
978 | + pix->bytesperline = (pix->width * fmt->depth) >> 3; | ||
979 | + pix->sizeimage = pix->height * pix->bytesperline; | ||
980 | + | ||
981 | + return 0; | ||
982 | +} | ||
983 | + | ||
984 | +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, | ||
985 | + struct v4l2_format *f) | ||
986 | +{ | ||
987 | + struct cssp_cam_dev *dev = video_drvdata(file); | ||
988 | + struct vb2_queue *q = &dev->vb_vidq; | ||
989 | + struct v4l2_pix_format *pix = &f->fmt.pix; | ||
990 | + struct v4l2_mbus_framefmt mbus_fmt; | ||
991 | + | ||
992 | + int ret = vidioc_try_fmt_vid_cap(file, priv, f); | ||
993 | + if (ret < 0) | ||
994 | + return ret; | ||
995 | + | ||
996 | + if (vb2_is_streaming(q)) { | ||
997 | + dprintk(dev, 1, "%s device busy\n", __func__); | ||
998 | + return -EBUSY; | ||
999 | + } | ||
1000 | + | ||
1001 | + dev->fmt = get_format(f); | ||
1002 | + dev->width = f->fmt.pix.width; | ||
1003 | + dev->height = f->fmt.pix.height; | ||
1004 | + dev->field = f->fmt.pix.field; | ||
1005 | + dev->colorspace = f->fmt.pix.colorspace; | ||
1006 | + dev->bytesperline = f->fmt.pix.bytesperline; | ||
1007 | + dev->sizeimage = f->fmt.pix.sizeimage; | ||
1008 | + | ||
1009 | + /* Set the sensor into the new format */ | ||
1010 | + v4l2_fill_mbus_format(&mbus_fmt, pix, dev->fmt->code); | ||
1011 | + v4l2_subdev_call(dev->subdev, video, s_mbus_fmt, &mbus_fmt); | ||
1012 | + | ||
1013 | + /* Set the EDMA for the new resolution */ | ||
1014 | + dev->dma_tr_params.a_b_cnt = ACNT(BYTES_PER_DMA_EVT) | BCNT(dev->bytesperline / BYTES_PER_DMA_EVT); | ||
1015 | + dev->dma_tr_params.link_bcntrld = BCNTRLD(dev->bytesperline / BYTES_PER_DMA_EVT) | LINK(0xffff); | ||
1016 | + dev->dma_tr_params.ccnt = CCNT(dev->height); | ||
1017 | + | ||
1018 | + return 0; | ||
1019 | +} | ||
1020 | + | ||
1021 | +static int vidioc_reqbufs(struct file *file, void *priv, | ||
1022 | + struct v4l2_requestbuffers *p) | ||
1023 | +{ | ||
1024 | + struct cssp_cam_dev *dev = video_drvdata(file); | ||
1025 | + return vb2_reqbufs(&dev->vb_vidq, p); | ||
1026 | +} | ||
1027 | + | ||
1028 | +static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) | ||
1029 | +{ | ||
1030 | + struct cssp_cam_dev *dev = video_drvdata(file); | ||
1031 | + return vb2_querybuf(&dev->vb_vidq, p); | ||
1032 | +} | ||
1033 | + | ||
1034 | +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) | ||
1035 | +{ | ||
1036 | + struct cssp_cam_dev *dev = video_drvdata(file); | ||
1037 | + return vb2_qbuf(&dev->vb_vidq, p); | ||
1038 | +} | ||
1039 | + | ||
1040 | +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) | ||
1041 | +{ | ||
1042 | + struct cssp_cam_dev *dev = video_drvdata(file); | ||
1043 | + return vb2_dqbuf(&dev->vb_vidq, p, file->f_flags & O_NONBLOCK); | ||
1044 | +} | ||
1045 | + | ||
1046 | +static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) | ||
1047 | +{ | ||
1048 | + struct cssp_cam_dev *dev = video_drvdata(file); | ||
1049 | + return vb2_streamon(&dev->vb_vidq, i); | ||
1050 | +} | ||
1051 | + | ||
1052 | +static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) | ||
1053 | +{ | ||
1054 | + struct cssp_cam_dev *dev = video_drvdata(file); | ||
1055 | + return vb2_streamoff(&dev->vb_vidq, i); | ||
1056 | +} | ||
1057 | + | ||
1058 | +static int vidioc_log_status(struct file *file, void *priv) | ||
1059 | +{ | ||
1060 | + struct cssp_cam_dev *dev = video_drvdata(file); | ||
1061 | + | ||
1062 | + v4l2_ctrl_handler_log_status(&dev->ctrl_handler, dev->v4l2_dev.name); | ||
1063 | + return 0; | ||
1064 | +} | ||
1065 | + | ||
1066 | +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) | ||
1067 | +{ | ||
1068 | + return 0; | ||
1069 | +} | ||
1070 | + | ||
1071 | +/* only one input in this sample driver */ | ||
1072 | +static int vidioc_enum_input(struct file *file, void *priv, | ||
1073 | + struct v4l2_input *inp) | ||
1074 | +{ | ||
1075 | + return -EINVAL; | ||
1076 | + | ||
1077 | + inp->type = V4L2_INPUT_TYPE_CAMERA; | ||
1078 | + inp->std = V4L2_STD_525_60; | ||
1079 | + sprintf(inp->name, "Camera %u", inp->index); | ||
1080 | + return 0; | ||
1081 | +} | ||
1082 | + | ||
1083 | +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) | ||
1084 | +{ | ||
1085 | + struct cssp_cam_dev *dev = video_drvdata(file); | ||
1086 | + | ||
1087 | + *i = dev->input; | ||
1088 | + | ||
1089 | + return 0; | ||
1090 | +} | ||
1091 | + | ||
1092 | +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) | ||
1093 | +{ | ||
1094 | + struct cssp_cam_dev *dev = video_drvdata(file); | ||
1095 | + | ||
1096 | + return -EINVAL; | ||
1097 | + | ||
1098 | + if (i == dev->input) | ||
1099 | + return 0; | ||
1100 | + | ||
1101 | + dev->input = i; | ||
1102 | + | ||
1103 | + return 0; | ||
1104 | +} | ||
1105 | + | ||
1106 | +static int vidioc_subscribe_event(struct v4l2_fh *fh, | ||
1107 | + struct v4l2_event_subscription *sub) | ||
1108 | +{ | ||
1109 | + switch (sub->type) { | ||
1110 | + case V4L2_EVENT_CTRL: | ||
1111 | + return v4l2_event_subscribe(fh, sub, 0); | ||
1112 | + default: | ||
1113 | + return -EINVAL; | ||
1114 | + } | ||
1115 | +} | ||
1116 | + | ||
1117 | +static const struct v4l2_ioctl_ops cssp_cam_ioctl_ops = { | ||
1118 | + .vidioc_querycap = vidioc_querycap, | ||
1119 | + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, | ||
1120 | + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, | ||
1121 | + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, | ||
1122 | + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, | ||
1123 | + .vidioc_reqbufs = vidioc_reqbufs, | ||
1124 | + .vidioc_querybuf = vidioc_querybuf, | ||
1125 | + .vidioc_qbuf = vidioc_qbuf, | ||
1126 | + .vidioc_dqbuf = vidioc_dqbuf, | ||
1127 | + .vidioc_s_std = vidioc_s_std, | ||
1128 | + .vidioc_enum_input = vidioc_enum_input, | ||
1129 | + .vidioc_g_input = vidioc_g_input, | ||
1130 | + .vidioc_s_input = vidioc_s_input, | ||
1131 | + .vidioc_streamon = vidioc_streamon, | ||
1132 | + .vidioc_streamoff = vidioc_streamoff, | ||
1133 | + .vidioc_log_status = vidioc_log_status, | ||
1134 | + .vidioc_subscribe_event = vidioc_subscribe_event, | ||
1135 | + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | ||
1136 | +}; | ||
1137 | + | ||
1138 | + | ||
1139 | +/* ------------------------------------------------------------------ | ||
1140 | + File operations | ||
1141 | + ------------------------------------------------------------------*/ | ||
1142 | + | ||
1143 | +static unsigned int video_poll(struct file *file, struct poll_table_struct *wait) | ||
1144 | +{ | ||
1145 | + struct cssp_cam_dev *dev = video_drvdata(file); | ||
1146 | + struct v4l2_fh *fh = file->private_data; | ||
1147 | + struct vb2_queue *q = &dev->vb_vidq; | ||
1148 | + unsigned int res; | ||
1149 | + | ||
1150 | + dprintk(dev, 1, "%s\n", __func__); | ||
1151 | + res = vb2_poll(q, file, wait); | ||
1152 | + if (v4l2_event_pending(fh)) | ||
1153 | + res |= POLLPRI; | ||
1154 | + else | ||
1155 | + poll_wait(file, &fh->wait, wait); | ||
1156 | + return res; | ||
1157 | +} | ||
1158 | + | ||
1159 | +static int video_mmap(struct file *file, struct vm_area_struct *vma) | ||
1160 | +{ | ||
1161 | + struct cssp_cam_dev *dev = video_drvdata(file); | ||
1162 | + int ret; | ||
1163 | + | ||
1164 | + dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma); | ||
1165 | + | ||
1166 | + ret = vb2_mmap(&dev->vb_vidq, vma); | ||
1167 | + dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n", | ||
1168 | + (unsigned long)vma->vm_start, | ||
1169 | + (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, | ||
1170 | + ret); | ||
1171 | + return ret; | ||
1172 | +} | ||
1173 | + | ||
1174 | +static ssize_t video_read(struct file *file, char __user *buf, size_t size, loff_t *offset) | ||
1175 | +{ | ||
1176 | + struct cssp_cam_dev *cam_dev = video_drvdata(file); | ||
1177 | + | ||
1178 | + dprintk(cam_dev, 1, "read called\n"); | ||
1179 | + return vb2_read(&cam_dev->vb_vidq, buf, size, offset, file->f_flags & O_NONBLOCK); | ||
1180 | +} | ||
1181 | + | ||
1182 | +static int video_close(struct file *file) | ||
1183 | +{ | ||
1184 | + struct video_device *vdev = video_devdata(file); | ||
1185 | + struct cssp_cam_dev *cam_dev = video_drvdata(file); | ||
1186 | + | ||
1187 | + dprintk(cam_dev, 1, "close called (dev=%s), file %p\n", | ||
1188 | + video_device_node_name(vdev), file); | ||
1189 | + | ||
1190 | + if (v4l2_fh_is_singular_file(file)) | ||
1191 | + vb2_queue_release(&cam_dev->vb_vidq); | ||
1192 | + return v4l2_fh_release(file); | ||
1193 | +} | ||
1194 | + | ||
1195 | +static const struct v4l2_file_operations cssp_cam_fops = { | ||
1196 | + .owner = THIS_MODULE, | ||
1197 | + .open = v4l2_fh_open, | ||
1198 | + .release = video_close, | ||
1199 | + .read = video_read, | ||
1200 | + .poll = video_poll, | ||
1201 | + .unlocked_ioctl = video_ioctl2, | ||
1202 | + .mmap = video_mmap, | ||
1203 | +}; | ||
1204 | + | ||
1205 | + | ||
1206 | +/* ------------------------------------------------------------------ | ||
1207 | + Driver initialization | ||
1208 | + ------------------------------------------------------------------*/ | ||
1209 | + | ||
1210 | +static struct video_device cssp_cam_template = { | ||
1211 | + .name = "cssp_camera", | ||
1212 | + .fops = &cssp_cam_fops, | ||
1213 | + .ioctl_ops = &cssp_cam_ioctl_ops, | ||
1214 | + .minor = -1, | ||
1215 | + .release = video_device_release, | ||
1216 | + .tvnorms = V4L2_STD_525_60, | ||
1217 | + .current_norm = V4L2_STD_NTSC_M, | ||
1218 | +}; | ||
1219 | + | ||
1220 | +static int __init video_probe(struct cssp_cam_dev *cam_dev) | ||
1221 | +{ | ||
1222 | + struct video_device *vfd; | ||
1223 | + struct v4l2_ctrl_handler *hdl; | ||
1224 | + struct vb2_queue *q; | ||
1225 | + int ret = 0; | ||
1226 | + | ||
1227 | + snprintf(cam_dev->v4l2_dev.name, sizeof(cam_dev->v4l2_dev.name), | ||
1228 | + "%s-%03d", "cssp_camera", 0); | ||
1229 | + ret = v4l2_device_register(NULL, &cam_dev->v4l2_dev); | ||
1230 | + if (ret) | ||
1231 | + goto free_dev; | ||
1232 | + | ||
1233 | + cam_dev->fmt = &formats[0]; | ||
1234 | + cam_dev->width = VGA_WIDTH; | ||
1235 | + cam_dev->height = VGA_HEIGHT; | ||
1236 | + cam_dev->sizeimage = VGA_WIDTH * VGA_HEIGHT * BYTES_PER_PIXEL; | ||
1237 | + hdl = &cam_dev->ctrl_handler; | ||
1238 | + v4l2_ctrl_handler_init(hdl, 0); | ||
1239 | + | ||
1240 | + if (hdl->error) { | ||
1241 | + ret = hdl->error; | ||
1242 | + goto unreg_dev; | ||
1243 | + } | ||
1244 | + cam_dev->v4l2_dev.ctrl_handler = hdl; | ||
1245 | + | ||
1246 | + /* initialize locks */ | ||
1247 | + spin_lock_init(&cam_dev->slock); | ||
1248 | + | ||
1249 | + /* initialize queue */ | ||
1250 | + q = &cam_dev->vb_vidq; | ||
1251 | + memset(q, 0, sizeof(cam_dev->vb_vidq)); | ||
1252 | + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1253 | + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; | ||
1254 | + q->drv_priv = cam_dev; | ||
1255 | + q->buf_struct_size = sizeof(struct cssp_cam_buffer); | ||
1256 | + q->ops = &cssp_cam_video_qops; | ||
1257 | + q->mem_ops = &vb2_dma_contig_memops; | ||
1258 | + | ||
1259 | + vb2_queue_init(q); | ||
1260 | + | ||
1261 | + mutex_init(&cam_dev->mutex); | ||
1262 | + | ||
1263 | + /* init video dma queues */ | ||
1264 | + INIT_LIST_HEAD(&cam_dev->vidq.active); | ||
1265 | + | ||
1266 | + ret = -ENOMEM; | ||
1267 | + vfd = video_device_alloc(); | ||
1268 | + if (!vfd) | ||
1269 | + goto unreg_dev; | ||
1270 | + | ||
1271 | + *vfd = cssp_cam_template; | ||
1272 | + vfd->debug = debug; | ||
1273 | + vfd->v4l2_dev = &cam_dev->v4l2_dev; | ||
1274 | + set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); | ||
1275 | + | ||
1276 | + /* | ||
1277 | + * Provide a mutex to v4l2 core. It will be used to protect | ||
1278 | + * all fops and v4l2 ioctls. | ||
1279 | + */ | ||
1280 | + vfd->lock = &cam_dev->mutex; | ||
1281 | + | ||
1282 | + ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); | ||
1283 | + if (ret < 0) | ||
1284 | + goto rel_vdev; | ||
1285 | + | ||
1286 | + video_set_drvdata(vfd, cam_dev); | ||
1287 | + | ||
1288 | + if (video_nr != -1) | ||
1289 | + video_nr++; | ||
1290 | + | ||
1291 | + cam_dev->vdev = vfd; | ||
1292 | + v4l2_info(&cam_dev->v4l2_dev, "V4L2 device registered as %s\n", | ||
1293 | + video_device_node_name(vfd)); | ||
1294 | + | ||
1295 | + return 0; | ||
1296 | + | ||
1297 | +rel_vdev: | ||
1298 | + video_device_release(vfd); | ||
1299 | +unreg_dev: | ||
1300 | + v4l2_ctrl_handler_free(hdl); | ||
1301 | + v4l2_device_unregister(&cam_dev->v4l2_dev); | ||
1302 | +free_dev: | ||
1303 | + return ret; | ||
1304 | +} | ||
1305 | + | ||
1306 | +static int video_remove(struct cssp_cam_dev *cam_dev) | ||
1307 | +{ | ||
1308 | + if (cam_dev->dma_cont_ctx != NULL) | ||
1309 | + vb2_dma_contig_cleanup_ctx(cam_dev->dma_cont_ctx); | ||
1310 | + | ||
1311 | + v4l2_info(&cam_dev->v4l2_dev, "unregistering %s\n", | ||
1312 | + video_device_node_name(cam_dev->vdev)); | ||
1313 | + video_unregister_device(cam_dev->vdev); | ||
1314 | + v4l2_device_unregister(&cam_dev->v4l2_dev); | ||
1315 | + v4l2_ctrl_handler_free(&cam_dev->ctrl_handler); | ||
1316 | + | ||
1317 | + return 0; | ||
1318 | +} | ||
1319 | + | ||
1320 | +static int __init cssp_cam_probe(struct platform_device *pdev) | ||
1321 | +{ | ||
1322 | + struct cssp_cam_dev *cam_dev; | ||
1323 | + int ret = 0; | ||
1324 | + struct cssp_cam_platform_data *cssp_cam_platform_data; | ||
1325 | + | ||
1326 | + cssp_cam_platform_data = (struct cssp_cam_platform_data *) pdev->dev.platform_data; | ||
1327 | + if (cssp_cam_platform_data == NULL) { | ||
1328 | + printk(KERN_ERR "[%s]: missing platform data\n", pdev->name); | ||
1329 | + return -ENODEV; | ||
1330 | + } | ||
1331 | + | ||
1332 | + if (cssp_cam_platform_data->cam_i2c_board_info == NULL) { | ||
1333 | + printk(KERN_ERR "[%s]: missing camera i2c board info\n", pdev->name); | ||
1334 | + return -ENODEV; | ||
1335 | + } | ||
1336 | + | ||
1337 | + cam_dev = kzalloc(sizeof(*cam_dev), GFP_KERNEL); | ||
1338 | + if (!cam_dev) | ||
1339 | + return -ENOMEM; | ||
1340 | + | ||
1341 | + cam_dev->pdev = pdev; | ||
1342 | + platform_set_drvdata(pdev, cam_dev); | ||
1343 | + | ||
1344 | + cam_dev->camera_board_info = cssp_cam_platform_data->cam_i2c_board_info; | ||
1345 | + | ||
1346 | + cam_dev->camera_clk = clk_get(&pdev->dev, cssp_cam_platform_data->cam_clk_name); | ||
1347 | + if (IS_ERR(cam_dev->camera_clk)) { | ||
1348 | + ret = PTR_ERR(cam_dev->camera_clk); | ||
1349 | + printk(KERN_ERR "[%s]: cannot clk_get %s\n", pdev->name, cssp_cam_platform_data->cam_clk_name); | ||
1350 | + goto fail0; | ||
1351 | + } | ||
1352 | + | ||
1353 | + ret = configure_cssp(cam_dev); | ||
1354 | + if (ret) | ||
1355 | + goto fail1; | ||
1356 | + | ||
1357 | + ret = configure_edma(cam_dev); | ||
1358 | + if (ret) | ||
1359 | + goto fail2; | ||
1360 | + | ||
1361 | + cam_dev->mode = FMT_2X8_EN | PCLK_POL | HS_EN; | ||
1362 | + | ||
1363 | + ret = configure_camera_sensor(cam_dev); | ||
1364 | + if (ret) { | ||
1365 | + printk(KERN_ERR "[%s]: camera sensor configuration failed\n", pdev->name); | ||
1366 | + goto fail3; | ||
1367 | + } | ||
1368 | + | ||
1369 | + cam_dev->dma_cont_ctx = vb2_dma_contig_init_ctx(&pdev->dev); | ||
1370 | + if (IS_ERR(cam_dev->dma_cont_ctx)) { | ||
1371 | + ret = PTR_ERR(cam_dev->dma_cont_ctx); | ||
1372 | + goto fail3; | ||
1373 | + } | ||
1374 | + | ||
1375 | + ret = video_probe(cam_dev); | ||
1376 | + if (ret) | ||
1377 | + goto fail4; | ||
1378 | + | ||
1379 | + return ret; | ||
1380 | + | ||
1381 | +fail4: | ||
1382 | + vb2_dma_contig_cleanup_ctx(cam_dev->dma_cont_ctx); | ||
1383 | + | ||
1384 | +fail3: | ||
1385 | + edma_free_channel(cam_dev->dma_ch); | ||
1386 | + | ||
1387 | +fail2: | ||
1388 | + gpio_free(cam_dev->reset_pin); | ||
1389 | + iounmap((void *)cam_dev->reg_base_virt); | ||
1390 | + release_mem_region(cam_dev->reg_base_phys, cam_dev->reg_size); | ||
1391 | + | ||
1392 | +fail1: | ||
1393 | + clk_put(cam_dev->camera_clk); | ||
1394 | + | ||
1395 | +fail0: | ||
1396 | + kfree(cam_dev); | ||
1397 | + | ||
1398 | + return ret; | ||
1399 | +} | ||
1400 | + | ||
1401 | +static int cssp_cam_remove(struct platform_device *pdev) | ||
1402 | +{ | ||
1403 | + struct cssp_cam_dev *cam = platform_get_drvdata(pdev); | ||
1404 | + | ||
1405 | + iounmap((void *)cam->reg_base_virt); | ||
1406 | + | ||
1407 | + release_mem_region(cam->reg_base_phys, cam->reg_size); | ||
1408 | + | ||
1409 | + gpio_free(cam->reset_pin); | ||
1410 | + | ||
1411 | + edma_free_channel(cam->dma_ch); | ||
1412 | + | ||
1413 | + video_remove(cam); | ||
1414 | + | ||
1415 | + clk_put(cam->camera_clk); | ||
1416 | + | ||
1417 | + kfree(cam); | ||
1418 | + | ||
1419 | + printk(KERN_INFO "[%s]: removed\n", pdev->name); | ||
1420 | + | ||
1421 | + return 0; | ||
1422 | +} | ||
1423 | + | ||
1424 | + | ||
1425 | +static struct platform_driver cssp_cam_driver = { | ||
1426 | + .probe = cssp_cam_probe, | ||
1427 | + .remove = __devexit_p(cssp_cam_remove), | ||
1428 | + .driver = { | ||
1429 | + .name = "cssp-camera", | ||
1430 | + .owner = THIS_MODULE, | ||
1431 | + }, | ||
1432 | +}; | ||
1433 | + | ||
1434 | + | ||
1435 | +static int __init cssp_cam_init(void) | ||
1436 | +{ | ||
1437 | + return platform_driver_register(&cssp_cam_driver); | ||
1438 | +} | ||
1439 | + | ||
1440 | +static void __exit cssp_cam_exit(void) | ||
1441 | +{ | ||
1442 | + platform_driver_unregister(&cssp_cam_driver); | ||
1443 | +} | ||
1444 | + | ||
1445 | + | ||
1446 | +module_init(cssp_cam_init); | ||
1447 | +module_exit(cssp_cam_exit); | ||
1448 | + | ||
1449 | +/* | ||
1450 | + * Macros sets license, author and description | ||
1451 | + */ | ||
1452 | +MODULE_LICENSE("GPLv2"); | ||
1453 | +MODULE_AUTHOR("Dan Aizenstros, Damian Eppel, Przemek Szewczyk"); | ||
1454 | +MODULE_DESCRIPTION("QuickLogic Camera Interface driver"); | ||
1455 | + | ||
1456 | diff --git a/drivers/media/video/cssp_camera/cssp_camera.h b/drivers/media/video/cssp_camera/cssp_camera.h | ||
1457 | new file mode 100644 | ||
1458 | index 0000000..d018ca1 | ||
1459 | --- /dev/null | ||
1460 | +++ b/drivers/media/video/cssp_camera/cssp_camera.h | ||
1461 | @@ -0,0 +1,148 @@ | ||
1462 | +/* | ||
1463 | + * cssp-camera driver | ||
1464 | + * | ||
1465 | + * Based on Vivi driver | ||
1466 | + * | ||
1467 | + * Copyright (C) 2012 QuickLogic Corp. | ||
1468 | + * | ||
1469 | + * Developed for QuickLogic by: | ||
1470 | + * Damian Eppel <damian.eppel@teleca.com> | ||
1471 | + * Przemek Szewczyk <przemek.szewczyk@teleca.com> | ||
1472 | + * Dan Aizenstros <daizenstros@quicklogic.com> | ||
1473 | + * | ||
1474 | + * This program is free software; you can redistribute it and/or modify | ||
1475 | + * it under the terms of the GNU General Public License version 2 as | ||
1476 | + * published by the Free Software Foundation. | ||
1477 | + * | ||
1478 | + */ | ||
1479 | + | ||
1480 | +#ifndef CSSP_CAMERA_H | ||
1481 | +#define CSSP_CAMERA_H | ||
1482 | + | ||
1483 | + | ||
1484 | +static unsigned video_nr = -1; | ||
1485 | +module_param(video_nr, uint, 0644); | ||
1486 | +MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect"); | ||
1487 | + | ||
1488 | +static unsigned debug; | ||
1489 | +module_param(debug, uint, 0644); | ||
1490 | +MODULE_PARM_DESC(debug, "activates debug info"); | ||
1491 | + | ||
1492 | +static unsigned int vid_limit = 1; | ||
1493 | +module_param(vid_limit, uint, 0644); | ||
1494 | +MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); | ||
1495 | + | ||
1496 | +#define dprintk(dev, level, fmt, arg...) \ | ||
1497 | + v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg) | ||
1498 | + | ||
1499 | +#define VGA_WIDTH 640 | ||
1500 | +#define VGA_HEIGHT 480 | ||
1501 | + | ||
1502 | +#define MAX_WIDTH 2048 | ||
1503 | +#define MAX_HEIGHT 1536 | ||
1504 | + | ||
1505 | +#define VGA_RES (VGA_WIDTH * VGA_HEIGHT) | ||
1506 | +#define BYTES_PER_PIXEL 2 | ||
1507 | +#define BYTES_PER_DMA_EVT 32 | ||
1508 | + | ||
1509 | +/* PaRAM.opt: */ | ||
1510 | +#define TCC(v) (((v) & 0x3f) << 12) | ||
1511 | +/* PaRAM.a_b_cnt: */ | ||
1512 | +#define ACNT(v) ((v) & 0xffff) | ||
1513 | +#define BCNT(v) (((v) & 0xffff) << 16) | ||
1514 | +/* PaRAM.src_dst_bidx: */ | ||
1515 | +#define SRCBIDX(v) ((v) & 0xffff) | ||
1516 | +#define DSTBIDX(v) (((v) & 0xffff) << 16) | ||
1517 | +/* PaRAM.link_bcntrld: */ | ||
1518 | +#define LINK(v) ((v) & 0xffff) | ||
1519 | +#define BCNTRLD(v) (((v) & 0xffff) << 16) | ||
1520 | +/* PaRAM.src_dst_cidx: */ | ||
1521 | +#define SRCCIDX(v) ((v) & 0xffff) | ||
1522 | +#define DSTCIDX(v) (((v) & 0xffff) << 16) | ||
1523 | +/* PaRAM.ccnt: */ | ||
1524 | +#define CCNT(v) ((v) & 0xffff) | ||
1525 | + | ||
1526 | + | ||
1527 | +struct cssp_cam_platform_data { | ||
1528 | + struct i2c_board_info *cam_i2c_board_info; | ||
1529 | + const char *cam_clk_name; | ||
1530 | + int dma_ch; | ||
1531 | + int gpio_reset_pin; | ||
1532 | +}; | ||
1533 | + | ||
1534 | + | ||
1535 | +/* ------------------------------------------------------------------ | ||
1536 | + video Basic structures | ||
1537 | + ------------------------------------------------------------------*/ | ||
1538 | + | ||
1539 | +struct cssp_cam_fmt { | ||
1540 | + char *name; | ||
1541 | + u32 fourcc; /* v4l2 format id */ | ||
1542 | + int depth; | ||
1543 | + enum v4l2_mbus_pixelcode code; | ||
1544 | +}; | ||
1545 | + | ||
1546 | +/* buffer for one video frame */ | ||
1547 | +struct cssp_cam_buffer { | ||
1548 | + /* common v4l buffer stuff -- must be first */ | ||
1549 | + struct vb2_buffer vb; | ||
1550 | + struct list_head list; | ||
1551 | + struct cssp_cam_fmt *fmt; | ||
1552 | +}; | ||
1553 | + | ||
1554 | +struct cssp_cam_dmaqueue { | ||
1555 | + struct list_head active; | ||
1556 | +}; | ||
1557 | + | ||
1558 | +struct cssp_cam_dev { | ||
1559 | + struct v4l2_device v4l2_dev; | ||
1560 | + struct v4l2_ctrl_handler ctrl_handler; | ||
1561 | + struct v4l2_subdev *subdev; | ||
1562 | + | ||
1563 | + spinlock_t slock; | ||
1564 | + struct mutex mutex; | ||
1565 | + | ||
1566 | + /* various device info */ | ||
1567 | + struct video_device *vdev; | ||
1568 | + struct platform_device *pdev; | ||
1569 | + | ||
1570 | + struct cssp_cam_dmaqueue vidq; | ||
1571 | + void *dma_cont_ctx; | ||
1572 | + int streaming_started; | ||
1573 | + struct vb2_buffer *current_vb; | ||
1574 | + | ||
1575 | + /* Input Number */ | ||
1576 | + int input; | ||
1577 | + | ||
1578 | + /* video capture */ | ||
1579 | + struct cssp_cam_fmt *fmt; | ||
1580 | + u32 width; | ||
1581 | + u32 height; | ||
1582 | + u32 bytesperline; | ||
1583 | + u32 sizeimage; | ||
1584 | + enum v4l2_colorspace colorspace; | ||
1585 | + struct vb2_queue vb_vidq; | ||
1586 | + enum v4l2_field field; | ||
1587 | + unsigned int field_count; | ||
1588 | + | ||
1589 | + | ||
1590 | + /* Camera Sensor */ | ||
1591 | + struct i2c_board_info *camera_board_info; | ||
1592 | + struct clk *camera_clk; | ||
1593 | + | ||
1594 | + unsigned int reg_base_virt; | ||
1595 | + unsigned int reg_base_phys; | ||
1596 | + resource_size_t reg_size; | ||
1597 | + u16 mode; | ||
1598 | + | ||
1599 | + struct edmacc_param dma_tr_params; | ||
1600 | + int dma_ch; | ||
1601 | + u64 dma_mask; | ||
1602 | + | ||
1603 | + int frame_cnt; | ||
1604 | + | ||
1605 | + int reset_pin; | ||
1606 | +}; | ||
1607 | + | ||
1608 | + | ||
1609 | +#endif /* CSSP_CAMERA_H */ | ||
1610 | -- | ||
1611 | 1.7.10 | ||
1612 | |||
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.2/beaglebone/0075-video-da8xx-fb-calculate-pixel-clock-period-for-the-.patch b/recipes-kernel/linux/linux-ti33x-psp-3.2/beaglebone/0075-video-da8xx-fb-calculate-pixel-clock-period-for-the-.patch new file mode 100644 index 00000000..face34b4 --- /dev/null +++ b/recipes-kernel/linux/linux-ti33x-psp-3.2/beaglebone/0075-video-da8xx-fb-calculate-pixel-clock-period-for-the-.patch | |||
@@ -0,0 +1,73 @@ | |||
1 | From e12d15eadf15f8119729a65ecca79529b4fe3863 Mon Sep 17 00:00:00 2001 | ||
2 | From: "Manjunathappa, Prakash" <prakash.pm@ti.com> | ||
3 | Date: Wed, 4 Jul 2012 17:10:16 +0530 | ||
4 | Subject: [PATCH 75/79] video:da8xx-fb: calculate pixel clock period for the | ||
5 | panel | ||
6 | |||
7 | Patch calculates pixel clock period in pico seconds and updates | ||
8 | the same in variable screen information structure. fbset utility | ||
9 | uses this information. | ||
10 | This patch is from upstream backport, bearing commit id | ||
11 | 12fa8350244d73b6111ec9bc6c2fd5d49fa601b5. | ||
12 | |||
13 | Signed-off-by: Manjunathappa, Prakash <prakash.pm@ti.com> | ||
14 | Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | ||
15 | Signed-off-by: Patil, Rachna <rachna@ti.com> | ||
16 | --- | ||
17 | drivers/video/da8xx-fb.c | 19 ++++++++++++++++++- | ||
18 | 1 file changed, 18 insertions(+), 1 deletion(-) | ||
19 | |||
20 | diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c | ||
21 | index 010a8bc..ddc251e 100644 | ||
22 | --- a/drivers/video/da8xx-fb.c | ||
23 | +++ b/drivers/video/da8xx-fb.c | ||
24 | @@ -37,6 +37,7 @@ | ||
25 | #include <linux/lcm.h> | ||
26 | #include <video/da8xx-fb.h> | ||
27 | #include <asm/mach-types.h> | ||
28 | +#include <asm/div64.h> | ||
29 | |||
30 | #define DRIVER_NAME "da8xx_lcdc" | ||
31 | |||
32 | @@ -192,7 +193,6 @@ static struct fb_var_screeninfo da8xx_fb_var __devinitdata = { | ||
33 | .activate = 0, | ||
34 | .height = -1, | ||
35 | .width = -1, | ||
36 | - .pixclock = 33333,/*Pico Sec*/ | ||
37 | .accel_flags = 0, | ||
38 | .left_margin = LEFT_MARGIN, | ||
39 | .right_margin = RIGHT_MARGIN, | ||
40 | @@ -1267,6 +1267,22 @@ static struct fb_ops da8xx_fb_ops = { | ||
41 | .fb_blank = cfb_blank, | ||
42 | }; | ||
43 | |||
44 | +/* Calculate and return pixel clock period in pico seconds */ | ||
45 | +static unsigned int da8xxfb_pixel_clk_period(struct da8xx_fb_par *par) | ||
46 | +{ | ||
47 | + unsigned int lcd_clk, div; | ||
48 | + unsigned int configured_pix_clk; | ||
49 | + unsigned long long pix_clk_period_picosec = 1000000000000ULL; | ||
50 | + | ||
51 | + lcd_clk = clk_get_rate(par->lcdc_clk); | ||
52 | + div = lcd_clk / par->pxl_clk; | ||
53 | + configured_pix_clk = (lcd_clk / div); | ||
54 | + | ||
55 | + do_div(pix_clk_period_picosec, configured_pix_clk); | ||
56 | + | ||
57 | + return pix_clk_period_picosec; | ||
58 | +} | ||
59 | + | ||
60 | static int __devinit fb_probe(struct platform_device *device) | ||
61 | { | ||
62 | struct da8xx_lcdc_platform_data *fb_pdata = | ||
63 | @@ -1437,6 +1453,7 @@ static int __devinit fb_probe(struct platform_device *device) | ||
64 | |||
65 | da8xx_fb_var.hsync_len = lcdc_info->hsw; | ||
66 | da8xx_fb_var.vsync_len = lcdc_info->vsw; | ||
67 | + da8xx_fb_var.pixclock = da8xxfb_pixel_clk_period(par); | ||
68 | |||
69 | da8xx_fb_var.right_margin = lcdc_info->hfp; | ||
70 | da8xx_fb_var.left_margin = lcdc_info->hbp; | ||
71 | -- | ||
72 | 1.7.10 | ||
73 | |||
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.2/beaglebone/0076-beaglebone-improve-GPMC-bus-timings-for-camera-cape.patch b/recipes-kernel/linux/linux-ti33x-psp-3.2/beaglebone/0076-beaglebone-improve-GPMC-bus-timings-for-camera-cape.patch new file mode 100644 index 00000000..5997367f --- /dev/null +++ b/recipes-kernel/linux/linux-ti33x-psp-3.2/beaglebone/0076-beaglebone-improve-GPMC-bus-timings-for-camera-cape.patch | |||
@@ -0,0 +1,105 @@ | |||
1 | From e81c7627c3d90209271a0f1e7486d0f779f05289 Mon Sep 17 00:00:00 2001 | ||
2 | From: Dan Aizenstros <daizenstros@quicklogic.com> | ||
3 | Date: Thu, 12 Jul 2012 12:31:08 -0400 | ||
4 | Subject: [PATCH 76/79] beaglebone: improve GPMC bus timings for camera cape | ||
5 | |||
6 | Signed-off-by: Dan Aizenstros <daizenstros@quicklogic.com> | ||
7 | Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> | ||
8 | --- | ||
9 | arch/arm/mach-omap2/board-am335xevm.c | 13 +++++++------ | ||
10 | drivers/media/video/cssp_camera/cssp_camera.c | 5 +---- | ||
11 | drivers/media/video/cssp_camera/cssp_camera.h | 2 +- | ||
12 | 3 files changed, 9 insertions(+), 11 deletions(-) | ||
13 | |||
14 | diff --git a/arch/arm/mach-omap2/board-am335xevm.c b/arch/arm/mach-omap2/board-am335xevm.c | ||
15 | index 6b4539e..82020fc 100644 | ||
16 | --- a/arch/arm/mach-omap2/board-am335xevm.c | ||
17 | +++ b/arch/arm/mach-omap2/board-am335xevm.c | ||
18 | @@ -1895,9 +1895,10 @@ static struct gpmc_timings cssp_timings = { | ||
19 | /* Minimum clock period for synchronous mode (in picoseconds) */ | ||
20 | .sync_clk = 10000, | ||
21 | |||
22 | + /* CS signal timings corresponding to GPMC_CONFIG2 */ | ||
23 | .cs_on = 0, | ||
24 | - .cs_rd_off = 23 * 10, /* Read deassertion time */ | ||
25 | - .cs_wr_off = 23 * 10, /* Write deassertion time */ | ||
26 | + .cs_rd_off = 8 * 10, /* Read deassertion time */ | ||
27 | + .cs_wr_off = 20 * 10, /* Write deassertion time */ | ||
28 | |||
29 | /* ADV signal timings corresponding to GPMC_CONFIG3 */ | ||
30 | .adv_on = 0, /* Assertion time */ | ||
31 | @@ -1906,17 +1907,17 @@ static struct gpmc_timings cssp_timings = { | ||
32 | |||
33 | /* WE signals timings corresponding to GPMC_CONFIG4 */ | ||
34 | .we_on = 3 * 10, /* WE assertion time */ | ||
35 | - .we_off = 23 * 10, /* WE deassertion time */ | ||
36 | + .we_off = 8 * 10, /* WE deassertion time */ | ||
37 | |||
38 | /* OE signals timings corresponding to GPMC_CONFIG4 */ | ||
39 | .oe_on = 3 * 10, /* OE assertion time */ | ||
40 | - .oe_off = 23 * 10, /* OE deassertion time */ | ||
41 | + .oe_off = 8 * 10, /* OE deassertion time */ | ||
42 | |||
43 | /* Access time and cycle time timings corresponding to GPMC_CONFIG5 */ | ||
44 | .page_burst_access = 1 * 10, /* Multiple access word delay */ | ||
45 | .access = 7 * 10, /* Start-cycle to first data valid delay */ | ||
46 | - .rd_cycle = 23 * 10, /* Total read cycle time */ | ||
47 | - .wr_cycle = 23 * 10, /* Total write cycle time */ | ||
48 | + .rd_cycle = 8 * 10, /* Total read cycle time */ | ||
49 | + .wr_cycle = 20 * 10, /* Total write cycle time */ | ||
50 | |||
51 | /* The following are only on OMAP3430 */ | ||
52 | .wr_access = 7 * 10, /* WRACCESSTIME */ | ||
53 | diff --git a/drivers/media/video/cssp_camera/cssp_camera.c b/drivers/media/video/cssp_camera/cssp_camera.c | ||
54 | index 39aa003..34a36d7 100644 | ||
55 | --- a/drivers/media/video/cssp_camera/cssp_camera.c | ||
56 | +++ b/drivers/media/video/cssp_camera/cssp_camera.c | ||
57 | @@ -147,7 +147,6 @@ static int trigger_dma_transfer_to_buf(struct cssp_cam_dev *dev, struct vb2_buff | ||
58 | // Enable data capture | ||
59 | dev->mode |= ENABLE; | ||
60 | writew(dev->mode, dev->reg_base_virt + REG_MODE); | ||
61 | - readw(dev->reg_base_virt + REG_MODE); | ||
62 | |||
63 | dev->current_vb = vb; | ||
64 | |||
65 | @@ -182,7 +181,6 @@ static void dma_callback(unsigned lch, u16 ch_status, void *data) | ||
66 | // Disable data capture | ||
67 | dev->mode &= ~ENABLE; | ||
68 | writew(dev->mode, dev->reg_base_virt + REG_MODE); | ||
69 | - readw(dev->reg_base_virt + REG_MODE); | ||
70 | |||
71 | if (ch_status == DMA_COMPLETE) { | ||
72 | struct vb2_buffer *vb = dev->current_vb; | ||
73 | @@ -223,7 +221,7 @@ static int configure_edma(struct cssp_cam_dev *cam) | ||
74 | return -1; | ||
75 | } | ||
76 | |||
77 | - cam->dma_ch = edma_alloc_channel(dma_channel, dma_callback, cam, EVENTQ_1); | ||
78 | + cam->dma_ch = edma_alloc_channel(dma_channel, dma_callback, cam, EVENTQ_0); | ||
79 | if (cam->dma_ch < 0) { | ||
80 | printk(KERN_ERR "[%s]: allocating channel for DMA failed\n", pdev->name); | ||
81 | return -EBUSY; | ||
82 | @@ -526,7 +524,6 @@ static int stop_streaming(struct vb2_queue *vq) | ||
83 | // Disable data capture | ||
84 | dev->mode &= ~ENABLE; | ||
85 | writew(dev->mode, dev->reg_base_virt + REG_MODE); | ||
86 | - readw(dev->reg_base_virt + REG_MODE); | ||
87 | |||
88 | stop_camera_sensor(dev); | ||
89 | |||
90 | diff --git a/drivers/media/video/cssp_camera/cssp_camera.h b/drivers/media/video/cssp_camera/cssp_camera.h | ||
91 | index d018ca1..8eb5f83 100644 | ||
92 | --- a/drivers/media/video/cssp_camera/cssp_camera.h | ||
93 | +++ b/drivers/media/video/cssp_camera/cssp_camera.h | ||
94 | @@ -28,7 +28,7 @@ static unsigned debug; | ||
95 | module_param(debug, uint, 0644); | ||
96 | MODULE_PARM_DESC(debug, "activates debug info"); | ||
97 | |||
98 | -static unsigned int vid_limit = 1; | ||
99 | +static unsigned int vid_limit = 6; | ||
100 | module_param(vid_limit, uint, 0644); | ||
101 | MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); | ||
102 | |||
103 | -- | ||
104 | 1.7.10 | ||
105 | |||
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.2/beaglebone/0077-beaglebone-disable-UYVY-VYUY-and-YVYU-modes-in-camer.patch b/recipes-kernel/linux/linux-ti33x-psp-3.2/beaglebone/0077-beaglebone-disable-UYVY-VYUY-and-YVYU-modes-in-camer.patch new file mode 100644 index 00000000..cc824168 --- /dev/null +++ b/recipes-kernel/linux/linux-ti33x-psp-3.2/beaglebone/0077-beaglebone-disable-UYVY-VYUY-and-YVYU-modes-in-camer.patch | |||
@@ -0,0 +1,39 @@ | |||
1 | From 850bc72301ae8eae6e9d11a9ec4d64bc683410fe Mon Sep 17 00:00:00 2001 | ||
2 | From: Dan Aizenstros <daizenstros@quicklogic.com> | ||
3 | Date: Wed, 11 Jul 2012 12:29:29 -0400 | ||
4 | Subject: [PATCH 77/79] beaglebone: disable UYVY, VYUY and YVYU modes in | ||
5 | camera_cssp.c | ||
6 | |||
7 | Signed-off-by: Dan Aizenstros <daizenstros@quicklogic.com> | ||
8 | Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> | ||
9 | --- | ||
10 | drivers/media/video/cssp_camera/cssp_camera.c | 6 ++++++ | ||
11 | 1 file changed, 6 insertions(+) | ||
12 | |||
13 | diff --git a/drivers/media/video/cssp_camera/cssp_camera.c b/drivers/media/video/cssp_camera/cssp_camera.c | ||
14 | index 34a36d7..acd38ee 100644 | ||
15 | --- a/drivers/media/video/cssp_camera/cssp_camera.c | ||
16 | +++ b/drivers/media/video/cssp_camera/cssp_camera.c | ||
17 | @@ -60,6 +60,11 @@ static struct cssp_cam_fmt formats[] = { | ||
18 | .depth = 16, | ||
19 | .code = V4L2_MBUS_FMT_YUYV8_2X8, | ||
20 | }, | ||
21 | +/* | ||
22 | + * UYVY doesn't work properly. VYUY and YVYU are not tested. | ||
23 | + * So disable the UYVY, VYUY and YVYU modes for now | ||
24 | + */ | ||
25 | +#if 0 | ||
26 | { | ||
27 | .name = "4:2:2, packed, UYVY", | ||
28 | .fourcc = V4L2_PIX_FMT_UYVY, | ||
29 | @@ -78,6 +83,7 @@ static struct cssp_cam_fmt formats[] = { | ||
30 | .depth = 16, | ||
31 | .code = V4L2_MBUS_FMT_YVYU8_2X8, | ||
32 | }, | ||
33 | +#endif | ||
34 | { | ||
35 | .name = "RGB565 (LE)", | ||
36 | .fourcc = V4L2_PIX_FMT_RGB565, | ||
37 | -- | ||
38 | 1.7.10 | ||
39 | |||
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.2/beaglebone/0078-beaglebone-error-handling-for-DMA-completion-in-cssp.patch b/recipes-kernel/linux/linux-ti33x-psp-3.2/beaglebone/0078-beaglebone-error-handling-for-DMA-completion-in-cssp.patch new file mode 100644 index 00000000..cc678ba9 --- /dev/null +++ b/recipes-kernel/linux/linux-ti33x-psp-3.2/beaglebone/0078-beaglebone-error-handling-for-DMA-completion-in-cssp.patch | |||
@@ -0,0 +1,49 @@ | |||
1 | From 823d8b7b4a1dcfefc7260110a3acada0d1f45695 Mon Sep 17 00:00:00 2001 | ||
2 | From: Dan Aizenstros <daizenstros@quicklogic.com> | ||
3 | Date: Thu, 12 Jul 2012 16:52:21 -0400 | ||
4 | Subject: [PATCH 78/79] beaglebone: error handling for DMA completion in | ||
5 | cssp_camera.c | ||
6 | |||
7 | Signed-off-by: Dan Aizenstros <daizenstros@quicklogic.com> | ||
8 | Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> | ||
9 | --- | ||
10 | drivers/media/video/cssp_camera/cssp_camera.c | 16 +++++++++++++++- | ||
11 | 1 file changed, 15 insertions(+), 1 deletion(-) | ||
12 | |||
13 | diff --git a/drivers/media/video/cssp_camera/cssp_camera.c b/drivers/media/video/cssp_camera/cssp_camera.c | ||
14 | index acd38ee..fca199b 100644 | ||
15 | --- a/drivers/media/video/cssp_camera/cssp_camera.c | ||
16 | +++ b/drivers/media/video/cssp_camera/cssp_camera.c | ||
17 | @@ -191,6 +191,21 @@ static void dma_callback(unsigned lch, u16 ch_status, void *data) | ||
18 | if (ch_status == DMA_COMPLETE) { | ||
19 | struct vb2_buffer *vb = dev->current_vb; | ||
20 | struct timeval ts; | ||
21 | + struct edmacc_param dma_tr_params; | ||
22 | + | ||
23 | + edma_read_slot(dev->dma_ch, &dma_tr_params); | ||
24 | + if ((dma_tr_params.opt != 0) || | ||
25 | + (dma_tr_params.src != 0) || | ||
26 | + (dma_tr_params.a_b_cnt != 0) || | ||
27 | + (dma_tr_params.dst != 0) || | ||
28 | + (dma_tr_params.src_dst_bidx != 0) || | ||
29 | + (dma_tr_params.link_bcntrld != 0xffff) || | ||
30 | + (dma_tr_params.src_dst_cidx != 0) || | ||
31 | + (dma_tr_params.ccnt != 0)) { | ||
32 | + | ||
33 | + trigger_dma_transfer_to_buf(dev, dev->current_vb); | ||
34 | + return; | ||
35 | + } | ||
36 | |||
37 | vb->v4l2_buf.field = dev->field; | ||
38 | dev->field_count++; | ||
39 | @@ -204,7 +219,6 @@ static void dma_callback(unsigned lch, u16 ch_status, void *data) | ||
40 | /* check if we have new buffer queued */ | ||
41 | dequeue_buffer_for_dma(dev); | ||
42 | } else { | ||
43 | - printk(KERN_ERR "[cssp_camera]: EDMA error (ch_status = %d)\n", ch_status); | ||
44 | /* we got a missed interrupt so just start a new DMA with the existing buffer */ | ||
45 | if (dev->current_vb != NULL) | ||
46 | trigger_dma_transfer_to_buf(dev, dev->current_vb); | ||
47 | -- | ||
48 | 1.7.10 | ||
49 | |||
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.2/beaglebone/0079-AM335X-errata-OPP50-on-MPU-domain-is-not-supported.patch b/recipes-kernel/linux/linux-ti33x-psp-3.2/beaglebone/0079-AM335X-errata-OPP50-on-MPU-domain-is-not-supported.patch new file mode 100644 index 00000000..c50abbf6 --- /dev/null +++ b/recipes-kernel/linux/linux-ti33x-psp-3.2/beaglebone/0079-AM335X-errata-OPP50-on-MPU-domain-is-not-supported.patch | |||
@@ -0,0 +1,52 @@ | |||
1 | From 662134c1007cc275193737dd11ea4b77f47256a7 Mon Sep 17 00:00:00 2001 | ||
2 | From: AnilKumar Ch <anilkumar@ti.com> | ||
3 | Date: Tue, 26 Jun 2012 15:41:51 +0530 | ||
4 | Subject: [PATCH 79/79] AM335X: errata: OPP50 on MPU domain is not supported | ||
5 | |||
6 | This patch implements a workaround for OPP50 erratum, Advisory | ||
7 | 1.0.15 at http://www.ti.com/lit/er/sprz360b/sprz360b.pdf | ||
8 | |||
9 | OPP50 Operation on MPU Domain is Not Supported. This issue seen with | ||
10 | reliability tests running on MPU. To minimize power consumption, the | ||
11 | ARM Cortex-A8 may be operated at the lower frequency defined by OPP50, | ||
12 | but the respective power terminal VDD_MPU must be operated as defined | ||
13 | by OPP100. So MPU OPP50 modified to <275MHz, 1.1V>. | ||
14 | |||
15 | Power consumption as seen on AM335x EVM: | ||
16 | OPP50 <275MHz, 0.95> - 40.5 mW | ||
17 | OPP50 <275MHz, 1.10> - 55.5 mW | ||
18 | OPP100 <500MHz, 1.10> - 98.5 mW | ||
19 | |||
20 | Based on the above data we can see 43mW power savings compared to | ||
21 | OPP100. This is the reason for keeping OPP50 alive instead of | ||
22 | shutting down completely. | ||
23 | |||
24 | Signed-off-by: AnilKumar Ch <anilkumar@ti.com> | ||
25 | --- | ||
26 | arch/arm/mach-omap2/opp3xxx_data.c | 10 +++++++++- | ||
27 | 1 file changed, 9 insertions(+), 1 deletion(-) | ||
28 | |||
29 | diff --git a/arch/arm/mach-omap2/opp3xxx_data.c b/arch/arm/mach-omap2/opp3xxx_data.c | ||
30 | index 0e540c8..9fbcfc3 100644 | ||
31 | --- a/arch/arm/mach-omap2/opp3xxx_data.c | ||
32 | +++ b/arch/arm/mach-omap2/opp3xxx_data.c | ||
33 | @@ -154,7 +154,15 @@ static struct omap_opp_def __initdata omap36xx_opp_def_list[] = { | ||
34 | |||
35 | /* VDD1 */ | ||
36 | |||
37 | -#define AM33XX_VDD_MPU_OPP50_UV 950000 | ||
38 | +/* | ||
39 | + * Errata 1.0.15: OPP50 Operation on MPU Domain is Not Supported. | ||
40 | + * | ||
41 | + * To minimize power consumption, the ARM Cortex-A8 may be operated at | ||
42 | + * the lower frequency defined by OPP50, but the respective voltage | ||
43 | + * domain VDD_MPU must be operated as defined by OPP100. So MPU OPP50 | ||
44 | + * definition is modified to 275MHz, 1.1V. | ||
45 | + */ | ||
46 | +#define AM33XX_VDD_MPU_OPP50_UV 1100000 | ||
47 | #define AM33XX_VDD_MPU_OPP100_UV 1100000 | ||
48 | #define AM33XX_VDD_MPU_OPP120_UV 1200000 | ||
49 | #define AM33XX_VDD_MPU_OPPTURBO_UV 1260000 | ||
50 | -- | ||
51 | 1.7.10 | ||
52 | |||
diff --git a/recipes-kernel/linux/linux-ti33x-psp_3.2.bb b/recipes-kernel/linux/linux-ti33x-psp_3.2.bb index 01bfc233..083f36a3 100644 --- a/recipes-kernel/linux/linux-ti33x-psp_3.2.bb +++ b/recipes-kernel/linux/linux-ti33x-psp_3.2.bb | |||
@@ -15,7 +15,7 @@ PV = "${@base_contains('DISTRO_FEATURES', 'tipspkernel', "3.2", "3.2.21", d)}" | |||
15 | 15 | ||
16 | BRANCH = "v3.2-staging" | 16 | BRANCH = "v3.2-staging" |
17 | SRCREV = "720e07b4c1f687b61b147b31c698cb6816d72f01" | 17 | SRCREV = "720e07b4c1f687b61b147b31c698cb6816d72f01" |
18 | MACHINE_KERNEL_PR_append = "f+gitr${SRCREV}" | 18 | MACHINE_KERNEL_PR_append = "g+gitr${SRCREV}" |
19 | 19 | ||
20 | COMPATIBLE_MACHINE = "(ti33x)" | 20 | COMPATIBLE_MACHINE = "(ti33x)" |
21 | 21 | ||
@@ -1530,7 +1530,6 @@ PATCHES_OVER_PSP = " \ | |||
1530 | file://beaglebone/0063-beaglebone-dvi-cape-audio-hacks.patch \ | 1530 | file://beaglebone/0063-beaglebone-dvi-cape-audio-hacks.patch \ |
1531 | file://beaglebone/0064-beaglebone-always-execute-the-pin-free-checks.patch \ | 1531 | file://beaglebone/0064-beaglebone-always-execute-the-pin-free-checks.patch \ |
1532 | file://beaglebone/0065-ti_tscadc-switch-to-16x-averaging.patch \ | 1532 | file://beaglebone/0065-ti_tscadc-switch-to-16x-averaging.patch \ |
1533 | file://beaglebone/0066-beaglebone-disable-OPP-for-275MHz-due-to-silicon-err.patch \ | ||
1534 | file://beaglebone/0067-video-da8xx-fb-Add-Newhaven-LCD-Panel-details.patch \ | 1533 | file://beaglebone/0067-video-da8xx-fb-Add-Newhaven-LCD-Panel-details.patch \ |
1535 | file://beaglebone/0068-beaglebone-add-support-for-the-4.3-lcd-cape-with-res.patch \ | 1534 | file://beaglebone/0068-beaglebone-add-support-for-the-4.3-lcd-cape-with-res.patch \ |
1536 | file://beaglebone/0069-beaglebone-add-support-for-LCD3-rev-A1.patch \ | 1535 | file://beaglebone/0069-beaglebone-add-support-for-LCD3-rev-A1.patch \ |
@@ -1540,4 +1539,9 @@ PATCHES_OVER_PSP = " \ | |||
1540 | file://beaglebone/0073-beaglebone-add-support-for-QuickLogic-Camera-interfa.patch \ | 1539 | file://beaglebone/0073-beaglebone-add-support-for-QuickLogic-Camera-interfa.patch \ |
1541 | file://beaglebone/0074-beaglebone-add-support-for-DVI-audio-and-audio-only-.patch \ | 1540 | file://beaglebone/0074-beaglebone-add-support-for-DVI-audio-and-audio-only-.patch \ |
1542 | file://beaglebone/0075-beaglebone-disable-LBO-GPIO-for-battery-cape.patch \ | 1541 | file://beaglebone/0075-beaglebone-disable-LBO-GPIO-for-battery-cape.patch \ |
1542 | file://beaglebone/0075-video-da8xx-fb-calculate-pixel-clock-period-for-the-.patch \ | ||
1543 | file://beaglebone/0076-beaglebone-improve-GPMC-bus-timings-for-camera-cape.patch \ | ||
1544 | file://beaglebone/0077-beaglebone-disable-UYVY-VYUY-and-YVYU-modes-in-camer.patch \ | ||
1545 | file://beaglebone/0078-beaglebone-error-handling-for-DMA-completion-in-cssp.patch \ | ||
1546 | file://beaglebone/0079-AM335X-errata-OPP50-on-MPU-domain-is-not-supported.patch \ | ||
1543 | " | 1547 | " |