diff options
-rw-r--r-- | arch/arm/mach-omap2/gpmc-nand.c | 18 | ||||
-rw-r--r-- | arch/arm/mach-omap2/gpmc-onenand.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-omap2/usb-tusb6010.c | 4 | ||||
-rw-r--r-- | drivers/memory/omap-gpmc.c | 358 | ||||
-rw-r--r-- | include/linux/omap-gpmc.h | 3 |
5 files changed, 305 insertions, 82 deletions
diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c index d5951b17b736..72918c4973ea 100644 --- a/arch/arm/mach-omap2/gpmc-nand.c +++ b/arch/arm/mach-omap2/gpmc-nand.c | |||
@@ -96,14 +96,6 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data, | |||
96 | gpmc_nand_res[1].start = gpmc_get_client_irq(GPMC_IRQ_FIFOEVENTENABLE); | 96 | gpmc_nand_res[1].start = gpmc_get_client_irq(GPMC_IRQ_FIFOEVENTENABLE); |
97 | gpmc_nand_res[2].start = gpmc_get_client_irq(GPMC_IRQ_COUNT_EVENT); | 97 | gpmc_nand_res[2].start = gpmc_get_client_irq(GPMC_IRQ_COUNT_EVENT); |
98 | 98 | ||
99 | if (gpmc_t) { | ||
100 | err = gpmc_cs_set_timings(gpmc_nand_data->cs, gpmc_t); | ||
101 | if (err < 0) { | ||
102 | pr_err("omap2-gpmc: Unable to set gpmc timings: %d\n", err); | ||
103 | return err; | ||
104 | } | ||
105 | } | ||
106 | |||
107 | memset(&s, 0, sizeof(struct gpmc_settings)); | 99 | memset(&s, 0, sizeof(struct gpmc_settings)); |
108 | if (gpmc_nand_data->of_node) | 100 | if (gpmc_nand_data->of_node) |
109 | gpmc_read_settings_dt(gpmc_nand_data->of_node, &s); | 101 | gpmc_read_settings_dt(gpmc_nand_data->of_node, &s); |
@@ -111,6 +103,16 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data, | |||
111 | gpmc_set_legacy(gpmc_nand_data, &s); | 103 | gpmc_set_legacy(gpmc_nand_data, &s); |
112 | 104 | ||
113 | s.device_nand = true; | 105 | s.device_nand = true; |
106 | |||
107 | if (gpmc_t) { | ||
108 | err = gpmc_cs_set_timings(gpmc_nand_data->cs, gpmc_t, &s); | ||
109 | if (err < 0) { | ||
110 | pr_err("omap2-gpmc: Unable to set gpmc timings: %d\n", | ||
111 | err); | ||
112 | return err; | ||
113 | } | ||
114 | } | ||
115 | |||
114 | err = gpmc_cs_program_settings(gpmc_nand_data->cs, &s); | 116 | err = gpmc_cs_program_settings(gpmc_nand_data->cs, &s); |
115 | if (err < 0) | 117 | if (err < 0) |
116 | goto out_free_cs; | 118 | goto out_free_cs; |
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c index 53d197e0c1f3..f899e77ff5e6 100644 --- a/arch/arm/mach-omap2/gpmc-onenand.c +++ b/arch/arm/mach-omap2/gpmc-onenand.c | |||
@@ -293,7 +293,7 @@ static int omap2_onenand_setup_async(void __iomem *onenand_base) | |||
293 | if (ret < 0) | 293 | if (ret < 0) |
294 | return ret; | 294 | return ret; |
295 | 295 | ||
296 | ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t); | 296 | ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t, &onenand_async); |
297 | if (ret < 0) | 297 | if (ret < 0) |
298 | return ret; | 298 | return ret; |
299 | 299 | ||
@@ -331,7 +331,7 @@ static int omap2_onenand_setup_sync(void __iomem *onenand_base, int *freq_ptr) | |||
331 | if (ret < 0) | 331 | if (ret < 0) |
332 | return ret; | 332 | return ret; |
333 | 333 | ||
334 | ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t); | 334 | ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, &t, &onenand_sync); |
335 | if (ret < 0) | 335 | if (ret < 0) |
336 | return ret; | 336 | return ret; |
337 | 337 | ||
diff --git a/arch/arm/mach-omap2/usb-tusb6010.c b/arch/arm/mach-omap2/usb-tusb6010.c index 8333400898fb..e554d9e66a1c 100644 --- a/arch/arm/mach-omap2/usb-tusb6010.c +++ b/arch/arm/mach-omap2/usb-tusb6010.c | |||
@@ -71,7 +71,7 @@ static int tusb_set_async_mode(unsigned sysclk_ps) | |||
71 | 71 | ||
72 | gpmc_calc_timings(&t, &tusb_async, &dev_t); | 72 | gpmc_calc_timings(&t, &tusb_async, &dev_t); |
73 | 73 | ||
74 | return gpmc_cs_set_timings(async_cs, &t); | 74 | return gpmc_cs_set_timings(async_cs, &t, &tusb_async); |
75 | } | 75 | } |
76 | 76 | ||
77 | static int tusb_set_sync_mode(unsigned sysclk_ps) | 77 | static int tusb_set_sync_mode(unsigned sysclk_ps) |
@@ -98,7 +98,7 @@ static int tusb_set_sync_mode(unsigned sysclk_ps) | |||
98 | 98 | ||
99 | gpmc_calc_timings(&t, &tusb_sync, &dev_t); | 99 | gpmc_calc_timings(&t, &tusb_sync, &dev_t); |
100 | 100 | ||
101 | return gpmc_cs_set_timings(sync_cs, &t); | 101 | return gpmc_cs_set_timings(sync_cs, &t, &tusb_sync); |
102 | } | 102 | } |
103 | 103 | ||
104 | /* tusb driver calls this when it changes the chip's clocking */ | 104 | /* tusb driver calls this when it changes the chip's clocking */ |
diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c index 24696f59215b..c94ea0d68746 100644 --- a/drivers/memory/omap-gpmc.c +++ b/drivers/memory/omap-gpmc.c | |||
@@ -12,8 +12,6 @@ | |||
12 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
13 | * published by the Free Software Foundation. | 13 | * published by the Free Software Foundation. |
14 | */ | 14 | */ |
15 | #undef DEBUG | ||
16 | |||
17 | #include <linux/irq.h> | 15 | #include <linux/irq.h> |
18 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
19 | #include <linux/init.h> | 17 | #include <linux/init.h> |
@@ -29,6 +27,7 @@ | |||
29 | #include <linux/of_address.h> | 27 | #include <linux/of_address.h> |
30 | #include <linux/of_mtd.h> | 28 | #include <linux/of_mtd.h> |
31 | #include <linux/of_device.h> | 29 | #include <linux/of_device.h> |
30 | #include <linux/of_platform.h> | ||
32 | #include <linux/omap-gpmc.h> | 31 | #include <linux/omap-gpmc.h> |
33 | #include <linux/mtd/nand.h> | 32 | #include <linux/mtd/nand.h> |
34 | #include <linux/pm_runtime.h> | 33 | #include <linux/pm_runtime.h> |
@@ -136,13 +135,21 @@ | |||
136 | #define GPMC_CONFIG1_WRITETYPE_ASYNC (0 << 27) | 135 | #define GPMC_CONFIG1_WRITETYPE_ASYNC (0 << 27) |
137 | #define GPMC_CONFIG1_WRITETYPE_SYNC (1 << 27) | 136 | #define GPMC_CONFIG1_WRITETYPE_SYNC (1 << 27) |
138 | #define GPMC_CONFIG1_CLKACTIVATIONTIME(val) ((val & 3) << 25) | 137 | #define GPMC_CONFIG1_CLKACTIVATIONTIME(val) ((val & 3) << 25) |
138 | /** CLKACTIVATIONTIME Max Ticks */ | ||
139 | #define GPMC_CONFIG1_CLKACTIVATIONTIME_MAX 2 | ||
139 | #define GPMC_CONFIG1_PAGE_LEN(val) ((val & 3) << 23) | 140 | #define GPMC_CONFIG1_PAGE_LEN(val) ((val & 3) << 23) |
141 | /** ATTACHEDDEVICEPAGELENGTH Max Value */ | ||
142 | #define GPMC_CONFIG1_ATTACHEDDEVICEPAGELENGTH_MAX 2 | ||
140 | #define GPMC_CONFIG1_WAIT_READ_MON (1 << 22) | 143 | #define GPMC_CONFIG1_WAIT_READ_MON (1 << 22) |
141 | #define GPMC_CONFIG1_WAIT_WRITE_MON (1 << 21) | 144 | #define GPMC_CONFIG1_WAIT_WRITE_MON (1 << 21) |
142 | #define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18) | 145 | #define GPMC_CONFIG1_WAIT_MON_TIME(val) ((val & 3) << 18) |
146 | /** WAITMONITORINGTIME Max Ticks */ | ||
147 | #define GPMC_CONFIG1_WAITMONITORINGTIME_MAX 2 | ||
143 | #define GPMC_CONFIG1_WAIT_PIN_SEL(val) ((val & 3) << 16) | 148 | #define GPMC_CONFIG1_WAIT_PIN_SEL(val) ((val & 3) << 16) |
144 | #define GPMC_CONFIG1_DEVICESIZE(val) ((val & 3) << 12) | 149 | #define GPMC_CONFIG1_DEVICESIZE(val) ((val & 3) << 12) |
145 | #define GPMC_CONFIG1_DEVICESIZE_16 GPMC_CONFIG1_DEVICESIZE(1) | 150 | #define GPMC_CONFIG1_DEVICESIZE_16 GPMC_CONFIG1_DEVICESIZE(1) |
151 | /** DEVICESIZE Max Value */ | ||
152 | #define GPMC_CONFIG1_DEVICESIZE_MAX 1 | ||
146 | #define GPMC_CONFIG1_DEVICETYPE(val) ((val & 3) << 10) | 153 | #define GPMC_CONFIG1_DEVICETYPE(val) ((val & 3) << 10) |
147 | #define GPMC_CONFIG1_DEVICETYPE_NOR GPMC_CONFIG1_DEVICETYPE(0) | 154 | #define GPMC_CONFIG1_DEVICETYPE_NOR GPMC_CONFIG1_DEVICETYPE(0) |
148 | #define GPMC_CONFIG1_MUXTYPE(val) ((val & 3) << 8) | 155 | #define GPMC_CONFIG1_MUXTYPE(val) ((val & 3) << 8) |
@@ -153,6 +160,15 @@ | |||
153 | #define GPMC_CONFIG1_FCLK_DIV4 (GPMC_CONFIG1_FCLK_DIV(3)) | 160 | #define GPMC_CONFIG1_FCLK_DIV4 (GPMC_CONFIG1_FCLK_DIV(3)) |
154 | #define GPMC_CONFIG7_CSVALID (1 << 6) | 161 | #define GPMC_CONFIG7_CSVALID (1 << 6) |
155 | 162 | ||
163 | #define GPMC_CONFIG7_BASEADDRESS_MASK 0x3f | ||
164 | #define GPMC_CONFIG7_CSVALID_MASK BIT(6) | ||
165 | #define GPMC_CONFIG7_MASKADDRESS_OFFSET 8 | ||
166 | #define GPMC_CONFIG7_MASKADDRESS_MASK (0xf << GPMC_CONFIG7_MASKADDRESS_OFFSET) | ||
167 | /* All CONFIG7 bits except reserved bits */ | ||
168 | #define GPMC_CONFIG7_MASK (GPMC_CONFIG7_BASEADDRESS_MASK | \ | ||
169 | GPMC_CONFIG7_CSVALID_MASK | \ | ||
170 | GPMC_CONFIG7_MASKADDRESS_MASK) | ||
171 | |||
156 | #define GPMC_DEVICETYPE_NOR 0 | 172 | #define GPMC_DEVICETYPE_NOR 0 |
157 | #define GPMC_DEVICETYPE_NAND 2 | 173 | #define GPMC_DEVICETYPE_NAND 2 |
158 | #define GPMC_CONFIG_WRITEPROTECT 0x00000010 | 174 | #define GPMC_CONFIG_WRITEPROTECT 0x00000010 |
@@ -169,6 +185,11 @@ | |||
169 | */ | 185 | */ |
170 | #define GPMC_NR_IRQ 2 | 186 | #define GPMC_NR_IRQ 2 |
171 | 187 | ||
188 | enum gpmc_clk_domain { | ||
189 | GPMC_CD_FCLK, | ||
190 | GPMC_CD_CLK | ||
191 | }; | ||
192 | |||
172 | struct gpmc_cs_data { | 193 | struct gpmc_cs_data { |
173 | const char *name; | 194 | const char *name; |
174 | 195 | ||
@@ -267,16 +288,55 @@ static unsigned long gpmc_get_fclk_period(void) | |||
267 | return rate; | 288 | return rate; |
268 | } | 289 | } |
269 | 290 | ||
270 | static unsigned int gpmc_ns_to_ticks(unsigned int time_ns) | 291 | /** |
292 | * gpmc_get_clk_period - get period of selected clock domain in ps | ||
293 | * @cs Chip Select Region. | ||
294 | * @cd Clock Domain. | ||
295 | * | ||
296 | * GPMC_CS_CONFIG1 GPMCFCLKDIVIDER for cs has to be setup | ||
297 | * prior to calling this function with GPMC_CD_CLK. | ||
298 | */ | ||
299 | static unsigned long gpmc_get_clk_period(int cs, enum gpmc_clk_domain cd) | ||
300 | { | ||
301 | |||
302 | unsigned long tick_ps = gpmc_get_fclk_period(); | ||
303 | u32 l; | ||
304 | int div; | ||
305 | |||
306 | switch (cd) { | ||
307 | case GPMC_CD_CLK: | ||
308 | /* get current clk divider */ | ||
309 | l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1); | ||
310 | div = (l & 0x03) + 1; | ||
311 | /* get GPMC_CLK period */ | ||
312 | tick_ps *= div; | ||
313 | break; | ||
314 | case GPMC_CD_FCLK: | ||
315 | /* FALL-THROUGH */ | ||
316 | default: | ||
317 | break; | ||
318 | } | ||
319 | |||
320 | return tick_ps; | ||
321 | |||
322 | } | ||
323 | |||
324 | static unsigned int gpmc_ns_to_clk_ticks(unsigned int time_ns, int cs, | ||
325 | enum gpmc_clk_domain cd) | ||
271 | { | 326 | { |
272 | unsigned long tick_ps; | 327 | unsigned long tick_ps; |
273 | 328 | ||
274 | /* Calculate in picosecs to yield more exact results */ | 329 | /* Calculate in picosecs to yield more exact results */ |
275 | tick_ps = gpmc_get_fclk_period(); | 330 | tick_ps = gpmc_get_clk_period(cs, cd); |
276 | 331 | ||
277 | return (time_ns * 1000 + tick_ps - 1) / tick_ps; | 332 | return (time_ns * 1000 + tick_ps - 1) / tick_ps; |
278 | } | 333 | } |
279 | 334 | ||
335 | static unsigned int gpmc_ns_to_ticks(unsigned int time_ns) | ||
336 | { | ||
337 | return gpmc_ns_to_clk_ticks(time_ns, /* any CS */ 0, GPMC_CD_FCLK); | ||
338 | } | ||
339 | |||
280 | static unsigned int gpmc_ps_to_ticks(unsigned int time_ps) | 340 | static unsigned int gpmc_ps_to_ticks(unsigned int time_ps) |
281 | { | 341 | { |
282 | unsigned long tick_ps; | 342 | unsigned long tick_ps; |
@@ -287,9 +347,15 @@ static unsigned int gpmc_ps_to_ticks(unsigned int time_ps) | |||
287 | return (time_ps + tick_ps - 1) / tick_ps; | 347 | return (time_ps + tick_ps - 1) / tick_ps; |
288 | } | 348 | } |
289 | 349 | ||
350 | unsigned int gpmc_clk_ticks_to_ns(unsigned ticks, int cs, | ||
351 | enum gpmc_clk_domain cd) | ||
352 | { | ||
353 | return ticks * gpmc_get_clk_period(cs, cd) / 1000; | ||
354 | } | ||
355 | |||
290 | unsigned int gpmc_ticks_to_ns(unsigned int ticks) | 356 | unsigned int gpmc_ticks_to_ns(unsigned int ticks) |
291 | { | 357 | { |
292 | return ticks * gpmc_get_fclk_period() / 1000; | 358 | return gpmc_clk_ticks_to_ns(ticks, /* any CS */ 0, GPMC_CD_FCLK); |
293 | } | 359 | } |
294 | 360 | ||
295 | static unsigned int gpmc_ticks_to_ps(unsigned int ticks) | 361 | static unsigned int gpmc_ticks_to_ps(unsigned int ticks) |
@@ -338,33 +404,66 @@ static void gpmc_cs_bool_timings(int cs, const struct gpmc_bool_timings *p) | |||
338 | } | 404 | } |
339 | 405 | ||
340 | #ifdef DEBUG | 406 | #ifdef DEBUG |
341 | static int get_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit, | 407 | /** |
342 | bool raw, bool noval, int shift, | 408 | * get_gpmc_timing_reg - read a timing parameter and print DTS settings for it. |
343 | const char *name) | 409 | * @cs: Chip Select Region |
410 | * @reg: GPMC_CS_CONFIGn register offset. | ||
411 | * @st_bit: Start Bit | ||
412 | * @end_bit: End Bit. Must be >= @st_bit. | ||
413 | * @ma:x Maximum parameter value (before optional @shift). | ||
414 | * If 0, maximum is as high as @st_bit and @end_bit allow. | ||
415 | * @name: DTS node name, w/o "gpmc," | ||
416 | * @cd: Clock Domain of timing parameter. | ||
417 | * @shift: Parameter value left shifts @shift, which is then printed instead of value. | ||
418 | * @raw: Raw Format Option. | ||
419 | * raw format: gpmc,name = <value> | ||
420 | * tick format: gpmc,name = <value> /‍* x ns -- y ns; x ticks *‍/ | ||
421 | * Where x ns -- y ns result in the same tick value. | ||
422 | * When @max is exceeded, "invalid" is printed inside comment. | ||
423 | * @noval: Parameter values equal to 0 are not printed. | ||
424 | * @return: Specified timing parameter (after optional @shift). | ||
425 | * | ||
426 | */ | ||
427 | static int get_gpmc_timing_reg( | ||
428 | /* timing specifiers */ | ||
429 | int cs, int reg, int st_bit, int end_bit, int max, | ||
430 | const char *name, const enum gpmc_clk_domain cd, | ||
431 | /* value transform */ | ||
432 | int shift, | ||
433 | /* format specifiers */ | ||
434 | bool raw, bool noval) | ||
344 | { | 435 | { |
345 | u32 l; | 436 | u32 l; |
346 | int nr_bits, max_value, mask; | 437 | int nr_bits; |
438 | int mask; | ||
439 | bool invalid; | ||
347 | 440 | ||
348 | l = gpmc_cs_read_reg(cs, reg); | 441 | l = gpmc_cs_read_reg(cs, reg); |
349 | nr_bits = end_bit - st_bit + 1; | 442 | nr_bits = end_bit - st_bit + 1; |
350 | max_value = (1 << nr_bits) - 1; | 443 | mask = (1 << nr_bits) - 1; |
351 | mask = max_value << st_bit; | 444 | l = (l >> st_bit) & mask; |
352 | l = (l & mask) >> st_bit; | 445 | if (!max) |
446 | max = mask; | ||
447 | invalid = l > max; | ||
353 | if (shift) | 448 | if (shift) |
354 | l = (shift << l); | 449 | l = (shift << l); |
355 | if (noval && (l == 0)) | 450 | if (noval && (l == 0)) |
356 | return 0; | 451 | return 0; |
357 | if (!raw) { | 452 | if (!raw) { |
358 | unsigned int time_ns_min, time_ns, time_ns_max; | 453 | /* DTS tick format for timings in ns */ |
359 | 454 | unsigned int time_ns; | |
360 | time_ns_min = gpmc_ticks_to_ns(l ? l - 1 : 0); | 455 | unsigned int time_ns_min = 0; |
361 | time_ns = gpmc_ticks_to_ns(l); | 456 | |
362 | time_ns_max = gpmc_ticks_to_ns(l + 1 > max_value ? | 457 | if (l) |
363 | max_value : l + 1); | 458 | time_ns_min = gpmc_clk_ticks_to_ns(l - 1, cs, cd) + 1; |
364 | pr_info("gpmc,%s = <%u> (%u - %u ns, %i ticks)\n", | 459 | time_ns = gpmc_clk_ticks_to_ns(l, cs, cd); |
365 | name, time_ns, time_ns_min, time_ns_max, l); | 460 | pr_info("gpmc,%s = <%u> /* %u ns - %u ns; %i ticks%s*/\n", |
461 | name, time_ns, time_ns_min, time_ns, l, | ||
462 | invalid ? "; invalid " : " "); | ||
366 | } else { | 463 | } else { |
367 | pr_info("gpmc,%s = <%u>\n", name, l); | 464 | /* raw format */ |
465 | pr_info("gpmc,%s = <%u>%s\n", name, l, | ||
466 | invalid ? " /* invalid */" : ""); | ||
368 | } | 467 | } |
369 | 468 | ||
370 | return l; | 469 | return l; |
@@ -374,13 +473,19 @@ static int get_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit, | |||
374 | pr_info("cs%i %s: 0x%08x\n", cs, #config, \ | 473 | pr_info("cs%i %s: 0x%08x\n", cs, #config, \ |
375 | gpmc_cs_read_reg(cs, config)) | 474 | gpmc_cs_read_reg(cs, config)) |
376 | #define GPMC_GET_RAW(reg, st, end, field) \ | 475 | #define GPMC_GET_RAW(reg, st, end, field) \ |
377 | get_gpmc_timing_reg(cs, (reg), (st), (end), 1, 0, 0, field) | 476 | get_gpmc_timing_reg(cs, (reg), (st), (end), 0, field, GPMC_CD_FCLK, 0, 1, 0) |
477 | #define GPMC_GET_RAW_MAX(reg, st, end, max, field) \ | ||
478 | get_gpmc_timing_reg(cs, (reg), (st), (end), (max), field, GPMC_CD_FCLK, 0, 1, 0) | ||
378 | #define GPMC_GET_RAW_BOOL(reg, st, end, field) \ | 479 | #define GPMC_GET_RAW_BOOL(reg, st, end, field) \ |
379 | get_gpmc_timing_reg(cs, (reg), (st), (end), 1, 1, 0, field) | 480 | get_gpmc_timing_reg(cs, (reg), (st), (end), 0, field, GPMC_CD_FCLK, 0, 1, 1) |
380 | #define GPMC_GET_RAW_SHIFT(reg, st, end, shift, field) \ | 481 | #define GPMC_GET_RAW_SHIFT_MAX(reg, st, end, shift, max, field) \ |
381 | get_gpmc_timing_reg(cs, (reg), (st), (end), 1, 1, (shift), field) | 482 | get_gpmc_timing_reg(cs, (reg), (st), (end), (max), field, GPMC_CD_FCLK, (shift), 1, 1) |
382 | #define GPMC_GET_TICKS(reg, st, end, field) \ | 483 | #define GPMC_GET_TICKS(reg, st, end, field) \ |
383 | get_gpmc_timing_reg(cs, (reg), (st), (end), 0, 0, 0, field) | 484 | get_gpmc_timing_reg(cs, (reg), (st), (end), 0, field, GPMC_CD_FCLK, 0, 0, 0) |
485 | #define GPMC_GET_TICKS_CD(reg, st, end, field, cd) \ | ||
486 | get_gpmc_timing_reg(cs, (reg), (st), (end), 0, field, (cd), 0, 0, 0) | ||
487 | #define GPMC_GET_TICKS_CD_MAX(reg, st, end, max, field, cd) \ | ||
488 | get_gpmc_timing_reg(cs, (reg), (st), (end), (max), field, (cd), 0, 0, 0) | ||
384 | 489 | ||
385 | static void gpmc_show_regs(int cs, const char *desc) | 490 | static void gpmc_show_regs(int cs, const char *desc) |
386 | { | 491 | { |
@@ -404,11 +509,14 @@ static void gpmc_cs_show_timings(int cs, const char *desc) | |||
404 | pr_info("gpmc cs%i access configuration:\n", cs); | 509 | pr_info("gpmc cs%i access configuration:\n", cs); |
405 | GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 4, 4, "time-para-granularity"); | 510 | GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 4, 4, "time-para-granularity"); |
406 | GPMC_GET_RAW(GPMC_CS_CONFIG1, 8, 9, "mux-add-data"); | 511 | GPMC_GET_RAW(GPMC_CS_CONFIG1, 8, 9, "mux-add-data"); |
407 | GPMC_GET_RAW(GPMC_CS_CONFIG1, 12, 13, "device-width"); | 512 | GPMC_GET_RAW_MAX(GPMC_CS_CONFIG1, 12, 13, |
513 | GPMC_CONFIG1_DEVICESIZE_MAX, "device-width"); | ||
408 | GPMC_GET_RAW(GPMC_CS_CONFIG1, 16, 17, "wait-pin"); | 514 | GPMC_GET_RAW(GPMC_CS_CONFIG1, 16, 17, "wait-pin"); |
409 | GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 21, 21, "wait-on-write"); | 515 | GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 21, 21, "wait-on-write"); |
410 | GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 22, 22, "wait-on-read"); | 516 | GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 22, 22, "wait-on-read"); |
411 | GPMC_GET_RAW_SHIFT(GPMC_CS_CONFIG1, 23, 24, 4, "burst-length"); | 517 | GPMC_GET_RAW_SHIFT_MAX(GPMC_CS_CONFIG1, 23, 24, 4, |
518 | GPMC_CONFIG1_ATTACHEDDEVICEPAGELENGTH_MAX, | ||
519 | "burst-length"); | ||
412 | GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 27, 27, "sync-write"); | 520 | GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 27, 27, "sync-write"); |
413 | GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 28, 28, "burst-write"); | 521 | GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 28, 28, "burst-write"); |
414 | GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 29, 29, "gpmc,sync-read"); | 522 | GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 29, 29, "gpmc,sync-read"); |
@@ -448,8 +556,12 @@ static void gpmc_cs_show_timings(int cs, const char *desc) | |||
448 | GPMC_GET_TICKS(GPMC_CS_CONFIG6, 0, 3, "bus-turnaround-ns"); | 556 | GPMC_GET_TICKS(GPMC_CS_CONFIG6, 0, 3, "bus-turnaround-ns"); |
449 | GPMC_GET_TICKS(GPMC_CS_CONFIG6, 8, 11, "cycle2cycle-delay-ns"); | 557 | GPMC_GET_TICKS(GPMC_CS_CONFIG6, 8, 11, "cycle2cycle-delay-ns"); |
450 | 558 | ||
451 | GPMC_GET_TICKS(GPMC_CS_CONFIG1, 18, 19, "wait-monitoring-ns"); | 559 | GPMC_GET_TICKS_CD_MAX(GPMC_CS_CONFIG1, 18, 19, |
452 | GPMC_GET_TICKS(GPMC_CS_CONFIG1, 25, 26, "clk-activation-ns"); | 560 | GPMC_CONFIG1_WAITMONITORINGTIME_MAX, |
561 | "wait-monitoring-ns", GPMC_CD_CLK); | ||
562 | GPMC_GET_TICKS_CD_MAX(GPMC_CS_CONFIG1, 25, 26, | ||
563 | GPMC_CONFIG1_CLKACTIVATIONTIME_MAX, | ||
564 | "clk-activation-ns", GPMC_CD_FCLK); | ||
453 | 565 | ||
454 | GPMC_GET_TICKS(GPMC_CS_CONFIG6, 16, 19, "wr-data-mux-bus-ns"); | 566 | GPMC_GET_TICKS(GPMC_CS_CONFIG6, 16, 19, "wr-data-mux-bus-ns"); |
455 | GPMC_GET_TICKS(GPMC_CS_CONFIG6, 24, 28, "wr-access-ns"); | 567 | GPMC_GET_TICKS(GPMC_CS_CONFIG6, 24, 28, "wr-access-ns"); |
@@ -460,8 +572,24 @@ static inline void gpmc_cs_show_timings(int cs, const char *desc) | |||
460 | } | 572 | } |
461 | #endif | 573 | #endif |
462 | 574 | ||
463 | static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit, | 575 | /** |
464 | int time, const char *name) | 576 | * set_gpmc_timing_reg - set a single timing parameter for Chip Select Region. |
577 | * Caller is expected to have initialized CONFIG1 GPMCFCLKDIVIDER | ||
578 | * prior to calling this function with @cd equal to GPMC_CD_CLK. | ||
579 | * | ||
580 | * @cs: Chip Select Region. | ||
581 | * @reg: GPMC_CS_CONFIGn register offset. | ||
582 | * @st_bit: Start Bit | ||
583 | * @end_bit: End Bit. Must be >= @st_bit. | ||
584 | * @max: Maximum parameter value. | ||
585 | * If 0, maximum is as high as @st_bit and @end_bit allow. | ||
586 | * @time: Timing parameter in ns. | ||
587 | * @cd: Timing parameter clock domain. | ||
588 | * @name: Timing parameter name. | ||
589 | * @return: 0 on success, -1 on error. | ||
590 | */ | ||
591 | static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit, int max, | ||
592 | int time, enum gpmc_clk_domain cd, const char *name) | ||
465 | { | 593 | { |
466 | u32 l; | 594 | u32 l; |
467 | int ticks, mask, nr_bits; | 595 | int ticks, mask, nr_bits; |
@@ -469,22 +597,25 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit, | |||
469 | if (time == 0) | 597 | if (time == 0) |
470 | ticks = 0; | 598 | ticks = 0; |
471 | else | 599 | else |
472 | ticks = gpmc_ns_to_ticks(time); | 600 | ticks = gpmc_ns_to_clk_ticks(time, cs, cd); |
473 | nr_bits = end_bit - st_bit + 1; | 601 | nr_bits = end_bit - st_bit + 1; |
474 | mask = (1 << nr_bits) - 1; | 602 | mask = (1 << nr_bits) - 1; |
475 | 603 | ||
476 | if (ticks > mask) { | 604 | if (!max) |
477 | pr_err("%s: GPMC error! CS%d: %s: %d ns, %d ticks > %d\n", | 605 | max = mask; |
478 | __func__, cs, name, time, ticks, mask); | 606 | |
607 | if (ticks > max) { | ||
608 | pr_err("%s: GPMC CS%d: %s %d ns, %d ticks > %d ticks\n", | ||
609 | __func__, cs, name, time, ticks, max); | ||
479 | 610 | ||
480 | return -1; | 611 | return -1; |
481 | } | 612 | } |
482 | 613 | ||
483 | l = gpmc_cs_read_reg(cs, reg); | 614 | l = gpmc_cs_read_reg(cs, reg); |
484 | #ifdef DEBUG | 615 | #ifdef DEBUG |
485 | printk(KERN_INFO | 616 | pr_info( |
486 | "GPMC CS%d: %-10s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n", | 617 | "GPMC CS%d: %-17s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n", |
487 | cs, name, ticks, gpmc_get_fclk_period() * ticks / 1000, | 618 | cs, name, ticks, gpmc_get_clk_period(cs, cd) * ticks / 1000, |
488 | (l >> st_bit) & mask, time); | 619 | (l >> st_bit) & mask, time); |
489 | #endif | 620 | #endif |
490 | l &= ~(mask << st_bit); | 621 | l &= ~(mask << st_bit); |
@@ -494,18 +625,56 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit, | |||
494 | return 0; | 625 | return 0; |
495 | } | 626 | } |
496 | 627 | ||
497 | #define GPMC_SET_ONE(reg, st, end, field) \ | 628 | #define GPMC_SET_ONE_CD_MAX(reg, st, end, max, field, cd) \ |
498 | if (set_gpmc_timing_reg(cs, (reg), (st), (end), \ | 629 | if (set_gpmc_timing_reg(cs, (reg), (st), (end), (max), \ |
499 | t->field, #field) < 0) \ | 630 | t->field, (cd), #field) < 0) \ |
500 | return -1 | 631 | return -1 |
501 | 632 | ||
633 | #define GPMC_SET_ONE(reg, st, end, field) \ | ||
634 | GPMC_SET_ONE_CD_MAX(reg, st, end, 0, field, GPMC_CD_FCLK) | ||
635 | |||
636 | /** | ||
637 | * gpmc_calc_waitmonitoring_divider - calculate proper GPMCFCLKDIVIDER based on WAITMONITORINGTIME | ||
638 | * WAITMONITORINGTIME will be _at least_ as long as desired, i.e. | ||
639 | * read --> don't sample bus too early | ||
640 | * write --> data is longer on bus | ||
641 | * | ||
642 | * Formula: | ||
643 | * gpmc_clk_div + 1 = ceil(ceil(waitmonitoringtime_ns / gpmc_fclk_ns) | ||
644 | * / waitmonitoring_ticks) | ||
645 | * WAITMONITORINGTIME resulting in 0 or 1 tick with div = 1 are caught by | ||
646 | * div <= 0 check. | ||
647 | * | ||
648 | * @wait_monitoring: WAITMONITORINGTIME in ns. | ||
649 | * @return: -1 on failure to scale, else proper divider > 0. | ||
650 | */ | ||
651 | static int gpmc_calc_waitmonitoring_divider(unsigned int wait_monitoring) | ||
652 | { | ||
653 | |||
654 | int div = gpmc_ns_to_ticks(wait_monitoring); | ||
655 | |||
656 | div += GPMC_CONFIG1_WAITMONITORINGTIME_MAX - 1; | ||
657 | div /= GPMC_CONFIG1_WAITMONITORINGTIME_MAX; | ||
658 | |||
659 | if (div > 4) | ||
660 | return -1; | ||
661 | if (div <= 0) | ||
662 | div = 1; | ||
663 | |||
664 | return div; | ||
665 | |||
666 | } | ||
667 | |||
668 | /** | ||
669 | * gpmc_calc_divider - calculate GPMC_FCLK divider for sync_clk GPMC_CLK period. | ||
670 | * @sync_clk: GPMC_CLK period in ps. | ||
671 | * @return: Returns at least 1 if GPMC_FCLK can be divided to GPMC_CLK. | ||
672 | * Else, returns -1. | ||
673 | */ | ||
502 | int gpmc_calc_divider(unsigned int sync_clk) | 674 | int gpmc_calc_divider(unsigned int sync_clk) |
503 | { | 675 | { |
504 | int div; | 676 | int div = gpmc_ps_to_ticks(sync_clk); |
505 | u32 l; | ||
506 | 677 | ||
507 | l = sync_clk + (gpmc_get_fclk_period() - 1); | ||
508 | div = l / gpmc_get_fclk_period(); | ||
509 | if (div > 4) | 678 | if (div > 4) |
510 | return -1; | 679 | return -1; |
511 | if (div <= 0) | 680 | if (div <= 0) |
@@ -514,7 +683,15 @@ int gpmc_calc_divider(unsigned int sync_clk) | |||
514 | return div; | 683 | return div; |
515 | } | 684 | } |
516 | 685 | ||
517 | int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t) | 686 | /** |
687 | * gpmc_cs_set_timings - program timing parameters for Chip Select Region. | ||
688 | * @cs: Chip Select Region. | ||
689 | * @t: GPMC timing parameters. | ||
690 | * @s: GPMC timing settings. | ||
691 | * @return: 0 on success, -1 on error. | ||
692 | */ | ||
693 | int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t, | ||
694 | const struct gpmc_settings *s) | ||
518 | { | 695 | { |
519 | int div; | 696 | int div; |
520 | u32 l; | 697 | u32 l; |
@@ -524,6 +701,33 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t) | |||
524 | if (div < 0) | 701 | if (div < 0) |
525 | return div; | 702 | return div; |
526 | 703 | ||
704 | /* | ||
705 | * See if we need to change the divider for waitmonitoringtime. | ||
706 | * | ||
707 | * Calculate GPMCFCLKDIVIDER independent of gpmc,sync-clk-ps in DT for | ||
708 | * pure asynchronous accesses, i.e. both read and write asynchronous. | ||
709 | * However, only do so if WAITMONITORINGTIME is actually used, i.e. | ||
710 | * either WAITREADMONITORING or WAITWRITEMONITORING is set. | ||
711 | * | ||
712 | * This statement must not change div to scale async WAITMONITORINGTIME | ||
713 | * to protect mixed synchronous and asynchronous accesses. | ||
714 | * | ||
715 | * We raise an error later if WAITMONITORINGTIME does not fit. | ||
716 | */ | ||
717 | if (!s->sync_read && !s->sync_write && | ||
718 | (s->wait_on_read || s->wait_on_write) | ||
719 | ) { | ||
720 | |||
721 | div = gpmc_calc_waitmonitoring_divider(t->wait_monitoring); | ||
722 | if (div < 0) { | ||
723 | pr_err("%s: waitmonitoringtime %3d ns too large for greatest gpmcfclkdivider.\n", | ||
724 | __func__, | ||
725 | t->wait_monitoring | ||
726 | ); | ||
727 | return -1; | ||
728 | } | ||
729 | } | ||
730 | |||
527 | GPMC_SET_ONE(GPMC_CS_CONFIG2, 0, 3, cs_on); | 731 | GPMC_SET_ONE(GPMC_CS_CONFIG2, 0, 3, cs_on); |
528 | GPMC_SET_ONE(GPMC_CS_CONFIG2, 8, 12, cs_rd_off); | 732 | GPMC_SET_ONE(GPMC_CS_CONFIG2, 8, 12, cs_rd_off); |
529 | GPMC_SET_ONE(GPMC_CS_CONFIG2, 16, 20, cs_wr_off); | 733 | GPMC_SET_ONE(GPMC_CS_CONFIG2, 16, 20, cs_wr_off); |
@@ -546,27 +750,27 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t) | |||
546 | GPMC_SET_ONE(GPMC_CS_CONFIG6, 0, 3, bus_turnaround); | 750 | GPMC_SET_ONE(GPMC_CS_CONFIG6, 0, 3, bus_turnaround); |
547 | GPMC_SET_ONE(GPMC_CS_CONFIG6, 8, 11, cycle2cycle_delay); | 751 | GPMC_SET_ONE(GPMC_CS_CONFIG6, 8, 11, cycle2cycle_delay); |
548 | 752 | ||
549 | GPMC_SET_ONE(GPMC_CS_CONFIG1, 18, 19, wait_monitoring); | ||
550 | GPMC_SET_ONE(GPMC_CS_CONFIG1, 25, 26, clk_activation); | ||
551 | |||
552 | if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS) | 753 | if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS) |
553 | GPMC_SET_ONE(GPMC_CS_CONFIG6, 16, 19, wr_data_mux_bus); | 754 | GPMC_SET_ONE(GPMC_CS_CONFIG6, 16, 19, wr_data_mux_bus); |
554 | if (gpmc_capability & GPMC_HAS_WR_ACCESS) | 755 | if (gpmc_capability & GPMC_HAS_WR_ACCESS) |
555 | GPMC_SET_ONE(GPMC_CS_CONFIG6, 24, 28, wr_access); | 756 | GPMC_SET_ONE(GPMC_CS_CONFIG6, 24, 28, wr_access); |
556 | 757 | ||
557 | /* caller is expected to have initialized CONFIG1 to cover | ||
558 | * at least sync vs async | ||
559 | */ | ||
560 | l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1); | 758 | l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1); |
561 | if (l & (GPMC_CONFIG1_READTYPE_SYNC | GPMC_CONFIG1_WRITETYPE_SYNC)) { | 759 | l &= ~0x03; |
760 | l |= (div - 1); | ||
761 | gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l); | ||
762 | |||
763 | GPMC_SET_ONE_CD_MAX(GPMC_CS_CONFIG1, 18, 19, | ||
764 | GPMC_CONFIG1_WAITMONITORINGTIME_MAX, | ||
765 | wait_monitoring, GPMC_CD_CLK); | ||
766 | GPMC_SET_ONE_CD_MAX(GPMC_CS_CONFIG1, 25, 26, | ||
767 | GPMC_CONFIG1_CLKACTIVATIONTIME_MAX, | ||
768 | clk_activation, GPMC_CD_FCLK); | ||
769 | |||
562 | #ifdef DEBUG | 770 | #ifdef DEBUG |
563 | printk(KERN_INFO "GPMC CS%d CLK period is %lu ns (div %d)\n", | 771 | pr_info("GPMC CS%d CLK period is %lu ns (div %d)\n", |
564 | cs, (div * gpmc_get_fclk_period()) / 1000, div); | 772 | cs, (div * gpmc_get_fclk_period()) / 1000, div); |
565 | #endif | 773 | #endif |
566 | l &= ~0x03; | ||
567 | l |= (div - 1); | ||
568 | gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l); | ||
569 | } | ||
570 | 774 | ||
571 | gpmc_cs_bool_timings(cs, &t->bool_timings); | 775 | gpmc_cs_bool_timings(cs, &t->bool_timings); |
572 | gpmc_cs_show_timings(cs, "after gpmc_cs_set_timings"); | 776 | gpmc_cs_show_timings(cs, "after gpmc_cs_set_timings"); |
@@ -586,12 +790,15 @@ static int gpmc_cs_set_memconf(int cs, u32 base, u32 size) | |||
586 | if (base & (size - 1)) | 790 | if (base & (size - 1)) |
587 | return -EINVAL; | 791 | return -EINVAL; |
588 | 792 | ||
793 | base >>= GPMC_CHUNK_SHIFT; | ||
589 | mask = (1 << GPMC_SECTION_SHIFT) - size; | 794 | mask = (1 << GPMC_SECTION_SHIFT) - size; |
795 | mask >>= GPMC_CHUNK_SHIFT; | ||
796 | mask <<= GPMC_CONFIG7_MASKADDRESS_OFFSET; | ||
797 | |||
590 | l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7); | 798 | l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7); |
591 | l &= ~0x3f; | 799 | l &= ~GPMC_CONFIG7_MASK; |
592 | l = (base >> GPMC_CHUNK_SHIFT) & 0x3f; | 800 | l |= base & GPMC_CONFIG7_BASEADDRESS_MASK; |
593 | l &= ~(0x0f << 8); | 801 | l |= mask & GPMC_CONFIG7_MASKADDRESS_MASK; |
594 | l |= ((mask >> GPMC_CHUNK_SHIFT) & 0x0f) << 8; | ||
595 | l |= GPMC_CONFIG7_CSVALID; | 802 | l |= GPMC_CONFIG7_CSVALID; |
596 | gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l); | 803 | gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l); |
597 | 804 | ||
@@ -656,7 +863,7 @@ static void gpmc_cs_set_name(int cs, const char *name) | |||
656 | gpmc->name = name; | 863 | gpmc->name = name; |
657 | } | 864 | } |
658 | 865 | ||
659 | const char *gpmc_cs_get_name(int cs) | 866 | static const char *gpmc_cs_get_name(int cs) |
660 | { | 867 | { |
661 | struct gpmc_cs_data *gpmc = &gpmc_cs[cs]; | 868 | struct gpmc_cs_data *gpmc = &gpmc_cs[cs]; |
662 | 869 | ||
@@ -1786,7 +1993,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, | |||
1786 | if (ret < 0) | 1993 | if (ret < 0) |
1787 | goto err; | 1994 | goto err; |
1788 | 1995 | ||
1789 | ret = gpmc_cs_set_timings(cs, &gpmc_t); | 1996 | ret = gpmc_cs_set_timings(cs, &gpmc_t, &gpmc_s); |
1790 | if (ret) { | 1997 | if (ret) { |
1791 | dev_err(&pdev->dev, "failed to set gpmc timings for: %s\n", | 1998 | dev_err(&pdev->dev, "failed to set gpmc timings for: %s\n", |
1792 | child->name); | 1999 | child->name); |
@@ -1802,8 +2009,21 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, | |||
1802 | gpmc_cs_enable_mem(cs); | 2009 | gpmc_cs_enable_mem(cs); |
1803 | 2010 | ||
1804 | no_timings: | 2011 | no_timings: |
1805 | if (of_platform_device_create(child, NULL, &pdev->dev)) | 2012 | |
1806 | return 0; | 2013 | /* create platform device, NULL on error or when disabled */ |
2014 | if (!of_platform_device_create(child, NULL, &pdev->dev)) | ||
2015 | goto err_child_fail; | ||
2016 | |||
2017 | /* is child a common bus? */ | ||
2018 | if (of_match_node(of_default_bus_match_table, child)) | ||
2019 | /* create children and other common bus children */ | ||
2020 | if (of_platform_populate(child, of_default_bus_match_table, | ||
2021 | NULL, &pdev->dev)) | ||
2022 | goto err_child_fail; | ||
2023 | |||
2024 | return 0; | ||
2025 | |||
2026 | err_child_fail: | ||
1807 | 2027 | ||
1808 | dev_err(&pdev->dev, "failed to create gpmc child %s\n", child->name); | 2028 | dev_err(&pdev->dev, "failed to create gpmc child %s\n", child->name); |
1809 | ret = -ENODEV; | 2029 | ret = -ENODEV; |
diff --git a/include/linux/omap-gpmc.h b/include/linux/omap-gpmc.h index c2080eebbb47..7dee00143afd 100644 --- a/include/linux/omap-gpmc.h +++ b/include/linux/omap-gpmc.h | |||
@@ -163,7 +163,8 @@ extern unsigned int gpmc_ticks_to_ns(unsigned int ticks); | |||
163 | 163 | ||
164 | extern void gpmc_cs_write_reg(int cs, int idx, u32 val); | 164 | extern void gpmc_cs_write_reg(int cs, int idx, u32 val); |
165 | extern int gpmc_calc_divider(unsigned int sync_clk); | 165 | extern int gpmc_calc_divider(unsigned int sync_clk); |
166 | extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t); | 166 | extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t, |
167 | const struct gpmc_settings *s); | ||
167 | extern int gpmc_cs_program_settings(int cs, struct gpmc_settings *p); | 168 | extern int gpmc_cs_program_settings(int cs, struct gpmc_settings *p); |
168 | extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base); | 169 | extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base); |
169 | extern void gpmc_cs_free(int cs); | 170 | extern void gpmc_cs_free(int cs); |