aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/jz4740
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-08-05 11:53:20 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-08-05 11:53:20 -0400
commitc3d1f1746b966907ba5ad2f75ddca24db8b21147 (patch)
tree548a25e104d8bdb906030b8d3bf78fbfde0e5817 /arch/mips/jz4740
parent66eddbfcc1f6610fa7c73c8d20a57eaf8e284e2f (diff)
parent0d365753d0b7c26043fdfa97790411606fb40112 (diff)
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/upstream-linus
* 'upstream' of git://git.linux-mips.org/pub/scm/upstream-linus: (150 commits) MIPS: PowerTV: Separate PowerTV USB support from non-USB code MIPS: strip the un-needed sections of vmlinuz MIPS: Clean up the calculation of VMLINUZ_LOAD_ADDRESS MIPS: Clean up arch/mips/boot/compressed/decompress.c MIPS: Clean up arch/mips/boot/compressed/ld.script MIPS: Unify the suffix of compressed vmlinux.bin MIPS: PowerTV: Add Gaia platform definitions. MIPS: BCM47xx: Fix nvram_getenv return value. MIPS: Octeon: Allow more than 3.75GB of memory with PCIe MIPS: Clean up notify_die() usage. MIPS: Remove unused task_struct.trap_no field. Documentation: Mention that KProbes is supported on MIPS SAMPLES: kprobe_example: Make it print something on MIPS. MIPS: kprobe: Add support. MIPS: Add instrunction format for BREAK and SYSCALL MIPS: kprobes: Define regs_return_value() MIPS: Ritually kill stupid printk. MIPS: Octeon: Disallow MSI-X interrupt and fall back to MSI interrupts. MIPS: Octeon: Support 256 MSI on PCIe MIPS: Decode core number for R2 CPUs. ...
Diffstat (limited to 'arch/mips/jz4740')
-rw-r--r--arch/mips/jz4740/Kconfig12
-rw-r--r--arch/mips/jz4740/Makefile20
-rw-r--r--arch/mips/jz4740/Platform3
-rw-r--r--arch/mips/jz4740/board-qi_lb60.c471
-rw-r--r--arch/mips/jz4740/clock-debugfs.c109
-rw-r--r--arch/mips/jz4740/clock.c924
-rw-r--r--arch/mips/jz4740/clock.h76
-rw-r--r--arch/mips/jz4740/dma.c289
-rw-r--r--arch/mips/jz4740/gpio.c604
-rw-r--r--arch/mips/jz4740/irq.c167
-rw-r--r--arch/mips/jz4740/irq.h21
-rw-r--r--arch/mips/jz4740/platform.c291
-rw-r--r--arch/mips/jz4740/pm.c56
-rw-r--r--arch/mips/jz4740/prom.c68
-rw-r--r--arch/mips/jz4740/pwm.c177
-rw-r--r--arch/mips/jz4740/reset.c79
-rw-r--r--arch/mips/jz4740/reset.h6
-rw-r--r--arch/mips/jz4740/serial.c33
-rw-r--r--arch/mips/jz4740/serial.h20
-rw-r--r--arch/mips/jz4740/setup.c29
-rw-r--r--arch/mips/jz4740/time.c144
-rw-r--r--arch/mips/jz4740/timer.c48
-rw-r--r--arch/mips/jz4740/timer.h136
23 files changed, 3783 insertions, 0 deletions
diff --git a/arch/mips/jz4740/Kconfig b/arch/mips/jz4740/Kconfig
new file mode 100644
index 000000000000..3e7141f0746c
--- /dev/null
+++ b/arch/mips/jz4740/Kconfig
@@ -0,0 +1,12 @@
1choice
2 prompt "Machine type"
3 depends on MACH_JZ4740
4 default JZ4740_QI_LB60
5
6config JZ4740_QI_LB60
7 bool "Qi Hardware Ben NanoNote"
8
9endchoice
10
11config HAVE_PWM
12 bool
diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile
new file mode 100644
index 000000000000..a604eaeb6c08
--- /dev/null
+++ b/arch/mips/jz4740/Makefile
@@ -0,0 +1,20 @@
1#
2# Makefile for the Ingenic JZ4740.
3#
4
5# Object file lists.
6
7obj-y += prom.o irq.o time.o reset.o setup.o dma.o \
8 gpio.o clock.o platform.o timer.o pwm.o serial.o
9
10obj-$(CONFIG_DEBUG_FS) += clock-debugfs.o
11
12# board specific support
13
14obj-$(CONFIG_JZ4740_QI_LB60) += board-qi_lb60.o
15
16# PM support
17
18obj-$(CONFIG_PM) += pm.o
19
20EXTRA_CFLAGS += -Werror -Wall
diff --git a/arch/mips/jz4740/Platform b/arch/mips/jz4740/Platform
new file mode 100644
index 000000000000..6a97230e3d05
--- /dev/null
+++ b/arch/mips/jz4740/Platform
@@ -0,0 +1,3 @@
1core-$(CONFIG_MACH_JZ4740) += arch/mips/jz4740/
2cflags-$(CONFIG_MACH_JZ4740) += -I$(srctree)/arch/mips/include/asm/mach-jz4740
3load-$(CONFIG_MACH_JZ4740) += 0xffffffff80010000
diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c
new file mode 100644
index 000000000000..5742bb4d78f4
--- /dev/null
+++ b/arch/mips/jz4740/board-qi_lb60.c
@@ -0,0 +1,471 @@
1/*
2 * linux/arch/mips/jz4740/board-qi_lb60.c
3 *
4 * QI_LB60 board support
5 *
6 * Copyright (c) 2009 Qi Hardware inc.,
7 * Author: Xiangfu Liu <xiangfu@qi-hardware.com>
8 * Copyright 2010, Lars-Petrer Clausen <lars@metafoo.de>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 or later
12 * as published by the Free Software Foundation.
13 */
14
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/gpio.h>
18
19#include <linux/input.h>
20#include <linux/gpio_keys.h>
21#include <linux/input/matrix_keypad.h>
22#include <linux/spi/spi.h>
23#include <linux/spi/spi_gpio.h>
24#include <linux/power_supply.h>
25#include <linux/power/jz4740-battery.h>
26
27#include <asm/mach-jz4740/jz4740_fb.h>
28#include <asm/mach-jz4740/jz4740_mmc.h>
29#include <asm/mach-jz4740/jz4740_nand.h>
30
31#include <linux/regulator/fixed.h>
32#include <linux/regulator/machine.h>
33
34#include <linux/leds_pwm.h>
35
36#include <asm/mach-jz4740/platform.h>
37
38#include "clock.h"
39
40static bool is_avt2;
41
42/* GPIOs */
43#define QI_LB60_GPIO_SD_CD JZ_GPIO_PORTD(0)
44#define QI_LB60_GPIO_SD_VCC_EN_N JZ_GPIO_PORTD(2)
45
46#define QI_LB60_GPIO_KEYOUT(x) (JZ_GPIO_PORTC(10) + (x))
47#define QI_LB60_GPIO_KEYIN(x) (JZ_GPIO_PORTD(18) + (x))
48#define QI_LB60_GPIO_KEYIN8 JZ_GPIO_PORTD(26)
49
50/* NAND */
51static struct nand_ecclayout qi_lb60_ecclayout_1gb = {
52/* .eccbytes = 36,
53 .eccpos = {
54 6, 7, 8, 9, 10, 11, 12, 13,
55 14, 15, 16, 17, 18, 19, 20, 21,
56 22, 23, 24, 25, 26, 27, 28, 29,
57 30, 31, 32, 33, 34, 35, 36, 37,
58 38, 39, 40, 41
59 },*/
60 .oobfree = {
61 { .offset = 2, .length = 4 },
62 { .offset = 42, .length = 22 }
63 },
64};
65
66/* Early prototypes of the QI LB60 had only 1GB of NAND.
67 * In order to support these devices aswell the partition and ecc layout is
68 * initalized depending on the NAND size */
69static struct mtd_partition qi_lb60_partitions_1gb[] = {
70 {
71 .name = "NAND BOOT partition",
72 .offset = 0 * 0x100000,
73 .size = 4 * 0x100000,
74 },
75 {
76 .name = "NAND KERNEL partition",
77 .offset = 4 * 0x100000,
78 .size = 4 * 0x100000,
79 },
80 {
81 .name = "NAND ROOTFS partition",
82 .offset = 8 * 0x100000,
83 .size = (504 + 512) * 0x100000,
84 },
85};
86
87static struct nand_ecclayout qi_lb60_ecclayout_2gb = {
88/* .eccbytes = 72,
89 .eccpos = {
90 12, 13, 14, 15, 16, 17, 18, 19,
91 20, 21, 22, 23, 24, 25, 26, 27,
92 28, 29, 30, 31, 32, 33, 34, 35,
93 36, 37, 38, 39, 40, 41, 42, 43,
94 44, 45, 46, 47, 48, 49, 50, 51,
95 52, 53, 54, 55, 56, 57, 58, 59,
96 60, 61, 62, 63, 64, 65, 66, 67,
97 68, 69, 70, 71, 72, 73, 74, 75,
98 76, 77, 78, 79, 80, 81, 82, 83
99 },*/
100 .oobfree = {
101 { .offset = 2, .length = 10 },
102 { .offset = 84, .length = 44 },
103 },
104};
105
106static struct mtd_partition qi_lb60_partitions_2gb[] = {
107 {
108 .name = "NAND BOOT partition",
109 .offset = 0 * 0x100000,
110 .size = 4 * 0x100000,
111 },
112 {
113 .name = "NAND KERNEL partition",
114 .offset = 4 * 0x100000,
115 .size = 4 * 0x100000,
116 },
117 {
118 .name = "NAND ROOTFS partition",
119 .offset = 8 * 0x100000,
120 .size = (504 + 512 + 1024) * 0x100000,
121 },
122};
123
124static void qi_lb60_nand_ident(struct platform_device *pdev,
125 struct nand_chip *chip, struct mtd_partition **partitions,
126 int *num_partitions)
127{
128 if (chip->page_shift == 12) {
129 chip->ecc.layout = &qi_lb60_ecclayout_2gb;
130 *partitions = qi_lb60_partitions_2gb;
131 *num_partitions = ARRAY_SIZE(qi_lb60_partitions_2gb);
132 } else {
133 chip->ecc.layout = &qi_lb60_ecclayout_1gb;
134 *partitions = qi_lb60_partitions_1gb;
135 *num_partitions = ARRAY_SIZE(qi_lb60_partitions_1gb);
136 }
137}
138
139static struct jz_nand_platform_data qi_lb60_nand_pdata = {
140 .ident_callback = qi_lb60_nand_ident,
141 .busy_gpio = 94,
142};
143
144/* Keyboard*/
145
146#define KEY_QI_QI KEY_F13
147#define KEY_QI_UPRED KEY_RIGHTALT
148#define KEY_QI_VOLUP KEY_VOLUMEUP
149#define KEY_QI_VOLDOWN KEY_VOLUMEDOWN
150#define KEY_QI_FN KEY_LEFTCTRL
151
152static const uint32_t qi_lb60_keymap[] = {
153 KEY(0, 0, KEY_F1), /* S2 */
154 KEY(0, 1, KEY_F2), /* S3 */
155 KEY(0, 2, KEY_F3), /* S4 */
156 KEY(0, 3, KEY_F4), /* S5 */
157 KEY(0, 4, KEY_F5), /* S6 */
158 KEY(0, 5, KEY_F6), /* S7 */
159 KEY(0, 6, KEY_F7), /* S8 */
160
161 KEY(1, 0, KEY_Q), /* S10 */
162 KEY(1, 1, KEY_W), /* S11 */
163 KEY(1, 2, KEY_E), /* S12 */
164 KEY(1, 3, KEY_R), /* S13 */
165 KEY(1, 4, KEY_T), /* S14 */
166 KEY(1, 5, KEY_Y), /* S15 */
167 KEY(1, 6, KEY_U), /* S16 */
168 KEY(1, 7, KEY_I), /* S17 */
169 KEY(2, 0, KEY_A), /* S18 */
170 KEY(2, 1, KEY_S), /* S19 */
171 KEY(2, 2, KEY_D), /* S20 */
172 KEY(2, 3, KEY_F), /* S21 */
173 KEY(2, 4, KEY_G), /* S22 */
174 KEY(2, 5, KEY_H), /* S23 */
175 KEY(2, 6, KEY_J), /* S24 */
176 KEY(2, 7, KEY_K), /* S25 */
177 KEY(3, 0, KEY_ESC), /* S26 */
178 KEY(3, 1, KEY_Z), /* S27 */
179 KEY(3, 2, KEY_X), /* S28 */
180 KEY(3, 3, KEY_C), /* S29 */
181 KEY(3, 4, KEY_V), /* S30 */
182 KEY(3, 5, KEY_B), /* S31 */
183 KEY(3, 6, KEY_N), /* S32 */
184 KEY(3, 7, KEY_M), /* S33 */
185 KEY(4, 0, KEY_TAB), /* S34 */
186 KEY(4, 1, KEY_CAPSLOCK), /* S35 */
187 KEY(4, 2, KEY_BACKSLASH), /* S36 */
188 KEY(4, 3, KEY_APOSTROPHE), /* S37 */
189 KEY(4, 4, KEY_COMMA), /* S38 */
190 KEY(4, 5, KEY_DOT), /* S39 */
191 KEY(4, 6, KEY_SLASH), /* S40 */
192 KEY(4, 7, KEY_UP), /* S41 */
193 KEY(5, 0, KEY_O), /* S42 */
194 KEY(5, 1, KEY_L), /* S43 */
195 KEY(5, 2, KEY_EQUAL), /* S44 */
196 KEY(5, 3, KEY_QI_UPRED), /* S45 */
197 KEY(5, 4, KEY_SPACE), /* S46 */
198 KEY(5, 5, KEY_QI_QI), /* S47 */
199 KEY(5, 6, KEY_RIGHTCTRL), /* S48 */
200 KEY(5, 7, KEY_LEFT), /* S49 */
201 KEY(6, 0, KEY_F8), /* S50 */
202 KEY(6, 1, KEY_P), /* S51 */
203 KEY(6, 2, KEY_BACKSPACE),/* S52 */
204 KEY(6, 3, KEY_ENTER), /* S53 */
205 KEY(6, 4, KEY_QI_VOLUP), /* S54 */
206 KEY(6, 5, KEY_QI_VOLDOWN), /* S55 */
207 KEY(6, 6, KEY_DOWN), /* S56 */
208 KEY(6, 7, KEY_RIGHT), /* S57 */
209
210 KEY(7, 0, KEY_LEFTSHIFT), /* S58 */
211 KEY(7, 1, KEY_LEFTALT), /* S59 */
212 KEY(7, 2, KEY_QI_FN), /* S60 */
213};
214
215static const struct matrix_keymap_data qi_lb60_keymap_data = {
216 .keymap = qi_lb60_keymap,
217 .keymap_size = ARRAY_SIZE(qi_lb60_keymap),
218};
219
220static const unsigned int qi_lb60_keypad_cols[] = {
221 QI_LB60_GPIO_KEYOUT(0),
222 QI_LB60_GPIO_KEYOUT(1),
223 QI_LB60_GPIO_KEYOUT(2),
224 QI_LB60_GPIO_KEYOUT(3),
225 QI_LB60_GPIO_KEYOUT(4),
226 QI_LB60_GPIO_KEYOUT(5),
227 QI_LB60_GPIO_KEYOUT(6),
228 QI_LB60_GPIO_KEYOUT(7),
229};
230
231static const unsigned int qi_lb60_keypad_rows[] = {
232 QI_LB60_GPIO_KEYIN(0),
233 QI_LB60_GPIO_KEYIN(1),
234 QI_LB60_GPIO_KEYIN(2),
235 QI_LB60_GPIO_KEYIN(3),
236 QI_LB60_GPIO_KEYIN(4),
237 QI_LB60_GPIO_KEYIN(5),
238 QI_LB60_GPIO_KEYIN(7),
239 QI_LB60_GPIO_KEYIN8,
240};
241
242static struct matrix_keypad_platform_data qi_lb60_pdata = {
243 .keymap_data = &qi_lb60_keymap_data,
244 .col_gpios = qi_lb60_keypad_cols,
245 .row_gpios = qi_lb60_keypad_rows,
246 .num_col_gpios = ARRAY_SIZE(qi_lb60_keypad_cols),
247 .num_row_gpios = ARRAY_SIZE(qi_lb60_keypad_rows),
248 .col_scan_delay_us = 10,
249 .debounce_ms = 10,
250 .wakeup = 1,
251 .active_low = 1,
252};
253
254static struct platform_device qi_lb60_keypad = {
255 .name = "matrix-keypad",
256 .id = -1,
257 .dev = {
258 .platform_data = &qi_lb60_pdata,
259 },
260};
261
262/* Display */
263static struct fb_videomode qi_lb60_video_modes[] = {
264 {
265 .name = "320x240",
266 .xres = 320,
267 .yres = 240,
268 .refresh = 30,
269 .left_margin = 140,
270 .right_margin = 273,
271 .upper_margin = 20,
272 .lower_margin = 2,
273 .hsync_len = 1,
274 .vsync_len = 1,
275 .sync = 0,
276 .vmode = FB_VMODE_NONINTERLACED,
277 },
278};
279
280static struct jz4740_fb_platform_data qi_lb60_fb_pdata = {
281 .width = 60,
282 .height = 45,
283 .num_modes = ARRAY_SIZE(qi_lb60_video_modes),
284 .modes = qi_lb60_video_modes,
285 .bpp = 24,
286 .lcd_type = JZ_LCD_TYPE_8BIT_SERIAL,
287 .pixclk_falling_edge = 1,
288};
289
290struct spi_gpio_platform_data spigpio_platform_data = {
291 .sck = JZ_GPIO_PORTC(23),
292 .mosi = JZ_GPIO_PORTC(22),
293 .miso = -1,
294 .num_chipselect = 1,
295};
296
297static struct platform_device spigpio_device = {
298 .name = "spi_gpio",
299 .id = 1,
300 .dev = {
301 .platform_data = &spigpio_platform_data,
302 },
303};
304
305static struct spi_board_info qi_lb60_spi_board_info[] = {
306 {
307 .modalias = "ili8960",
308 .controller_data = (void *)JZ_GPIO_PORTC(21),
309 .chip_select = 0,
310 .bus_num = 1,
311 .max_speed_hz = 30 * 1000,
312 .mode = SPI_3WIRE,
313 },
314};
315
316/* Battery */
317static struct jz_battery_platform_data qi_lb60_battery_pdata = {
318 .gpio_charge = JZ_GPIO_PORTC(27),
319 .gpio_charge_active_low = 1,
320 .info = {
321 .name = "battery",
322 .technology = POWER_SUPPLY_TECHNOLOGY_LIPO,
323 .voltage_max_design = 4200000,
324 .voltage_min_design = 3600000,
325 },
326};
327
328/* GPIO Key: power */
329static struct gpio_keys_button qi_lb60_gpio_keys_buttons[] = {
330 [0] = {
331 .code = KEY_POWER,
332 .gpio = JZ_GPIO_PORTD(29),
333 .active_low = 1,
334 .desc = "Power",
335 .wakeup = 1,
336 },
337};
338
339static struct gpio_keys_platform_data qi_lb60_gpio_keys_data = {
340 .nbuttons = ARRAY_SIZE(qi_lb60_gpio_keys_buttons),
341 .buttons = qi_lb60_gpio_keys_buttons,
342};
343
344static struct platform_device qi_lb60_gpio_keys = {
345 .name = "gpio-keys",
346 .id = -1,
347 .dev = {
348 .platform_data = &qi_lb60_gpio_keys_data,
349 }
350};
351
352static struct jz4740_mmc_platform_data qi_lb60_mmc_pdata = {
353 .gpio_card_detect = QI_LB60_GPIO_SD_CD,
354 .gpio_read_only = -1,
355 .gpio_power = QI_LB60_GPIO_SD_VCC_EN_N,
356 .power_active_low = 1,
357};
358
359/* OHCI */
360static struct regulator_consumer_supply avt2_usb_regulator_consumer =
361 REGULATOR_SUPPLY("vbus", "jz4740-ohci");
362
363static struct regulator_init_data avt2_usb_regulator_init_data = {
364 .num_consumer_supplies = 1,
365 .consumer_supplies = &avt2_usb_regulator_consumer,
366 .constraints = {
367 .name = "USB power",
368 .min_uV = 5000000,
369 .max_uV = 5000000,
370 .valid_modes_mask = REGULATOR_MODE_NORMAL,
371 .valid_ops_mask = REGULATOR_CHANGE_STATUS,
372 },
373};
374
375static struct fixed_voltage_config avt2_usb_regulator_data = {
376 .supply_name = "USB power",
377 .microvolts = 5000000,
378 .gpio = JZ_GPIO_PORTB(17),
379 .init_data = &avt2_usb_regulator_init_data,
380};
381
382static struct platform_device avt2_usb_regulator_device = {
383 .name = "reg-fixed-voltage",
384 .id = -1,
385 .dev = {
386 .platform_data = &avt2_usb_regulator_data,
387 }
388};
389
390/* beeper */
391static struct platform_device qi_lb60_pwm_beeper = {
392 .name = "pwm-beeper",
393 .id = -1,
394 .dev = {
395 .platform_data = (void *)4,
396 },
397};
398
399static struct platform_device *jz_platform_devices[] __initdata = {
400 &jz4740_udc_device,
401 &jz4740_mmc_device,
402 &jz4740_nand_device,
403 &qi_lb60_keypad,
404 &spigpio_device,
405 &jz4740_framebuffer_device,
406 &jz4740_pcm_device,
407 &jz4740_i2s_device,
408 &jz4740_codec_device,
409 &jz4740_rtc_device,
410 &jz4740_adc_device,
411 &qi_lb60_gpio_keys,
412 &qi_lb60_pwm_beeper,
413};
414
415static void __init board_gpio_setup(void)
416{
417 /* We only need to enable/disable pullup here for pins used in generic
418 * drivers. Everything else is done by the drivers themselfs. */
419 jz_gpio_disable_pullup(QI_LB60_GPIO_SD_VCC_EN_N);
420 jz_gpio_disable_pullup(QI_LB60_GPIO_SD_CD);
421}
422
423static int __init qi_lb60_init_platform_devices(void)
424{
425 jz4740_framebuffer_device.dev.platform_data = &qi_lb60_fb_pdata;
426 jz4740_nand_device.dev.platform_data = &qi_lb60_nand_pdata;
427 jz4740_adc_device.dev.platform_data = &qi_lb60_battery_pdata;
428 jz4740_mmc_device.dev.platform_data = &qi_lb60_mmc_pdata;
429
430 jz4740_serial_device_register();
431
432 spi_register_board_info(qi_lb60_spi_board_info,
433 ARRAY_SIZE(qi_lb60_spi_board_info));
434
435 if (is_avt2) {
436 platform_device_register(&avt2_usb_regulator_device);
437 platform_device_register(&jz4740_usb_ohci_device);
438 }
439
440 return platform_add_devices(jz_platform_devices,
441 ARRAY_SIZE(jz_platform_devices));
442
443}
444
445struct jz4740_clock_board_data jz4740_clock_bdata = {
446 .ext_rate = 12000000,
447 .rtc_rate = 32768,
448};
449
450static __init int board_avt2(char *str)
451{
452 qi_lb60_mmc_pdata.card_detect_active_low = 1;
453 is_avt2 = true;
454
455 return 1;
456}
457__setup("avt2", board_avt2);
458
459static int __init qi_lb60_board_setup(void)
460{
461 printk(KERN_INFO "Qi Hardware JZ4740 QI %s setup\n",
462 is_avt2 ? "AVT2" : "LB60");
463
464 board_gpio_setup();
465
466 if (qi_lb60_init_platform_devices())
467 panic("Failed to initalize platform devices\n");
468
469 return 0;
470}
471arch_initcall(qi_lb60_board_setup);
diff --git a/arch/mips/jz4740/clock-debugfs.c b/arch/mips/jz4740/clock-debugfs.c
new file mode 100644
index 000000000000..330a0f2bf17b
--- /dev/null
+++ b/arch/mips/jz4740/clock-debugfs.c
@@ -0,0 +1,109 @@
1/*
2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4740 SoC clock support debugfs entries
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/clk.h>
19#include <linux/err.h>
20
21#include <linux/debugfs.h>
22#include <linux/uaccess.h>
23
24#include <asm/mach-jz4740/clock.h>
25#include "clock.h"
26
27static struct dentry *jz4740_clock_debugfs;
28
29static int jz4740_clock_debugfs_show_enabled(void *data, uint64_t *value)
30{
31 struct clk *clk = data;
32 *value = clk_is_enabled(clk);
33
34 return 0;
35}
36
37static int jz4740_clock_debugfs_set_enabled(void *data, uint64_t value)
38{
39 struct clk *clk = data;
40
41 if (value)
42 return clk_enable(clk);
43 else
44 clk_disable(clk);
45
46 return 0;
47}
48
49DEFINE_SIMPLE_ATTRIBUTE(jz4740_clock_debugfs_ops_enabled,
50 jz4740_clock_debugfs_show_enabled,
51 jz4740_clock_debugfs_set_enabled,
52 "%llu\n");
53
54static int jz4740_clock_debugfs_show_rate(void *data, uint64_t *value)
55{
56 struct clk *clk = data;
57 *value = clk_get_rate(clk);
58
59 return 0;
60}
61
62DEFINE_SIMPLE_ATTRIBUTE(jz4740_clock_debugfs_ops_rate,
63 jz4740_clock_debugfs_show_rate,
64 NULL,
65 "%llu\n");
66
67void jz4740_clock_debugfs_add_clk(struct clk *clk)
68{
69 if (!jz4740_clock_debugfs)
70 return;
71
72 clk->debugfs_entry = debugfs_create_dir(clk->name, jz4740_clock_debugfs);
73 debugfs_create_file("rate", S_IWUGO | S_IRUGO, clk->debugfs_entry, clk,
74 &jz4740_clock_debugfs_ops_rate);
75 debugfs_create_file("enabled", S_IRUGO, clk->debugfs_entry, clk,
76 &jz4740_clock_debugfs_ops_enabled);
77
78 if (clk->parent) {
79 char parent_path[100];
80 snprintf(parent_path, 100, "../%s", clk->parent->name);
81 clk->debugfs_parent_entry = debugfs_create_symlink("parent",
82 clk->debugfs_entry,
83 parent_path);
84 }
85}
86
87/* TODO: Locking */
88void jz4740_clock_debugfs_update_parent(struct clk *clk)
89{
90 if (clk->debugfs_parent_entry)
91 debugfs_remove(clk->debugfs_parent_entry);
92
93 if (clk->parent) {
94 char parent_path[100];
95 snprintf(parent_path, 100, "../%s", clk->parent->name);
96 clk->debugfs_parent_entry = debugfs_create_symlink("parent",
97 clk->debugfs_entry,
98 parent_path);
99 } else {
100 clk->debugfs_parent_entry = NULL;
101 }
102}
103
104void jz4740_clock_debugfs_init(void)
105{
106 jz4740_clock_debugfs = debugfs_create_dir("jz4740-clock", NULL);
107 if (IS_ERR(jz4740_clock_debugfs))
108 jz4740_clock_debugfs = NULL;
109}
diff --git a/arch/mips/jz4740/clock.c b/arch/mips/jz4740/clock.c
new file mode 100644
index 000000000000..118a8a5562dd
--- /dev/null
+++ b/arch/mips/jz4740/clock.c
@@ -0,0 +1,924 @@
1/*
2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4740 SoC clock support
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#include <linux/kernel.h>
17#include <linux/errno.h>
18#include <linux/clk.h>
19#include <linux/spinlock.h>
20#include <linux/io.h>
21#include <linux/module.h>
22#include <linux/list.h>
23#include <linux/err.h>
24
25#include <asm/mach-jz4740/clock.h>
26#include <asm/mach-jz4740/base.h>
27
28#include "clock.h"
29
30#define JZ_REG_CLOCK_CTRL 0x00
31#define JZ_REG_CLOCK_LOW_POWER 0x04
32#define JZ_REG_CLOCK_PLL 0x10
33#define JZ_REG_CLOCK_GATE 0x20
34#define JZ_REG_CLOCK_SLEEP_CTRL 0x24
35#define JZ_REG_CLOCK_I2S 0x60
36#define JZ_REG_CLOCK_LCD 0x64
37#define JZ_REG_CLOCK_MMC 0x68
38#define JZ_REG_CLOCK_UHC 0x6C
39#define JZ_REG_CLOCK_SPI 0x74
40
41#define JZ_CLOCK_CTRL_I2S_SRC_PLL BIT(31)
42#define JZ_CLOCK_CTRL_KO_ENABLE BIT(30)
43#define JZ_CLOCK_CTRL_UDC_SRC_PLL BIT(29)
44#define JZ_CLOCK_CTRL_UDIV_MASK 0x1f800000
45#define JZ_CLOCK_CTRL_CHANGE_ENABLE BIT(22)
46#define JZ_CLOCK_CTRL_PLL_HALF BIT(21)
47#define JZ_CLOCK_CTRL_LDIV_MASK 0x001f0000
48#define JZ_CLOCK_CTRL_UDIV_OFFSET 23
49#define JZ_CLOCK_CTRL_LDIV_OFFSET 16
50#define JZ_CLOCK_CTRL_MDIV_OFFSET 12
51#define JZ_CLOCK_CTRL_PDIV_OFFSET 8
52#define JZ_CLOCK_CTRL_HDIV_OFFSET 4
53#define JZ_CLOCK_CTRL_CDIV_OFFSET 0
54
55#define JZ_CLOCK_GATE_UART0 BIT(0)
56#define JZ_CLOCK_GATE_TCU BIT(1)
57#define JZ_CLOCK_GATE_RTC BIT(2)
58#define JZ_CLOCK_GATE_I2C BIT(3)
59#define JZ_CLOCK_GATE_SPI BIT(4)
60#define JZ_CLOCK_GATE_AIC BIT(5)
61#define JZ_CLOCK_GATE_I2S BIT(6)
62#define JZ_CLOCK_GATE_MMC BIT(7)
63#define JZ_CLOCK_GATE_ADC BIT(8)
64#define JZ_CLOCK_GATE_CIM BIT(9)
65#define JZ_CLOCK_GATE_LCD BIT(10)
66#define JZ_CLOCK_GATE_UDC BIT(11)
67#define JZ_CLOCK_GATE_DMAC BIT(12)
68#define JZ_CLOCK_GATE_IPU BIT(13)
69#define JZ_CLOCK_GATE_UHC BIT(14)
70#define JZ_CLOCK_GATE_UART1 BIT(15)
71
72#define JZ_CLOCK_I2S_DIV_MASK 0x01ff
73
74#define JZ_CLOCK_LCD_DIV_MASK 0x01ff
75
76#define JZ_CLOCK_MMC_DIV_MASK 0x001f
77
78#define JZ_CLOCK_UHC_DIV_MASK 0x000f
79
80#define JZ_CLOCK_SPI_SRC_PLL BIT(31)
81#define JZ_CLOCK_SPI_DIV_MASK 0x000f
82
83#define JZ_CLOCK_PLL_M_MASK 0x01ff
84#define JZ_CLOCK_PLL_N_MASK 0x001f
85#define JZ_CLOCK_PLL_OD_MASK 0x0003
86#define JZ_CLOCK_PLL_STABLE BIT(10)
87#define JZ_CLOCK_PLL_BYPASS BIT(9)
88#define JZ_CLOCK_PLL_ENABLED BIT(8)
89#define JZ_CLOCK_PLL_STABLIZE_MASK 0x000f
90#define JZ_CLOCK_PLL_M_OFFSET 23
91#define JZ_CLOCK_PLL_N_OFFSET 18
92#define JZ_CLOCK_PLL_OD_OFFSET 16
93
94#define JZ_CLOCK_LOW_POWER_MODE_DOZE BIT(2)
95#define JZ_CLOCK_LOW_POWER_MODE_SLEEP BIT(0)
96
97#define JZ_CLOCK_SLEEP_CTRL_SUSPEND_UHC BIT(7)
98#define JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC BIT(6)
99
100static void __iomem *jz_clock_base;
101static spinlock_t jz_clock_lock;
102static LIST_HEAD(jz_clocks);
103
104struct main_clk {
105 struct clk clk;
106 uint32_t div_offset;
107};
108
109struct divided_clk {
110 struct clk clk;
111 uint32_t reg;
112 uint32_t mask;
113};
114
115struct static_clk {
116 struct clk clk;
117 unsigned long rate;
118};
119
120static uint32_t jz_clk_reg_read(int reg)
121{
122 return readl(jz_clock_base + reg);
123}
124
125static void jz_clk_reg_write_mask(int reg, uint32_t val, uint32_t mask)
126{
127 uint32_t val2;
128
129 spin_lock(&jz_clock_lock);
130 val2 = readl(jz_clock_base + reg);
131 val2 &= ~mask;
132 val2 |= val;
133 writel(val2, jz_clock_base + reg);
134 spin_unlock(&jz_clock_lock);
135}
136
137static void jz_clk_reg_set_bits(int reg, uint32_t mask)
138{
139 uint32_t val;
140
141 spin_lock(&jz_clock_lock);
142 val = readl(jz_clock_base + reg);
143 val |= mask;
144 writel(val, jz_clock_base + reg);
145 spin_unlock(&jz_clock_lock);
146}
147
148static void jz_clk_reg_clear_bits(int reg, uint32_t mask)
149{
150 uint32_t val;
151
152 spin_lock(&jz_clock_lock);
153 val = readl(jz_clock_base + reg);
154 val &= ~mask;
155 writel(val, jz_clock_base + reg);
156 spin_unlock(&jz_clock_lock);
157}
158
159static int jz_clk_enable_gating(struct clk *clk)
160{
161 if (clk->gate_bit == JZ4740_CLK_NOT_GATED)
162 return -EINVAL;
163
164 jz_clk_reg_clear_bits(JZ_REG_CLOCK_GATE, clk->gate_bit);
165 return 0;
166}
167
168static int jz_clk_disable_gating(struct clk *clk)
169{
170 if (clk->gate_bit == JZ4740_CLK_NOT_GATED)
171 return -EINVAL;
172
173 jz_clk_reg_set_bits(JZ_REG_CLOCK_GATE, clk->gate_bit);
174 return 0;
175}
176
177static int jz_clk_is_enabled_gating(struct clk *clk)
178{
179 if (clk->gate_bit == JZ4740_CLK_NOT_GATED)
180 return 1;
181
182 return !(jz_clk_reg_read(JZ_REG_CLOCK_GATE) & clk->gate_bit);
183}
184
185static unsigned long jz_clk_static_get_rate(struct clk *clk)
186{
187 return ((struct static_clk *)clk)->rate;
188}
189
190static int jz_clk_ko_enable(struct clk *clk)
191{
192 jz_clk_reg_set_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_KO_ENABLE);
193 return 0;
194}
195
196static int jz_clk_ko_disable(struct clk *clk)
197{
198 jz_clk_reg_clear_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_KO_ENABLE);
199 return 0;
200}
201
202static int jz_clk_ko_is_enabled(struct clk *clk)
203{
204 return !!(jz_clk_reg_read(JZ_REG_CLOCK_CTRL) & JZ_CLOCK_CTRL_KO_ENABLE);
205}
206
207static const int pllno[] = {1, 2, 2, 4};
208
209static unsigned long jz_clk_pll_get_rate(struct clk *clk)
210{
211 uint32_t val;
212 int m;
213 int n;
214 int od;
215
216 val = jz_clk_reg_read(JZ_REG_CLOCK_PLL);
217
218 if (val & JZ_CLOCK_PLL_BYPASS)
219 return clk_get_rate(clk->parent);
220
221 m = ((val >> 23) & 0x1ff) + 2;
222 n = ((val >> 18) & 0x1f) + 2;
223 od = (val >> 16) & 0x3;
224
225 return ((clk_get_rate(clk->parent) / n) * m) / pllno[od];
226}
227
228static unsigned long jz_clk_pll_half_get_rate(struct clk *clk)
229{
230 uint32_t reg;
231
232 reg = jz_clk_reg_read(JZ_REG_CLOCK_CTRL);
233 if (reg & JZ_CLOCK_CTRL_PLL_HALF)
234 return jz_clk_pll_get_rate(clk->parent);
235 return jz_clk_pll_get_rate(clk->parent) >> 1;
236}
237
238static const int jz_clk_main_divs[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
239
240static unsigned long jz_clk_main_round_rate(struct clk *clk, unsigned long rate)
241{
242 unsigned long parent_rate = jz_clk_pll_get_rate(clk->parent);
243 int div;
244
245 div = parent_rate / rate;
246 if (div > 32)
247 return parent_rate / 32;
248 else if (div < 1)
249 return parent_rate;
250
251 div &= (0x3 << (ffs(div) - 1));
252
253 return parent_rate / div;
254}
255
256static unsigned long jz_clk_main_get_rate(struct clk *clk)
257{
258 struct main_clk *mclk = (struct main_clk *)clk;
259 uint32_t div;
260
261 div = jz_clk_reg_read(JZ_REG_CLOCK_CTRL);
262
263 div >>= mclk->div_offset;
264 div &= 0xf;
265
266 if (div >= ARRAY_SIZE(jz_clk_main_divs))
267 div = ARRAY_SIZE(jz_clk_main_divs) - 1;
268
269 return jz_clk_pll_get_rate(clk->parent) / jz_clk_main_divs[div];
270}
271
272static int jz_clk_main_set_rate(struct clk *clk, unsigned long rate)
273{
274 struct main_clk *mclk = (struct main_clk *)clk;
275 int i;
276 int div;
277 unsigned long parent_rate = jz_clk_pll_get_rate(clk->parent);
278
279 rate = jz_clk_main_round_rate(clk, rate);
280
281 div = parent_rate / rate;
282
283 i = (ffs(div) - 1) << 1;
284 if (i > 0 && !(div & BIT(i-1)))
285 i -= 1;
286
287 jz_clk_reg_write_mask(JZ_REG_CLOCK_CTRL, i << mclk->div_offset,
288 0xf << mclk->div_offset);
289
290 return 0;
291}
292
293static struct clk_ops jz_clk_static_ops = {
294 .get_rate = jz_clk_static_get_rate,
295 .enable = jz_clk_enable_gating,
296 .disable = jz_clk_disable_gating,
297 .is_enabled = jz_clk_is_enabled_gating,
298};
299
300static struct static_clk jz_clk_ext = {
301 .clk = {
302 .name = "ext",
303 .gate_bit = JZ4740_CLK_NOT_GATED,
304 .ops = &jz_clk_static_ops,
305 },
306};
307
308static struct clk_ops jz_clk_pll_ops = {
309 .get_rate = jz_clk_pll_get_rate,
310};
311
312static struct clk jz_clk_pll = {
313 .name = "pll",
314 .parent = &jz_clk_ext.clk,
315 .ops = &jz_clk_pll_ops,
316};
317
318static struct clk_ops jz_clk_pll_half_ops = {
319 .get_rate = jz_clk_pll_half_get_rate,
320};
321
322static struct clk jz_clk_pll_half = {
323 .name = "pll half",
324 .parent = &jz_clk_pll,
325 .ops = &jz_clk_pll_half_ops,
326};
327
328static const struct clk_ops jz_clk_main_ops = {
329 .get_rate = jz_clk_main_get_rate,
330 .set_rate = jz_clk_main_set_rate,
331 .round_rate = jz_clk_main_round_rate,
332};
333
334static struct main_clk jz_clk_cpu = {
335 .clk = {
336 .name = "cclk",
337 .parent = &jz_clk_pll,
338 .ops = &jz_clk_main_ops,
339 },
340 .div_offset = JZ_CLOCK_CTRL_CDIV_OFFSET,
341};
342
343static struct main_clk jz_clk_memory = {
344 .clk = {
345 .name = "mclk",
346 .parent = &jz_clk_pll,
347 .ops = &jz_clk_main_ops,
348 },
349 .div_offset = JZ_CLOCK_CTRL_MDIV_OFFSET,
350};
351
352static struct main_clk jz_clk_high_speed_peripheral = {
353 .clk = {
354 .name = "hclk",
355 .parent = &jz_clk_pll,
356 .ops = &jz_clk_main_ops,
357 },
358 .div_offset = JZ_CLOCK_CTRL_HDIV_OFFSET,
359};
360
361
362static struct main_clk jz_clk_low_speed_peripheral = {
363 .clk = {
364 .name = "pclk",
365 .parent = &jz_clk_pll,
366 .ops = &jz_clk_main_ops,
367 },
368 .div_offset = JZ_CLOCK_CTRL_PDIV_OFFSET,
369};
370
371static const struct clk_ops jz_clk_ko_ops = {
372 .enable = jz_clk_ko_enable,
373 .disable = jz_clk_ko_disable,
374 .is_enabled = jz_clk_ko_is_enabled,
375};
376
377static struct clk jz_clk_ko = {
378 .name = "cko",
379 .parent = &jz_clk_memory.clk,
380 .ops = &jz_clk_ko_ops,
381};
382
383static int jz_clk_spi_set_parent(struct clk *clk, struct clk *parent)
384{
385 if (parent == &jz_clk_pll)
386 jz_clk_reg_set_bits(JZ_CLOCK_SPI_SRC_PLL, JZ_REG_CLOCK_SPI);
387 else if (parent == &jz_clk_ext.clk)
388 jz_clk_reg_clear_bits(JZ_CLOCK_SPI_SRC_PLL, JZ_REG_CLOCK_SPI);
389 else
390 return -EINVAL;
391
392 clk->parent = parent;
393
394 return 0;
395}
396
397static int jz_clk_i2s_set_parent(struct clk *clk, struct clk *parent)
398{
399 if (parent == &jz_clk_pll_half)
400 jz_clk_reg_set_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_I2S_SRC_PLL);
401 else if (parent == &jz_clk_ext.clk)
402 jz_clk_reg_clear_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_I2S_SRC_PLL);
403 else
404 return -EINVAL;
405
406 clk->parent = parent;
407
408 return 0;
409}
410
411static int jz_clk_udc_enable(struct clk *clk)
412{
413 jz_clk_reg_set_bits(JZ_REG_CLOCK_SLEEP_CTRL,
414 JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC);
415
416 return 0;
417}
418
419static int jz_clk_udc_disable(struct clk *clk)
420{
421 jz_clk_reg_clear_bits(JZ_REG_CLOCK_SLEEP_CTRL,
422 JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC);
423
424 return 0;
425}
426
427static int jz_clk_udc_is_enabled(struct clk *clk)
428{
429 return !!(jz_clk_reg_read(JZ_REG_CLOCK_SLEEP_CTRL) &
430 JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC);
431}
432
433static int jz_clk_udc_set_parent(struct clk *clk, struct clk *parent)
434{
435 if (parent == &jz_clk_pll_half)
436 jz_clk_reg_set_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_UDC_SRC_PLL);
437 else if (parent == &jz_clk_ext.clk)
438 jz_clk_reg_clear_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_UDC_SRC_PLL);
439 else
440 return -EINVAL;
441
442 clk->parent = parent;
443
444 return 0;
445}
446
447static int jz_clk_udc_set_rate(struct clk *clk, unsigned long rate)
448{
449 int div;
450
451 if (clk->parent == &jz_clk_ext.clk)
452 return -EINVAL;
453
454 div = clk_get_rate(clk->parent) / rate - 1;
455
456 if (div < 0)
457 div = 0;
458 else if (div > 63)
459 div = 63;
460
461 jz_clk_reg_write_mask(JZ_REG_CLOCK_CTRL, div << JZ_CLOCK_CTRL_UDIV_OFFSET,
462 JZ_CLOCK_CTRL_UDIV_MASK);
463 return 0;
464}
465
466static unsigned long jz_clk_udc_get_rate(struct clk *clk)
467{
468 int div;
469
470 if (clk->parent == &jz_clk_ext.clk)
471 return clk_get_rate(clk->parent);
472
473 div = (jz_clk_reg_read(JZ_REG_CLOCK_CTRL) & JZ_CLOCK_CTRL_UDIV_MASK);
474 div >>= JZ_CLOCK_CTRL_UDIV_OFFSET;
475 div += 1;
476
477 return clk_get_rate(clk->parent) / div;
478}
479
480static unsigned long jz_clk_divided_get_rate(struct clk *clk)
481{
482 struct divided_clk *dclk = (struct divided_clk *)clk;
483 int div;
484
485 if (clk->parent == &jz_clk_ext.clk)
486 return clk_get_rate(clk->parent);
487
488 div = (jz_clk_reg_read(dclk->reg) & dclk->mask) + 1;
489
490 return clk_get_rate(clk->parent) / div;
491}
492
493static int jz_clk_divided_set_rate(struct clk *clk, unsigned long rate)
494{
495 struct divided_clk *dclk = (struct divided_clk *)clk;
496 int div;
497
498 if (clk->parent == &jz_clk_ext.clk)
499 return -EINVAL;
500
501 div = clk_get_rate(clk->parent) / rate - 1;
502
503 if (div < 0)
504 div = 0;
505 else if (div > dclk->mask)
506 div = dclk->mask;
507
508 jz_clk_reg_write_mask(dclk->reg, div, dclk->mask);
509
510 return 0;
511}
512
513static unsigned long jz_clk_ldclk_round_rate(struct clk *clk, unsigned long rate)
514{
515 int div;
516 unsigned long parent_rate = jz_clk_pll_half_get_rate(clk->parent);
517
518 if (rate > 150000000)
519 return 150000000;
520
521 div = parent_rate / rate;
522 if (div < 1)
523 div = 1;
524 else if (div > 32)
525 div = 32;
526
527 return parent_rate / div;
528}
529
530static int jz_clk_ldclk_set_rate(struct clk *clk, unsigned long rate)
531{
532 int div;
533
534 if (rate > 150000000)
535 return -EINVAL;
536
537 div = jz_clk_pll_half_get_rate(clk->parent) / rate - 1;
538 if (div < 0)
539 div = 0;
540 else if (div > 31)
541 div = 31;
542
543 jz_clk_reg_write_mask(JZ_REG_CLOCK_CTRL, div << JZ_CLOCK_CTRL_LDIV_OFFSET,
544 JZ_CLOCK_CTRL_LDIV_MASK);
545
546 return 0;
547}
548
549static unsigned long jz_clk_ldclk_get_rate(struct clk *clk)
550{
551 int div;
552
553 div = jz_clk_reg_read(JZ_REG_CLOCK_CTRL) & JZ_CLOCK_CTRL_LDIV_MASK;
554 div >>= JZ_CLOCK_CTRL_LDIV_OFFSET;
555
556 return jz_clk_pll_half_get_rate(clk->parent) / (div + 1);
557}
558
559static const struct clk_ops jz_clk_ops_ld = {
560 .set_rate = jz_clk_ldclk_set_rate,
561 .get_rate = jz_clk_ldclk_get_rate,
562 .round_rate = jz_clk_ldclk_round_rate,
563 .enable = jz_clk_enable_gating,
564 .disable = jz_clk_disable_gating,
565 .is_enabled = jz_clk_is_enabled_gating,
566};
567
568static struct clk jz_clk_ld = {
569 .name = "lcd",
570 .gate_bit = JZ_CLOCK_GATE_LCD,
571 .parent = &jz_clk_pll_half,
572 .ops = &jz_clk_ops_ld,
573};
574
575static const struct clk_ops jz_clk_i2s_ops = {
576 .set_rate = jz_clk_divided_set_rate,
577 .get_rate = jz_clk_divided_get_rate,
578 .enable = jz_clk_enable_gating,
579 .disable = jz_clk_disable_gating,
580 .is_enabled = jz_clk_is_enabled_gating,
581 .set_parent = jz_clk_i2s_set_parent,
582};
583
584static const struct clk_ops jz_clk_spi_ops = {
585 .set_rate = jz_clk_divided_set_rate,
586 .get_rate = jz_clk_divided_get_rate,
587 .enable = jz_clk_enable_gating,
588 .disable = jz_clk_disable_gating,
589 .is_enabled = jz_clk_is_enabled_gating,
590 .set_parent = jz_clk_spi_set_parent,
591};
592
593static const struct clk_ops jz_clk_divided_ops = {
594 .set_rate = jz_clk_divided_set_rate,
595 .get_rate = jz_clk_divided_get_rate,
596 .enable = jz_clk_enable_gating,
597 .disable = jz_clk_disable_gating,
598 .is_enabled = jz_clk_is_enabled_gating,
599};
600
601static struct divided_clk jz4740_clock_divided_clks[] = {
602 [0] = {
603 .clk = {
604 .name = "i2s",
605 .parent = &jz_clk_ext.clk,
606 .gate_bit = JZ_CLOCK_GATE_I2S,
607 .ops = &jz_clk_i2s_ops,
608 },
609 .reg = JZ_REG_CLOCK_I2S,
610 .mask = JZ_CLOCK_I2S_DIV_MASK,
611 },
612 [1] = {
613 .clk = {
614 .name = "spi",
615 .parent = &jz_clk_ext.clk,
616 .gate_bit = JZ_CLOCK_GATE_SPI,
617 .ops = &jz_clk_spi_ops,
618 },
619 .reg = JZ_REG_CLOCK_SPI,
620 .mask = JZ_CLOCK_SPI_DIV_MASK,
621 },
622 [2] = {
623 .clk = {
624 .name = "lcd_pclk",
625 .parent = &jz_clk_pll_half,
626 .gate_bit = JZ4740_CLK_NOT_GATED,
627 .ops = &jz_clk_divided_ops,
628 },
629 .reg = JZ_REG_CLOCK_LCD,
630 .mask = JZ_CLOCK_LCD_DIV_MASK,
631 },
632 [3] = {
633 .clk = {
634 .name = "mmc",
635 .parent = &jz_clk_pll_half,
636 .gate_bit = JZ_CLOCK_GATE_MMC,
637 .ops = &jz_clk_divided_ops,
638 },
639 .reg = JZ_REG_CLOCK_MMC,
640 .mask = JZ_CLOCK_MMC_DIV_MASK,
641 },
642 [4] = {
643 .clk = {
644 .name = "uhc",
645 .parent = &jz_clk_pll_half,
646 .gate_bit = JZ_CLOCK_GATE_UHC,
647 .ops = &jz_clk_divided_ops,
648 },
649 .reg = JZ_REG_CLOCK_UHC,
650 .mask = JZ_CLOCK_UHC_DIV_MASK,
651 },
652};
653
654static const struct clk_ops jz_clk_udc_ops = {
655 .set_parent = jz_clk_udc_set_parent,
656 .set_rate = jz_clk_udc_set_rate,
657 .get_rate = jz_clk_udc_get_rate,
658 .enable = jz_clk_udc_enable,
659 .disable = jz_clk_udc_disable,
660 .is_enabled = jz_clk_udc_is_enabled,
661};
662
663static const struct clk_ops jz_clk_simple_ops = {
664 .enable = jz_clk_enable_gating,
665 .disable = jz_clk_disable_gating,
666 .is_enabled = jz_clk_is_enabled_gating,
667};
668
669static struct clk jz4740_clock_simple_clks[] = {
670 [0] = {
671 .name = "udc",
672 .parent = &jz_clk_ext.clk,
673 .ops = &jz_clk_udc_ops,
674 },
675 [1] = {
676 .name = "uart0",
677 .parent = &jz_clk_ext.clk,
678 .gate_bit = JZ_CLOCK_GATE_UART0,
679 .ops = &jz_clk_simple_ops,
680 },
681 [2] = {
682 .name = "uart1",
683 .parent = &jz_clk_ext.clk,
684 .gate_bit = JZ_CLOCK_GATE_UART1,
685 .ops = &jz_clk_simple_ops,
686 },
687 [3] = {
688 .name = "dma",
689 .parent = &jz_clk_high_speed_peripheral.clk,
690 .gate_bit = JZ_CLOCK_GATE_UART0,
691 .ops = &jz_clk_simple_ops,
692 },
693 [4] = {
694 .name = "ipu",
695 .parent = &jz_clk_high_speed_peripheral.clk,
696 .gate_bit = JZ_CLOCK_GATE_IPU,
697 .ops = &jz_clk_simple_ops,
698 },
699 [5] = {
700 .name = "adc",
701 .parent = &jz_clk_ext.clk,
702 .gate_bit = JZ_CLOCK_GATE_ADC,
703 .ops = &jz_clk_simple_ops,
704 },
705 [6] = {
706 .name = "i2c",
707 .parent = &jz_clk_ext.clk,
708 .gate_bit = JZ_CLOCK_GATE_I2C,
709 .ops = &jz_clk_simple_ops,
710 },
711 [7] = {
712 .name = "aic",
713 .parent = &jz_clk_ext.clk,
714 .gate_bit = JZ_CLOCK_GATE_AIC,
715 .ops = &jz_clk_simple_ops,
716 },
717};
718
719static struct static_clk jz_clk_rtc = {
720 .clk = {
721 .name = "rtc",
722 .gate_bit = JZ_CLOCK_GATE_RTC,
723 .ops = &jz_clk_static_ops,
724 },
725 .rate = 32768,
726};
727
728int clk_enable(struct clk *clk)
729{
730 if (!clk->ops->enable)
731 return -EINVAL;
732
733 return clk->ops->enable(clk);
734}
735EXPORT_SYMBOL_GPL(clk_enable);
736
737void clk_disable(struct clk *clk)
738{
739 if (clk->ops->disable)
740 clk->ops->disable(clk);
741}
742EXPORT_SYMBOL_GPL(clk_disable);
743
744int clk_is_enabled(struct clk *clk)
745{
746 if (clk->ops->is_enabled)
747 return clk->ops->is_enabled(clk);
748
749 return 1;
750}
751
752unsigned long clk_get_rate(struct clk *clk)
753{
754 if (clk->ops->get_rate)
755 return clk->ops->get_rate(clk);
756 if (clk->parent)
757 return clk_get_rate(clk->parent);
758
759 return -EINVAL;
760}
761EXPORT_SYMBOL_GPL(clk_get_rate);
762
763int clk_set_rate(struct clk *clk, unsigned long rate)
764{
765 if (!clk->ops->set_rate)
766 return -EINVAL;
767 return clk->ops->set_rate(clk, rate);
768}
769EXPORT_SYMBOL_GPL(clk_set_rate);
770
771long clk_round_rate(struct clk *clk, unsigned long rate)
772{
773 if (clk->ops->round_rate)
774 return clk->ops->round_rate(clk, rate);
775
776 return -EINVAL;
777}
778EXPORT_SYMBOL_GPL(clk_round_rate);
779
780int clk_set_parent(struct clk *clk, struct clk *parent)
781{
782 int ret;
783 int enabled;
784
785 if (!clk->ops->set_parent)
786 return -EINVAL;
787
788 enabled = clk_is_enabled(clk);
789 if (enabled)
790 clk_disable(clk);
791 ret = clk->ops->set_parent(clk, parent);
792 if (enabled)
793 clk_enable(clk);
794
795 jz4740_clock_debugfs_update_parent(clk);
796
797 return ret;
798}
799EXPORT_SYMBOL_GPL(clk_set_parent);
800
801struct clk *clk_get(struct device *dev, const char *name)
802{
803 struct clk *clk;
804
805 list_for_each_entry(clk, &jz_clocks, list) {
806 if (strcmp(clk->name, name) == 0)
807 return clk;
808 }
809 return ERR_PTR(-ENXIO);
810}
811EXPORT_SYMBOL_GPL(clk_get);
812
813void clk_put(struct clk *clk)
814{
815}
816EXPORT_SYMBOL_GPL(clk_put);
817
818static inline void clk_add(struct clk *clk)
819{
820 list_add_tail(&clk->list, &jz_clocks);
821
822 jz4740_clock_debugfs_add_clk(clk);
823}
824
825static void clk_register_clks(void)
826{
827 size_t i;
828
829 clk_add(&jz_clk_ext.clk);
830 clk_add(&jz_clk_pll);
831 clk_add(&jz_clk_pll_half);
832 clk_add(&jz_clk_cpu.clk);
833 clk_add(&jz_clk_high_speed_peripheral.clk);
834 clk_add(&jz_clk_low_speed_peripheral.clk);
835 clk_add(&jz_clk_ko);
836 clk_add(&jz_clk_ld);
837 clk_add(&jz_clk_rtc.clk);
838
839 for (i = 0; i < ARRAY_SIZE(jz4740_clock_divided_clks); ++i)
840 clk_add(&jz4740_clock_divided_clks[i].clk);
841
842 for (i = 0; i < ARRAY_SIZE(jz4740_clock_simple_clks); ++i)
843 clk_add(&jz4740_clock_simple_clks[i]);
844}
845
846void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode)
847{
848 switch (mode) {
849 case JZ4740_WAIT_MODE_IDLE:
850 jz_clk_reg_clear_bits(JZ_REG_CLOCK_LOW_POWER, JZ_CLOCK_LOW_POWER_MODE_SLEEP);
851 break;
852 case JZ4740_WAIT_MODE_SLEEP:
853 jz_clk_reg_set_bits(JZ_REG_CLOCK_LOW_POWER, JZ_CLOCK_LOW_POWER_MODE_SLEEP);
854 break;
855 }
856}
857
858void jz4740_clock_udc_disable_auto_suspend(void)
859{
860 jz_clk_reg_clear_bits(JZ_REG_CLOCK_GATE, JZ_CLOCK_GATE_UDC);
861}
862EXPORT_SYMBOL_GPL(jz4740_clock_udc_disable_auto_suspend);
863
864void jz4740_clock_udc_enable_auto_suspend(void)
865{
866 jz_clk_reg_set_bits(JZ_REG_CLOCK_GATE, JZ_CLOCK_GATE_UDC);
867}
868EXPORT_SYMBOL_GPL(jz4740_clock_udc_enable_auto_suspend);
869
870void jz4740_clock_suspend(void)
871{
872 jz_clk_reg_set_bits(JZ_REG_CLOCK_GATE,
873 JZ_CLOCK_GATE_TCU | JZ_CLOCK_GATE_DMAC | JZ_CLOCK_GATE_UART0);
874
875 jz_clk_reg_clear_bits(JZ_REG_CLOCK_PLL, JZ_CLOCK_PLL_ENABLED);
876}
877
878void jz4740_clock_resume(void)
879{
880 uint32_t pll;
881
882 jz_clk_reg_set_bits(JZ_REG_CLOCK_PLL, JZ_CLOCK_PLL_ENABLED);
883
884 do {
885 pll = jz_clk_reg_read(JZ_REG_CLOCK_PLL);
886 } while (!(pll & JZ_CLOCK_PLL_STABLE));
887
888 jz_clk_reg_clear_bits(JZ_REG_CLOCK_GATE,
889 JZ_CLOCK_GATE_TCU | JZ_CLOCK_GATE_DMAC | JZ_CLOCK_GATE_UART0);
890}
891
892static int jz4740_clock_init(void)
893{
894 uint32_t val;
895
896 jz_clock_base = ioremap(JZ4740_CPM_BASE_ADDR, 0x100);
897 if (!jz_clock_base)
898 return -EBUSY;
899
900 spin_lock_init(&jz_clock_lock);
901
902 jz_clk_ext.rate = jz4740_clock_bdata.ext_rate;
903 jz_clk_rtc.rate = jz4740_clock_bdata.rtc_rate;
904
905 val = jz_clk_reg_read(JZ_REG_CLOCK_SPI);
906
907 if (val & JZ_CLOCK_SPI_SRC_PLL)
908 jz4740_clock_divided_clks[1].clk.parent = &jz_clk_pll_half;
909
910 val = jz_clk_reg_read(JZ_REG_CLOCK_CTRL);
911
912 if (val & JZ_CLOCK_CTRL_I2S_SRC_PLL)
913 jz4740_clock_divided_clks[0].clk.parent = &jz_clk_pll_half;
914
915 if (val & JZ_CLOCK_CTRL_UDC_SRC_PLL)
916 jz4740_clock_simple_clks[0].parent = &jz_clk_pll_half;
917
918 jz4740_clock_debugfs_init();
919
920 clk_register_clks();
921
922 return 0;
923}
924arch_initcall(jz4740_clock_init);
diff --git a/arch/mips/jz4740/clock.h b/arch/mips/jz4740/clock.h
new file mode 100644
index 000000000000..5d07499d7461
--- /dev/null
+++ b/arch/mips/jz4740/clock.h
@@ -0,0 +1,76 @@
1/*
2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4740 SoC clock support
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#ifndef __MIPS_JZ4740_CLOCK_H__
17#define __MIPS_JZ4740_CLOCK_H__
18
19#include <linux/list.h>
20
21struct jz4740_clock_board_data {
22 unsigned long ext_rate;
23 unsigned long rtc_rate;
24};
25
26extern struct jz4740_clock_board_data jz4740_clock_bdata;
27
28void jz4740_clock_suspend(void);
29void jz4740_clock_resume(void);
30
31struct clk;
32
33struct clk_ops {
34 unsigned long (*get_rate)(struct clk *clk);
35 unsigned long (*round_rate)(struct clk *clk, unsigned long rate);
36 int (*set_rate)(struct clk *clk, unsigned long rate);
37 int (*enable)(struct clk *clk);
38 int (*disable)(struct clk *clk);
39 int (*is_enabled)(struct clk *clk);
40
41 int (*set_parent)(struct clk *clk, struct clk *parent);
42
43};
44
45struct clk {
46 const char *name;
47 struct clk *parent;
48
49 uint32_t gate_bit;
50
51 const struct clk_ops *ops;
52
53 struct list_head list;
54
55#ifdef CONFIG_DEBUG_FS
56 struct dentry *debugfs_entry;
57 struct dentry *debugfs_parent_entry;
58#endif
59
60};
61
62#define JZ4740_CLK_NOT_GATED ((uint32_t)-1)
63
64int clk_is_enabled(struct clk *clk);
65
66#ifdef CONFIG_DEBUG_FS
67void jz4740_clock_debugfs_init(void);
68void jz4740_clock_debugfs_add_clk(struct clk *clk);
69void jz4740_clock_debugfs_update_parent(struct clk *clk);
70#else
71static inline void jz4740_clock_debugfs_init(void) {};
72static inline void jz4740_clock_debugfs_add_clk(struct clk *clk) {};
73static inline void jz4740_clock_debugfs_update_parent(struct clk *clk) {};
74#endif
75
76#endif
diff --git a/arch/mips/jz4740/dma.c b/arch/mips/jz4740/dma.c
new file mode 100644
index 000000000000..5ebe75a68350
--- /dev/null
+++ b/arch/mips/jz4740/dma.c
@@ -0,0 +1,289 @@
1/*
2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4740 SoC DMA support
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/spinlock.h>
19#include <linux/interrupt.h>
20
21#include <linux/dma-mapping.h>
22#include <asm/mach-jz4740/dma.h>
23#include <asm/mach-jz4740/base.h>
24
25#define JZ_REG_DMA_SRC_ADDR(x) (0x00 + (x) * 0x20)
26#define JZ_REG_DMA_DST_ADDR(x) (0x04 + (x) * 0x20)
27#define JZ_REG_DMA_TRANSFER_COUNT(x) (0x08 + (x) * 0x20)
28#define JZ_REG_DMA_REQ_TYPE(x) (0x0C + (x) * 0x20)
29#define JZ_REG_DMA_STATUS_CTRL(x) (0x10 + (x) * 0x20)
30#define JZ_REG_DMA_CMD(x) (0x14 + (x) * 0x20)
31#define JZ_REG_DMA_DESC_ADDR(x) (0x18 + (x) * 0x20)
32
33#define JZ_REG_DMA_CTRL 0x300
34#define JZ_REG_DMA_IRQ 0x304
35#define JZ_REG_DMA_DOORBELL 0x308
36#define JZ_REG_DMA_DOORBELL_SET 0x30C
37
38#define JZ_DMA_STATUS_CTRL_NO_DESC BIT(31)
39#define JZ_DMA_STATUS_CTRL_DESC_INV BIT(6)
40#define JZ_DMA_STATUS_CTRL_ADDR_ERR BIT(4)
41#define JZ_DMA_STATUS_CTRL_TRANSFER_DONE BIT(3)
42#define JZ_DMA_STATUS_CTRL_HALT BIT(2)
43#define JZ_DMA_STATUS_CTRL_COUNT_TERMINATE BIT(1)
44#define JZ_DMA_STATUS_CTRL_ENABLE BIT(0)
45
46#define JZ_DMA_CMD_SRC_INC BIT(23)
47#define JZ_DMA_CMD_DST_INC BIT(22)
48#define JZ_DMA_CMD_RDIL_MASK (0xf << 16)
49#define JZ_DMA_CMD_SRC_WIDTH_MASK (0x3 << 14)
50#define JZ_DMA_CMD_DST_WIDTH_MASK (0x3 << 12)
51#define JZ_DMA_CMD_INTERVAL_LENGTH_MASK (0x7 << 8)
52#define JZ_DMA_CMD_BLOCK_MODE BIT(7)
53#define JZ_DMA_CMD_DESC_VALID BIT(4)
54#define JZ_DMA_CMD_DESC_VALID_MODE BIT(3)
55#define JZ_DMA_CMD_VALID_IRQ_ENABLE BIT(2)
56#define JZ_DMA_CMD_TRANSFER_IRQ_ENABLE BIT(1)
57#define JZ_DMA_CMD_LINK_ENABLE BIT(0)
58
59#define JZ_DMA_CMD_FLAGS_OFFSET 22
60#define JZ_DMA_CMD_RDIL_OFFSET 16
61#define JZ_DMA_CMD_SRC_WIDTH_OFFSET 14
62#define JZ_DMA_CMD_DST_WIDTH_OFFSET 12
63#define JZ_DMA_CMD_TRANSFER_SIZE_OFFSET 8
64#define JZ_DMA_CMD_MODE_OFFSET 7
65
66#define JZ_DMA_CTRL_PRIORITY_MASK (0x3 << 8)
67#define JZ_DMA_CTRL_HALT BIT(3)
68#define JZ_DMA_CTRL_ADDRESS_ERROR BIT(2)
69#define JZ_DMA_CTRL_ENABLE BIT(0)
70
71
72static void __iomem *jz4740_dma_base;
73static spinlock_t jz4740_dma_lock;
74
75static inline uint32_t jz4740_dma_read(size_t reg)
76{
77 return readl(jz4740_dma_base + reg);
78}
79
80static inline void jz4740_dma_write(size_t reg, uint32_t val)
81{
82 writel(val, jz4740_dma_base + reg);
83}
84
85static inline void jz4740_dma_write_mask(size_t reg, uint32_t val, uint32_t mask)
86{
87 uint32_t val2;
88 val2 = jz4740_dma_read(reg);
89 val2 &= ~mask;
90 val2 |= val;
91 jz4740_dma_write(reg, val2);
92}
93
94struct jz4740_dma_chan {
95 unsigned int id;
96 void *dev;
97 const char *name;
98
99 enum jz4740_dma_flags flags;
100 uint32_t transfer_shift;
101
102 jz4740_dma_complete_callback_t complete_cb;
103
104 unsigned used:1;
105};
106
107#define JZ4740_DMA_CHANNEL(_id) { .id = _id }
108
109struct jz4740_dma_chan jz4740_dma_channels[] = {
110 JZ4740_DMA_CHANNEL(0),
111 JZ4740_DMA_CHANNEL(1),
112 JZ4740_DMA_CHANNEL(2),
113 JZ4740_DMA_CHANNEL(3),
114 JZ4740_DMA_CHANNEL(4),
115 JZ4740_DMA_CHANNEL(5),
116};
117
118struct jz4740_dma_chan *jz4740_dma_request(void *dev, const char *name)
119{
120 unsigned int i;
121 struct jz4740_dma_chan *dma = NULL;
122
123 spin_lock(&jz4740_dma_lock);
124
125 for (i = 0; i < ARRAY_SIZE(jz4740_dma_channels); ++i) {
126 if (!jz4740_dma_channels[i].used) {
127 dma = &jz4740_dma_channels[i];
128 dma->used = 1;
129 break;
130 }
131 }
132
133 spin_unlock(&jz4740_dma_lock);
134
135 if (!dma)
136 return NULL;
137
138 dma->dev = dev;
139 dma->name = name;
140
141 return dma;
142}
143EXPORT_SYMBOL_GPL(jz4740_dma_request);
144
145void jz4740_dma_configure(struct jz4740_dma_chan *dma,
146 const struct jz4740_dma_config *config)
147{
148 uint32_t cmd;
149
150 switch (config->transfer_size) {
151 case JZ4740_DMA_TRANSFER_SIZE_2BYTE:
152 dma->transfer_shift = 1;
153 break;
154 case JZ4740_DMA_TRANSFER_SIZE_4BYTE:
155 dma->transfer_shift = 2;
156 break;
157 case JZ4740_DMA_TRANSFER_SIZE_16BYTE:
158 dma->transfer_shift = 4;
159 break;
160 case JZ4740_DMA_TRANSFER_SIZE_32BYTE:
161 dma->transfer_shift = 5;
162 break;
163 default:
164 dma->transfer_shift = 0;
165 break;
166 }
167
168 cmd = config->flags << JZ_DMA_CMD_FLAGS_OFFSET;
169 cmd |= config->src_width << JZ_DMA_CMD_SRC_WIDTH_OFFSET;
170 cmd |= config->dst_width << JZ_DMA_CMD_DST_WIDTH_OFFSET;
171 cmd |= config->transfer_size << JZ_DMA_CMD_TRANSFER_SIZE_OFFSET;
172 cmd |= config->mode << JZ_DMA_CMD_MODE_OFFSET;
173 cmd |= JZ_DMA_CMD_TRANSFER_IRQ_ENABLE;
174
175 jz4740_dma_write(JZ_REG_DMA_CMD(dma->id), cmd);
176 jz4740_dma_write(JZ_REG_DMA_STATUS_CTRL(dma->id), 0);
177 jz4740_dma_write(JZ_REG_DMA_REQ_TYPE(dma->id), config->request_type);
178}
179EXPORT_SYMBOL_GPL(jz4740_dma_configure);
180
181void jz4740_dma_set_src_addr(struct jz4740_dma_chan *dma, dma_addr_t src)
182{
183 jz4740_dma_write(JZ_REG_DMA_SRC_ADDR(dma->id), src);
184}
185EXPORT_SYMBOL_GPL(jz4740_dma_set_src_addr);
186
187void jz4740_dma_set_dst_addr(struct jz4740_dma_chan *dma, dma_addr_t dst)
188{
189 jz4740_dma_write(JZ_REG_DMA_DST_ADDR(dma->id), dst);
190}
191EXPORT_SYMBOL_GPL(jz4740_dma_set_dst_addr);
192
193void jz4740_dma_set_transfer_count(struct jz4740_dma_chan *dma, uint32_t count)
194{
195 count >>= dma->transfer_shift;
196 jz4740_dma_write(JZ_REG_DMA_TRANSFER_COUNT(dma->id), count);
197}
198EXPORT_SYMBOL_GPL(jz4740_dma_set_transfer_count);
199
200void jz4740_dma_set_complete_cb(struct jz4740_dma_chan *dma,
201 jz4740_dma_complete_callback_t cb)
202{
203 dma->complete_cb = cb;
204}
205EXPORT_SYMBOL_GPL(jz4740_dma_set_complete_cb);
206
207void jz4740_dma_free(struct jz4740_dma_chan *dma)
208{
209 dma->dev = NULL;
210 dma->complete_cb = NULL;
211 dma->used = 0;
212}
213EXPORT_SYMBOL_GPL(jz4740_dma_free);
214
215void jz4740_dma_enable(struct jz4740_dma_chan *dma)
216{
217 jz4740_dma_write_mask(JZ_REG_DMA_STATUS_CTRL(dma->id),
218 JZ_DMA_STATUS_CTRL_NO_DESC | JZ_DMA_STATUS_CTRL_ENABLE,
219 JZ_DMA_STATUS_CTRL_HALT | JZ_DMA_STATUS_CTRL_NO_DESC |
220 JZ_DMA_STATUS_CTRL_ENABLE);
221
222 jz4740_dma_write_mask(JZ_REG_DMA_CTRL,
223 JZ_DMA_CTRL_ENABLE,
224 JZ_DMA_CTRL_HALT | JZ_DMA_CTRL_ENABLE);
225}
226EXPORT_SYMBOL_GPL(jz4740_dma_enable);
227
228void jz4740_dma_disable(struct jz4740_dma_chan *dma)
229{
230 jz4740_dma_write_mask(JZ_REG_DMA_STATUS_CTRL(dma->id), 0,
231 JZ_DMA_STATUS_CTRL_ENABLE);
232}
233EXPORT_SYMBOL_GPL(jz4740_dma_disable);
234
235uint32_t jz4740_dma_get_residue(const struct jz4740_dma_chan *dma)
236{
237 uint32_t residue;
238 residue = jz4740_dma_read(JZ_REG_DMA_TRANSFER_COUNT(dma->id));
239 return residue << dma->transfer_shift;
240}
241EXPORT_SYMBOL_GPL(jz4740_dma_get_residue);
242
243static void jz4740_dma_chan_irq(struct jz4740_dma_chan *dma)
244{
245 uint32_t status;
246
247 status = jz4740_dma_read(JZ_REG_DMA_STATUS_CTRL(dma->id));
248
249 jz4740_dma_write_mask(JZ_REG_DMA_STATUS_CTRL(dma->id), 0,
250 JZ_DMA_STATUS_CTRL_ENABLE | JZ_DMA_STATUS_CTRL_TRANSFER_DONE);
251
252 if (dma->complete_cb)
253 dma->complete_cb(dma, 0, dma->dev);
254}
255
256static irqreturn_t jz4740_dma_irq(int irq, void *dev_id)
257{
258 uint32_t irq_status;
259 unsigned int i;
260
261 irq_status = readl(jz4740_dma_base + JZ_REG_DMA_IRQ);
262
263 for (i = 0; i < 6; ++i) {
264 if (irq_status & (1 << i))
265 jz4740_dma_chan_irq(&jz4740_dma_channels[i]);
266 }
267
268 return IRQ_HANDLED;
269}
270
271static int jz4740_dma_init(void)
272{
273 unsigned int ret;
274
275 jz4740_dma_base = ioremap(JZ4740_DMAC_BASE_ADDR, 0x400);
276
277 if (!jz4740_dma_base)
278 return -EBUSY;
279
280 spin_lock_init(&jz4740_dma_lock);
281
282 ret = request_irq(JZ4740_IRQ_DMAC, jz4740_dma_irq, 0, "DMA", NULL);
283
284 if (ret)
285 printk(KERN_ERR "JZ4740 DMA: Failed to request irq: %d\n", ret);
286
287 return ret;
288}
289arch_initcall(jz4740_dma_init);
diff --git a/arch/mips/jz4740/gpio.c b/arch/mips/jz4740/gpio.c
new file mode 100644
index 000000000000..38f60f35156c
--- /dev/null
+++ b/arch/mips/jz4740/gpio.c
@@ -0,0 +1,604 @@
1/*
2 * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4740 platform GPIO support
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/init.h>
19
20#include <linux/spinlock.h>
21#include <linux/sysdev.h>
22#include <linux/io.h>
23#include <linux/gpio.h>
24#include <linux/delay.h>
25#include <linux/interrupt.h>
26#include <linux/bitops.h>
27
28#include <linux/debugfs.h>
29#include <linux/seq_file.h>
30
31#include <asm/mach-jz4740/base.h>
32
33#define JZ4740_GPIO_BASE_A (32*0)
34#define JZ4740_GPIO_BASE_B (32*1)
35#define JZ4740_GPIO_BASE_C (32*2)
36#define JZ4740_GPIO_BASE_D (32*3)
37
38#define JZ4740_GPIO_NUM_A 32
39#define JZ4740_GPIO_NUM_B 32
40#define JZ4740_GPIO_NUM_C 31
41#define JZ4740_GPIO_NUM_D 32
42
43#define JZ4740_IRQ_GPIO_BASE_A (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_A)
44#define JZ4740_IRQ_GPIO_BASE_B (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_B)
45#define JZ4740_IRQ_GPIO_BASE_C (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_C)
46#define JZ4740_IRQ_GPIO_BASE_D (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_D)
47
48#define JZ_REG_GPIO_PIN 0x00
49#define JZ_REG_GPIO_DATA 0x10
50#define JZ_REG_GPIO_DATA_SET 0x14
51#define JZ_REG_GPIO_DATA_CLEAR 0x18
52#define JZ_REG_GPIO_MASK 0x20
53#define JZ_REG_GPIO_MASK_SET 0x24
54#define JZ_REG_GPIO_MASK_CLEAR 0x28
55#define JZ_REG_GPIO_PULL 0x30
56#define JZ_REG_GPIO_PULL_SET 0x34
57#define JZ_REG_GPIO_PULL_CLEAR 0x38
58#define JZ_REG_GPIO_FUNC 0x40
59#define JZ_REG_GPIO_FUNC_SET 0x44
60#define JZ_REG_GPIO_FUNC_CLEAR 0x48
61#define JZ_REG_GPIO_SELECT 0x50
62#define JZ_REG_GPIO_SELECT_SET 0x54
63#define JZ_REG_GPIO_SELECT_CLEAR 0x58
64#define JZ_REG_GPIO_DIRECTION 0x60
65#define JZ_REG_GPIO_DIRECTION_SET 0x64
66#define JZ_REG_GPIO_DIRECTION_CLEAR 0x68
67#define JZ_REG_GPIO_TRIGGER 0x70
68#define JZ_REG_GPIO_TRIGGER_SET 0x74
69#define JZ_REG_GPIO_TRIGGER_CLEAR 0x78
70#define JZ_REG_GPIO_FLAG 0x80
71#define JZ_REG_GPIO_FLAG_CLEAR 0x14
72
73#define GPIO_TO_BIT(gpio) BIT(gpio & 0x1f)
74#define GPIO_TO_REG(gpio, reg) (gpio_to_jz_gpio_chip(gpio)->base + (reg))
75#define CHIP_TO_REG(chip, reg) (gpio_chip_to_jz_gpio_chip(chip)->base + (reg))
76
77struct jz_gpio_chip {
78 unsigned int irq;
79 unsigned int irq_base;
80 uint32_t wakeup;
81 uint32_t suspend_mask;
82 uint32_t edge_trigger_both;
83
84 void __iomem *base;
85
86 spinlock_t lock;
87
88 struct gpio_chip gpio_chip;
89 struct irq_chip irq_chip;
90 struct sys_device sysdev;
91};
92
93static struct jz_gpio_chip jz4740_gpio_chips[];
94
95static inline struct jz_gpio_chip *gpio_to_jz_gpio_chip(unsigned int gpio)
96{
97 return &jz4740_gpio_chips[gpio >> 5];
98}
99
100static inline struct jz_gpio_chip *gpio_chip_to_jz_gpio_chip(struct gpio_chip *gpio_chip)
101{
102 return container_of(gpio_chip, struct jz_gpio_chip, gpio_chip);
103}
104
105static inline struct jz_gpio_chip *irq_to_jz_gpio_chip(unsigned int irq)
106{
107 return get_irq_chip_data(irq);
108}
109
110static inline void jz_gpio_write_bit(unsigned int gpio, unsigned int reg)
111{
112 writel(GPIO_TO_BIT(gpio), GPIO_TO_REG(gpio, reg));
113}
114
115int jz_gpio_set_function(int gpio, enum jz_gpio_function function)
116{
117 if (function == JZ_GPIO_FUNC_NONE) {
118 jz_gpio_write_bit(gpio, JZ_REG_GPIO_FUNC_CLEAR);
119 jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_CLEAR);
120 jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_CLEAR);
121 } else {
122 jz_gpio_write_bit(gpio, JZ_REG_GPIO_FUNC_SET);
123 jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_CLEAR);
124 switch (function) {
125 case JZ_GPIO_FUNC1:
126 jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_CLEAR);
127 break;
128 case JZ_GPIO_FUNC3:
129 jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_SET);
130 case JZ_GPIO_FUNC2: /* Falltrough */
131 jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_SET);
132 break;
133 default:
134 BUG();
135 break;
136 }
137 }
138
139 return 0;
140}
141EXPORT_SYMBOL_GPL(jz_gpio_set_function);
142
143int jz_gpio_bulk_request(const struct jz_gpio_bulk_request *request, size_t num)
144{
145 size_t i;
146 int ret;
147
148 for (i = 0; i < num; ++i, ++request) {
149 ret = gpio_request(request->gpio, request->name);
150 if (ret)
151 goto err;
152 jz_gpio_set_function(request->gpio, request->function);
153 }
154
155 return 0;
156
157err:
158 for (--request; i > 0; --i, --request) {
159 gpio_free(request->gpio);
160 jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE);
161 }
162
163 return ret;
164}
165EXPORT_SYMBOL_GPL(jz_gpio_bulk_request);
166
167void jz_gpio_bulk_free(const struct jz_gpio_bulk_request *request, size_t num)
168{
169 size_t i;
170
171 for (i = 0; i < num; ++i, ++request) {
172 gpio_free(request->gpio);
173 jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE);
174 }
175
176}
177EXPORT_SYMBOL_GPL(jz_gpio_bulk_free);
178
179void jz_gpio_bulk_suspend(const struct jz_gpio_bulk_request *request, size_t num)
180{
181 size_t i;
182
183 for (i = 0; i < num; ++i, ++request) {
184 jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE);
185 jz_gpio_write_bit(request->gpio, JZ_REG_GPIO_DIRECTION_CLEAR);
186 jz_gpio_write_bit(request->gpio, JZ_REG_GPIO_PULL_SET);
187 }
188}
189EXPORT_SYMBOL_GPL(jz_gpio_bulk_suspend);
190
191void jz_gpio_bulk_resume(const struct jz_gpio_bulk_request *request, size_t num)
192{
193 size_t i;
194
195 for (i = 0; i < num; ++i, ++request)
196 jz_gpio_set_function(request->gpio, request->function);
197}
198EXPORT_SYMBOL_GPL(jz_gpio_bulk_resume);
199
200void jz_gpio_enable_pullup(unsigned gpio)
201{
202 jz_gpio_write_bit(gpio, JZ_REG_GPIO_PULL_CLEAR);
203}
204EXPORT_SYMBOL_GPL(jz_gpio_enable_pullup);
205
206void jz_gpio_disable_pullup(unsigned gpio)
207{
208 jz_gpio_write_bit(gpio, JZ_REG_GPIO_PULL_SET);
209}
210EXPORT_SYMBOL_GPL(jz_gpio_disable_pullup);
211
212static int jz_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
213{
214 return !!(readl(CHIP_TO_REG(chip, JZ_REG_GPIO_PIN)) & BIT(gpio));
215}
216
217static void jz_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value)
218{
219 uint32_t __iomem *reg = CHIP_TO_REG(chip, JZ_REG_GPIO_DATA_SET);
220 reg += !value;
221 writel(BIT(gpio), reg);
222}
223
224static int jz_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
225 int value)
226{
227 writel(BIT(gpio), CHIP_TO_REG(chip, JZ_REG_GPIO_DIRECTION_SET));
228 jz_gpio_set_value(chip, gpio, value);
229
230 return 0;
231}
232
233static int jz_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
234{
235 writel(BIT(gpio), CHIP_TO_REG(chip, JZ_REG_GPIO_DIRECTION_CLEAR));
236
237 return 0;
238}
239
240int jz_gpio_port_direction_input(int port, uint32_t mask)
241{
242 writel(mask, GPIO_TO_REG(port, JZ_REG_GPIO_DIRECTION_CLEAR));
243
244 return 0;
245}
246EXPORT_SYMBOL(jz_gpio_port_direction_input);
247
248int jz_gpio_port_direction_output(int port, uint32_t mask)
249{
250 writel(mask, GPIO_TO_REG(port, JZ_REG_GPIO_DIRECTION_SET));
251
252 return 0;
253}
254EXPORT_SYMBOL(jz_gpio_port_direction_output);
255
256void jz_gpio_port_set_value(int port, uint32_t value, uint32_t mask)
257{
258 writel(~value & mask, GPIO_TO_REG(port, JZ_REG_GPIO_DATA_CLEAR));
259 writel(value & mask, GPIO_TO_REG(port, JZ_REG_GPIO_DATA_SET));
260}
261EXPORT_SYMBOL(jz_gpio_port_set_value);
262
263uint32_t jz_gpio_port_get_value(int port, uint32_t mask)
264{
265 uint32_t value = readl(GPIO_TO_REG(port, JZ_REG_GPIO_PIN));
266
267 return value & mask;
268}
269EXPORT_SYMBOL(jz_gpio_port_get_value);
270
271int gpio_to_irq(unsigned gpio)
272{
273 return JZ4740_IRQ_GPIO(0) + gpio;
274}
275EXPORT_SYMBOL_GPL(gpio_to_irq);
276
277int irq_to_gpio(unsigned irq)
278{
279 return irq - JZ4740_IRQ_GPIO(0);
280}
281EXPORT_SYMBOL_GPL(irq_to_gpio);
282
283#define IRQ_TO_BIT(irq) BIT(irq_to_gpio(irq) & 0x1f)
284
285static void jz_gpio_check_trigger_both(struct jz_gpio_chip *chip, unsigned int irq)
286{
287 uint32_t value;
288 void __iomem *reg;
289 uint32_t mask = IRQ_TO_BIT(irq);
290
291 if (!(chip->edge_trigger_both & mask))
292 return;
293
294 reg = chip->base;
295
296 value = readl(chip->base + JZ_REG_GPIO_PIN);
297 if (value & mask)
298 reg += JZ_REG_GPIO_DIRECTION_CLEAR;
299 else
300 reg += JZ_REG_GPIO_DIRECTION_SET;
301
302 writel(mask, reg);
303}
304
305static void jz_gpio_irq_demux_handler(unsigned int irq, struct irq_desc *desc)
306{
307 uint32_t flag;
308 unsigned int gpio_irq;
309 unsigned int gpio_bank;
310 struct jz_gpio_chip *chip = get_irq_desc_data(desc);
311
312 gpio_bank = JZ4740_IRQ_GPIO0 - irq;
313
314 flag = readl(chip->base + JZ_REG_GPIO_FLAG);
315
316 if (!flag)
317 return;
318
319 gpio_irq = __fls(flag);
320
321 jz_gpio_check_trigger_both(chip, irq);
322
323 gpio_irq += (gpio_bank << 5) + JZ4740_IRQ_GPIO(0);
324
325 generic_handle_irq(gpio_irq);
326};
327
328static inline void jz_gpio_set_irq_bit(unsigned int irq, unsigned int reg)
329{
330 struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(irq);
331 writel(IRQ_TO_BIT(irq), chip->base + reg);
332}
333
334static void jz_gpio_irq_mask(unsigned int irq)
335{
336 jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_MASK_SET);
337};
338
339static void jz_gpio_irq_unmask(unsigned int irq)
340{
341 struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(irq);
342
343 jz_gpio_check_trigger_both(chip, irq);
344
345 jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_MASK_CLEAR);
346};
347
348/* TODO: Check if function is gpio */
349static unsigned int jz_gpio_irq_startup(unsigned int irq)
350{
351 struct irq_desc *desc = irq_to_desc(irq);
352
353 jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_SELECT_SET);
354
355 desc->status &= ~IRQ_MASKED;
356 jz_gpio_irq_unmask(irq);
357
358 return 0;
359}
360
361static void jz_gpio_irq_shutdown(unsigned int irq)
362{
363 struct irq_desc *desc = irq_to_desc(irq);
364
365 jz_gpio_irq_mask(irq);
366 desc->status |= IRQ_MASKED;
367
368 /* Set direction to input */
369 jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_DIRECTION_CLEAR);
370 jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_SELECT_CLEAR);
371}
372
373static void jz_gpio_irq_ack(unsigned int irq)
374{
375 jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_FLAG_CLEAR);
376};
377
378static int jz_gpio_irq_set_type(unsigned int irq, unsigned int flow_type)
379{
380 struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(irq);
381 struct irq_desc *desc = irq_to_desc(irq);
382
383 jz_gpio_irq_mask(irq);
384
385 if (flow_type == IRQ_TYPE_EDGE_BOTH) {
386 uint32_t value = readl(chip->base + JZ_REG_GPIO_PIN);
387 if (value & IRQ_TO_BIT(irq))
388 flow_type = IRQ_TYPE_EDGE_FALLING;
389 else
390 flow_type = IRQ_TYPE_EDGE_RISING;
391 chip->edge_trigger_both |= IRQ_TO_BIT(irq);
392 } else {
393 chip->edge_trigger_both &= ~IRQ_TO_BIT(irq);
394 }
395
396 switch (flow_type) {
397 case IRQ_TYPE_EDGE_RISING:
398 jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_DIRECTION_SET);
399 jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_TRIGGER_SET);
400 break;
401 case IRQ_TYPE_EDGE_FALLING:
402 jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_DIRECTION_CLEAR);
403 jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_TRIGGER_SET);
404 break;
405 case IRQ_TYPE_LEVEL_HIGH:
406 jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_DIRECTION_SET);
407 jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_TRIGGER_CLEAR);
408 break;
409 case IRQ_TYPE_LEVEL_LOW:
410 jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_DIRECTION_CLEAR);
411 jz_gpio_set_irq_bit(irq, JZ_REG_GPIO_TRIGGER_CLEAR);
412 break;
413 default:
414 return -EINVAL;
415 }
416
417 if (!(desc->status & IRQ_MASKED))
418 jz_gpio_irq_unmask(irq);
419
420 return 0;
421}
422
423static int jz_gpio_irq_set_wake(unsigned int irq, unsigned int on)
424{
425 struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(irq);
426 spin_lock(&chip->lock);
427 if (on)
428 chip->wakeup |= IRQ_TO_BIT(irq);
429 else
430 chip->wakeup &= ~IRQ_TO_BIT(irq);
431 spin_unlock(&chip->lock);
432
433 set_irq_wake(chip->irq, on);
434 return 0;
435}
436
437/*
438 * This lock class tells lockdep that GPIO irqs are in a different
439 * category than their parents, so it won't report false recursion.
440 */
441static struct lock_class_key gpio_lock_class;
442
443#define JZ4740_GPIO_CHIP(_bank) { \
444 .irq_base = JZ4740_IRQ_GPIO_BASE_ ## _bank, \
445 .gpio_chip = { \
446 .label = "Bank " # _bank, \
447 .owner = THIS_MODULE, \
448 .set = jz_gpio_set_value, \
449 .get = jz_gpio_get_value, \
450 .direction_output = jz_gpio_direction_output, \
451 .direction_input = jz_gpio_direction_input, \
452 .base = JZ4740_GPIO_BASE_ ## _bank, \
453 .ngpio = JZ4740_GPIO_NUM_ ## _bank, \
454 }, \
455 .irq_chip = { \
456 .name = "GPIO Bank " # _bank, \
457 .mask = jz_gpio_irq_mask, \
458 .unmask = jz_gpio_irq_unmask, \
459 .ack = jz_gpio_irq_ack, \
460 .startup = jz_gpio_irq_startup, \
461 .shutdown = jz_gpio_irq_shutdown, \
462 .set_type = jz_gpio_irq_set_type, \
463 .set_wake = jz_gpio_irq_set_wake, \
464 }, \
465}
466
467static struct jz_gpio_chip jz4740_gpio_chips[] = {
468 JZ4740_GPIO_CHIP(A),
469 JZ4740_GPIO_CHIP(B),
470 JZ4740_GPIO_CHIP(C),
471 JZ4740_GPIO_CHIP(D),
472};
473
474static inline struct jz_gpio_chip *sysdev_to_chip(struct sys_device *dev)
475{
476 return container_of(dev, struct jz_gpio_chip, sysdev);
477}
478
479static int jz4740_gpio_suspend(struct sys_device *dev, pm_message_t state)
480{
481 struct jz_gpio_chip *chip = sysdev_to_chip(dev);
482
483 chip->suspend_mask = readl(chip->base + JZ_REG_GPIO_MASK);
484 writel(~(chip->wakeup), chip->base + JZ_REG_GPIO_MASK_SET);
485 writel(chip->wakeup, chip->base + JZ_REG_GPIO_MASK_CLEAR);
486
487 return 0;
488}
489
490static int jz4740_gpio_resume(struct sys_device *dev)
491{
492 struct jz_gpio_chip *chip = sysdev_to_chip(dev);
493 uint32_t mask = chip->suspend_mask;
494
495 writel(~mask, chip->base + JZ_REG_GPIO_MASK_CLEAR);
496 writel(mask, chip->base + JZ_REG_GPIO_MASK_SET);
497
498 return 0;
499}
500
501static struct sysdev_class jz4740_gpio_sysdev_class = {
502 .name = "gpio",
503 .suspend = jz4740_gpio_suspend,
504 .resume = jz4740_gpio_resume,
505};
506
507static int jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id)
508{
509 int ret, irq;
510
511 chip->sysdev.id = id;
512 chip->sysdev.cls = &jz4740_gpio_sysdev_class;
513 ret = sysdev_register(&chip->sysdev);
514
515 if (ret)
516 return ret;
517
518 spin_lock_init(&chip->lock);
519
520 chip->base = ioremap(JZ4740_GPIO_BASE_ADDR + (id * 0x100), 0x100);
521
522 gpiochip_add(&chip->gpio_chip);
523
524 chip->irq = JZ4740_IRQ_INTC_GPIO(id);
525 set_irq_data(chip->irq, chip);
526 set_irq_chained_handler(chip->irq, jz_gpio_irq_demux_handler);
527
528 for (irq = chip->irq_base; irq < chip->irq_base + chip->gpio_chip.ngpio; ++irq) {
529 lockdep_set_class(&irq_desc[irq].lock, &gpio_lock_class);
530 set_irq_chip_data(irq, chip);
531 set_irq_chip_and_handler(irq, &chip->irq_chip, handle_level_irq);
532 }
533
534 return 0;
535}
536
537static int __init jz4740_gpio_init(void)
538{
539 unsigned int i;
540 int ret;
541
542 ret = sysdev_class_register(&jz4740_gpio_sysdev_class);
543 if (ret)
544 return ret;
545
546 for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); ++i)
547 jz4740_gpio_chip_init(&jz4740_gpio_chips[i], i);
548
549 printk(KERN_INFO "JZ4740 GPIO initalized\n");
550
551 return 0;
552}
553arch_initcall(jz4740_gpio_init);
554
555#ifdef CONFIG_DEBUG_FS
556
557static inline void gpio_seq_reg(struct seq_file *s, struct jz_gpio_chip *chip,
558 const char *name, unsigned int reg)
559{
560 seq_printf(s, "\t%s: %08x\n", name, readl(chip->base + reg));
561}
562
563static int gpio_regs_show(struct seq_file *s, void *unused)
564{
565 struct jz_gpio_chip *chip = jz4740_gpio_chips;
566 int i;
567
568 for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); ++i, ++chip) {
569 seq_printf(s, "==GPIO %d==\n", i);
570 gpio_seq_reg(s, chip, "Pin", JZ_REG_GPIO_PIN);
571 gpio_seq_reg(s, chip, "Data", JZ_REG_GPIO_DATA);
572 gpio_seq_reg(s, chip, "Mask", JZ_REG_GPIO_MASK);
573 gpio_seq_reg(s, chip, "Pull", JZ_REG_GPIO_PULL);
574 gpio_seq_reg(s, chip, "Func", JZ_REG_GPIO_FUNC);
575 gpio_seq_reg(s, chip, "Select", JZ_REG_GPIO_SELECT);
576 gpio_seq_reg(s, chip, "Direction", JZ_REG_GPIO_DIRECTION);
577 gpio_seq_reg(s, chip, "Trigger", JZ_REG_GPIO_TRIGGER);
578 gpio_seq_reg(s, chip, "Flag", JZ_REG_GPIO_FLAG);
579 }
580
581 return 0;
582}
583
584static int gpio_regs_open(struct inode *inode, struct file *file)
585{
586 return single_open(file, gpio_regs_show, NULL);
587}
588
589static const struct file_operations gpio_regs_operations = {
590 .open = gpio_regs_open,
591 .read = seq_read,
592 .llseek = seq_lseek,
593 .release = single_release,
594};
595
596static int __init gpio_debugfs_init(void)
597{
598 (void) debugfs_create_file("jz_regs_gpio", S_IFREG | S_IRUGO,
599 NULL, NULL, &gpio_regs_operations);
600 return 0;
601}
602subsys_initcall(gpio_debugfs_init);
603
604#endif
diff --git a/arch/mips/jz4740/irq.c b/arch/mips/jz4740/irq.c
new file mode 100644
index 000000000000..7d33ff83580f
--- /dev/null
+++ b/arch/mips/jz4740/irq.c
@@ -0,0 +1,167 @@
1/*
2 * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4740 platform IRQ support
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#include <linux/errno.h>
17#include <linux/init.h>
18#include <linux/types.h>
19#include <linux/interrupt.h>
20#include <linux/ioport.h>
21#include <linux/timex.h>
22#include <linux/slab.h>
23#include <linux/delay.h>
24
25#include <linux/debugfs.h>
26#include <linux/seq_file.h>
27
28#include <asm/io.h>
29#include <asm/mipsregs.h>
30#include <asm/irq_cpu.h>
31
32#include <asm/mach-jz4740/base.h>
33
34static void __iomem *jz_intc_base;
35static uint32_t jz_intc_wakeup;
36static uint32_t jz_intc_saved;
37
38#define JZ_REG_INTC_STATUS 0x00
39#define JZ_REG_INTC_MASK 0x04
40#define JZ_REG_INTC_SET_MASK 0x08
41#define JZ_REG_INTC_CLEAR_MASK 0x0c
42#define JZ_REG_INTC_PENDING 0x10
43
44#define IRQ_BIT(x) BIT((x) - JZ4740_IRQ_BASE)
45
46static void intc_irq_unmask(unsigned int irq)
47{
48 writel(IRQ_BIT(irq), jz_intc_base + JZ_REG_INTC_CLEAR_MASK);
49}
50
51static void intc_irq_mask(unsigned int irq)
52{
53 writel(IRQ_BIT(irq), jz_intc_base + JZ_REG_INTC_SET_MASK);
54}
55
56static int intc_irq_set_wake(unsigned int irq, unsigned int on)
57{
58 if (on)
59 jz_intc_wakeup |= IRQ_BIT(irq);
60 else
61 jz_intc_wakeup &= ~IRQ_BIT(irq);
62
63 return 0;
64}
65
66static struct irq_chip intc_irq_type = {
67 .name = "INTC",
68 .mask = intc_irq_mask,
69 .mask_ack = intc_irq_mask,
70 .unmask = intc_irq_unmask,
71 .set_wake = intc_irq_set_wake,
72};
73
74static irqreturn_t jz4740_cascade(int irq, void *data)
75{
76 uint32_t irq_reg;
77
78 irq_reg = readl(jz_intc_base + JZ_REG_INTC_PENDING);
79
80 if (irq_reg)
81 generic_handle_irq(__fls(irq_reg) + JZ4740_IRQ_BASE);
82
83 return IRQ_HANDLED;
84}
85
86static struct irqaction jz4740_cascade_action = {
87 .handler = jz4740_cascade,
88 .name = "JZ4740 cascade interrupt",
89};
90
91void __init arch_init_irq(void)
92{
93 int i;
94 mips_cpu_irq_init();
95
96 jz_intc_base = ioremap(JZ4740_INTC_BASE_ADDR, 0x14);
97
98 for (i = JZ4740_IRQ_BASE; i < JZ4740_IRQ_BASE + 32; i++) {
99 intc_irq_mask(i);
100 set_irq_chip_and_handler(i, &intc_irq_type, handle_level_irq);
101 }
102
103 setup_irq(2, &jz4740_cascade_action);
104}
105
106asmlinkage void plat_irq_dispatch(void)
107{
108 unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
109 if (pending & STATUSF_IP2)
110 do_IRQ(2);
111 else if (pending & STATUSF_IP3)
112 do_IRQ(3);
113 else
114 spurious_interrupt();
115}
116
117void jz4740_intc_suspend(void)
118{
119 jz_intc_saved = readl(jz_intc_base + JZ_REG_INTC_MASK);
120 writel(~jz_intc_wakeup, jz_intc_base + JZ_REG_INTC_SET_MASK);
121 writel(jz_intc_wakeup, jz_intc_base + JZ_REG_INTC_CLEAR_MASK);
122}
123
124void jz4740_intc_resume(void)
125{
126 writel(~jz_intc_saved, jz_intc_base + JZ_REG_INTC_CLEAR_MASK);
127 writel(jz_intc_saved, jz_intc_base + JZ_REG_INTC_SET_MASK);
128}
129
130#ifdef CONFIG_DEBUG_FS
131
132static inline void intc_seq_reg(struct seq_file *s, const char *name,
133 unsigned int reg)
134{
135 seq_printf(s, "%s:\t\t%08x\n", name, readl(jz_intc_base + reg));
136}
137
138static int intc_regs_show(struct seq_file *s, void *unused)
139{
140 intc_seq_reg(s, "Status", JZ_REG_INTC_STATUS);
141 intc_seq_reg(s, "Mask", JZ_REG_INTC_MASK);
142 intc_seq_reg(s, "Pending", JZ_REG_INTC_PENDING);
143
144 return 0;
145}
146
147static int intc_regs_open(struct inode *inode, struct file *file)
148{
149 return single_open(file, intc_regs_show, NULL);
150}
151
152static const struct file_operations intc_regs_operations = {
153 .open = intc_regs_open,
154 .read = seq_read,
155 .llseek = seq_lseek,
156 .release = single_release,
157};
158
159static int __init intc_debugfs_init(void)
160{
161 (void) debugfs_create_file("jz_regs_intc", S_IFREG | S_IRUGO,
162 NULL, NULL, &intc_regs_operations);
163 return 0;
164}
165subsys_initcall(intc_debugfs_init);
166
167#endif
diff --git a/arch/mips/jz4740/irq.h b/arch/mips/jz4740/irq.h
new file mode 100644
index 000000000000..56b5eadd1fa2
--- /dev/null
+++ b/arch/mips/jz4740/irq.h
@@ -0,0 +1,21 @@
1/*
2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * You should have received a copy of the GNU General Public License along
10 * with this program; if not, write to the Free Software Foundation, Inc.,
11 * 675 Mass Ave, Cambridge, MA 02139, USA.
12 *
13 */
14
15#ifndef __MIPS_JZ4740_IRQ_H__
16#define __MIPS_JZ4740_IRQ_H__
17
18extern void jz4740_intc_suspend(void);
19extern void jz4740_intc_resume(void);
20
21#endif
diff --git a/arch/mips/jz4740/platform.c b/arch/mips/jz4740/platform.c
new file mode 100644
index 000000000000..95bc2b5b14f1
--- /dev/null
+++ b/arch/mips/jz4740/platform.c
@@ -0,0 +1,291 @@
1/*
2 * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4740 platform devices
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#include <linux/device.h>
17#include <linux/init.h>
18#include <linux/kernel.h>
19#include <linux/platform_device.h>
20#include <linux/resource.h>
21
22#include <linux/dma-mapping.h>
23
24#include <asm/mach-jz4740/platform.h>
25#include <asm/mach-jz4740/base.h>
26#include <asm/mach-jz4740/irq.h>
27
28#include <linux/serial_core.h>
29#include <linux/serial_8250.h>
30
31#include "serial.h"
32#include "clock.h"
33
34/* OHCI controller */
35static struct resource jz4740_usb_ohci_resources[] = {
36 {
37 .start = JZ4740_UHC_BASE_ADDR,
38 .end = JZ4740_UHC_BASE_ADDR + 0x1000 - 1,
39 .flags = IORESOURCE_MEM,
40 },
41 {
42 .start = JZ4740_IRQ_UHC,
43 .end = JZ4740_IRQ_UHC,
44 .flags = IORESOURCE_IRQ,
45 },
46};
47
48struct platform_device jz4740_usb_ohci_device = {
49 .name = "jz4740-ohci",
50 .id = -1,
51 .dev = {
52 .dma_mask = &jz4740_usb_ohci_device.dev.coherent_dma_mask,
53 .coherent_dma_mask = DMA_BIT_MASK(32),
54 },
55 .num_resources = ARRAY_SIZE(jz4740_usb_ohci_resources),
56 .resource = jz4740_usb_ohci_resources,
57};
58
59/* UDC (USB gadget controller) */
60static struct resource jz4740_usb_gdt_resources[] = {
61 {
62 .start = JZ4740_UDC_BASE_ADDR,
63 .end = JZ4740_UDC_BASE_ADDR + 0x1000 - 1,
64 .flags = IORESOURCE_MEM,
65 },
66 {
67 .start = JZ4740_IRQ_UDC,
68 .end = JZ4740_IRQ_UDC,
69 .flags = IORESOURCE_IRQ,
70 },
71};
72
73struct platform_device jz4740_udc_device = {
74 .name = "jz-udc",
75 .id = -1,
76 .dev = {
77 .dma_mask = &jz4740_udc_device.dev.coherent_dma_mask,
78 .coherent_dma_mask = DMA_BIT_MASK(32),
79 },
80 .num_resources = ARRAY_SIZE(jz4740_usb_gdt_resources),
81 .resource = jz4740_usb_gdt_resources,
82};
83
84/* MMC/SD controller */
85static struct resource jz4740_mmc_resources[] = {
86 {
87 .start = JZ4740_MSC_BASE_ADDR,
88 .end = JZ4740_MSC_BASE_ADDR + 0x1000 - 1,
89 .flags = IORESOURCE_MEM,
90 },
91 {
92 .start = JZ4740_IRQ_MSC,
93 .end = JZ4740_IRQ_MSC,
94 .flags = IORESOURCE_IRQ,
95 }
96};
97
98struct platform_device jz4740_mmc_device = {
99 .name = "jz4740-mmc",
100 .id = 0,
101 .dev = {
102 .dma_mask = &jz4740_mmc_device.dev.coherent_dma_mask,
103 .coherent_dma_mask = DMA_BIT_MASK(32),
104 },
105 .num_resources = ARRAY_SIZE(jz4740_mmc_resources),
106 .resource = jz4740_mmc_resources,
107};
108
109/* RTC controller */
110static struct resource jz4740_rtc_resources[] = {
111 {
112 .start = JZ4740_RTC_BASE_ADDR,
113 .end = JZ4740_RTC_BASE_ADDR + 0x38 - 1,
114 .flags = IORESOURCE_MEM,
115 },
116 {
117 .start = JZ4740_IRQ_RTC,
118 .end = JZ4740_IRQ_RTC,
119 .flags = IORESOURCE_IRQ,
120 },
121};
122
123struct platform_device jz4740_rtc_device = {
124 .name = "jz4740-rtc",
125 .id = -1,
126 .num_resources = ARRAY_SIZE(jz4740_rtc_resources),
127 .resource = jz4740_rtc_resources,
128};
129
130/* I2C controller */
131static struct resource jz4740_i2c_resources[] = {
132 {
133 .start = JZ4740_I2C_BASE_ADDR,
134 .end = JZ4740_I2C_BASE_ADDR + 0x1000 - 1,
135 .flags = IORESOURCE_MEM,
136 },
137 {
138 .start = JZ4740_IRQ_I2C,
139 .end = JZ4740_IRQ_I2C,
140 .flags = IORESOURCE_IRQ,
141 }
142};
143
144struct platform_device jz4740_i2c_device = {
145 .name = "jz4740-i2c",
146 .id = 0,
147 .num_resources = ARRAY_SIZE(jz4740_i2c_resources),
148 .resource = jz4740_i2c_resources,
149};
150
151/* NAND controller */
152static struct resource jz4740_nand_resources[] = {
153 {
154 .name = "mmio",
155 .start = JZ4740_EMC_BASE_ADDR,
156 .end = JZ4740_EMC_BASE_ADDR + 0x1000 - 1,
157 .flags = IORESOURCE_MEM,
158 },
159 {
160 .name = "bank",
161 .start = 0x18000000,
162 .end = 0x180C0000 - 1,
163 .flags = IORESOURCE_MEM,
164 },
165};
166
167struct platform_device jz4740_nand_device = {
168 .name = "jz4740-nand",
169 .num_resources = ARRAY_SIZE(jz4740_nand_resources),
170 .resource = jz4740_nand_resources,
171};
172
173/* LCD controller */
174static struct resource jz4740_framebuffer_resources[] = {
175 {
176 .start = JZ4740_LCD_BASE_ADDR,
177 .end = JZ4740_LCD_BASE_ADDR + 0x1000 - 1,
178 .flags = IORESOURCE_MEM,
179 },
180};
181
182struct platform_device jz4740_framebuffer_device = {
183 .name = "jz4740-fb",
184 .id = -1,
185 .num_resources = ARRAY_SIZE(jz4740_framebuffer_resources),
186 .resource = jz4740_framebuffer_resources,
187 .dev = {
188 .dma_mask = &jz4740_framebuffer_device.dev.coherent_dma_mask,
189 .coherent_dma_mask = DMA_BIT_MASK(32),
190 },
191};
192
193/* I2S controller */
194static struct resource jz4740_i2s_resources[] = {
195 {
196 .start = JZ4740_AIC_BASE_ADDR,
197 .end = JZ4740_AIC_BASE_ADDR + 0x38 - 1,
198 .flags = IORESOURCE_MEM,
199 },
200};
201
202struct platform_device jz4740_i2s_device = {
203 .name = "jz4740-i2s",
204 .id = -1,
205 .num_resources = ARRAY_SIZE(jz4740_i2s_resources),
206 .resource = jz4740_i2s_resources,
207};
208
209/* PCM */
210struct platform_device jz4740_pcm_device = {
211 .name = "jz4740-pcm",
212 .id = -1,
213};
214
215/* Codec */
216static struct resource jz4740_codec_resources[] = {
217 {
218 .start = JZ4740_AIC_BASE_ADDR + 0x80,
219 .end = JZ4740_AIC_BASE_ADDR + 0x88 - 1,
220 .flags = IORESOURCE_MEM,
221 },
222};
223
224struct platform_device jz4740_codec_device = {
225 .name = "jz4740-codec",
226 .id = -1,
227 .num_resources = ARRAY_SIZE(jz4740_codec_resources),
228 .resource = jz4740_codec_resources,
229};
230
231/* ADC controller */
232static struct resource jz4740_adc_resources[] = {
233 {
234 .start = JZ4740_SADC_BASE_ADDR,
235 .end = JZ4740_SADC_BASE_ADDR + 0x30,
236 .flags = IORESOURCE_MEM,
237 },
238 {
239 .start = JZ4740_IRQ_SADC,
240 .end = JZ4740_IRQ_SADC,
241 .flags = IORESOURCE_IRQ,
242 },
243 {
244 .start = JZ4740_IRQ_ADC_BASE,
245 .end = JZ4740_IRQ_ADC_BASE,
246 .flags = IORESOURCE_IRQ,
247 },
248};
249
250struct platform_device jz4740_adc_device = {
251 .name = "jz4740-adc",
252 .id = -1,
253 .num_resources = ARRAY_SIZE(jz4740_adc_resources),
254 .resource = jz4740_adc_resources,
255};
256
257/* Serial */
258#define JZ4740_UART_DATA(_id) \
259 { \
260 .flags = UPF_SKIP_TEST | UPF_IOREMAP | UPF_FIXED_TYPE, \
261 .iotype = UPIO_MEM, \
262 .regshift = 2, \
263 .serial_out = jz4740_serial_out, \
264 .type = PORT_16550, \
265 .mapbase = JZ4740_UART ## _id ## _BASE_ADDR, \
266 .irq = JZ4740_IRQ_UART ## _id, \
267 }
268
269static struct plat_serial8250_port jz4740_uart_data[] = {
270 JZ4740_UART_DATA(0),
271 JZ4740_UART_DATA(1),
272 {},
273};
274
275static struct platform_device jz4740_uart_device = {
276 .name = "serial8250",
277 .id = 0,
278 .dev = {
279 .platform_data = jz4740_uart_data,
280 },
281};
282
283void jz4740_serial_device_register(void)
284{
285 struct plat_serial8250_port *p;
286
287 for (p = jz4740_uart_data; p->flags != 0; ++p)
288 p->uartclk = jz4740_clock_bdata.ext_rate;
289
290 platform_device_register(&jz4740_uart_device);
291}
diff --git a/arch/mips/jz4740/pm.c b/arch/mips/jz4740/pm.c
new file mode 100644
index 000000000000..a9994585424d
--- /dev/null
+++ b/arch/mips/jz4740/pm.c
@@ -0,0 +1,56 @@
1/*
2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4740 SoC power management support
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#include <linux/init.h>
17#include <linux/pm.h>
18#include <linux/delay.h>
19#include <linux/suspend.h>
20
21#include <asm/mach-jz4740/clock.h>
22
23#include "clock.h"
24#include "irq.h"
25
26static int jz4740_pm_enter(suspend_state_t state)
27{
28 jz4740_intc_suspend();
29 jz4740_clock_suspend();
30
31 jz4740_clock_set_wait_mode(JZ4740_WAIT_MODE_SLEEP);
32
33 __asm__(".set\tmips3\n\t"
34 "wait\n\t"
35 ".set\tmips0");
36
37 jz4740_clock_set_wait_mode(JZ4740_WAIT_MODE_IDLE);
38
39 jz4740_clock_resume();
40 jz4740_intc_resume();
41
42 return 0;
43}
44
45static struct platform_suspend_ops jz4740_pm_ops = {
46 .valid = suspend_valid_only_mem,
47 .enter = jz4740_pm_enter,
48};
49
50static int __init jz4740_pm_init(void)
51{
52 suspend_set_ops(&jz4740_pm_ops);
53 return 0;
54
55}
56late_initcall(jz4740_pm_init);
diff --git a/arch/mips/jz4740/prom.c b/arch/mips/jz4740/prom.c
new file mode 100644
index 000000000000..cfeac15eb2e4
--- /dev/null
+++ b/arch/mips/jz4740/prom.c
@@ -0,0 +1,68 @@
1/*
2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4740 SoC prom code
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#include <linux/module.h>
17#include <linux/kernel.h>
18#include <linux/init.h>
19#include <linux/string.h>
20
21#include <linux/serial_reg.h>
22
23#include <asm/bootinfo.h>
24#include <asm/mach-jz4740/base.h>
25
26void jz4740_init_cmdline(int argc, char *argv[])
27{
28 unsigned int count = COMMAND_LINE_SIZE - 1;
29 int i;
30 char *dst = &(arcs_cmdline[0]);
31 char *src;
32
33 for (i = 1; i < argc && count; ++i) {
34 src = argv[i];
35 while (*src && count) {
36 *dst++ = *src++;
37 --count;
38 }
39 *dst++ = ' ';
40 }
41 if (i > 1)
42 --dst;
43
44 *dst = 0;
45}
46
47void __init prom_init(void)
48{
49 jz4740_init_cmdline((int)fw_arg0, (char **)fw_arg1);
50 mips_machtype = MACH_INGENIC_JZ4740;
51}
52
53void __init prom_free_prom_memory(void)
54{
55}
56
57#define UART_REG(_reg) ((void __iomem *)CKSEG1ADDR(JZ4740_UART0_BASE_ADDR + (_reg << 2)))
58
59void prom_putchar(char c)
60{
61 uint8_t lsr;
62
63 do {
64 lsr = readb(UART_REG(UART_LSR));
65 } while ((lsr & UART_LSR_TEMT) == 0);
66
67 writeb(c, UART_REG(UART_TX));
68}
diff --git a/arch/mips/jz4740/pwm.c b/arch/mips/jz4740/pwm.c
new file mode 100644
index 000000000000..a26a6faec9a6
--- /dev/null
+++ b/arch/mips/jz4740/pwm.c
@@ -0,0 +1,177 @@
1/*
2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4740 platform PWM support
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#include <linux/kernel.h>
17
18#include <linux/clk.h>
19#include <linux/err.h>
20#include <linux/pwm.h>
21#include <linux/gpio.h>
22
23#include <asm/mach-jz4740/gpio.h>
24#include "timer.h"
25
26static struct clk *jz4740_pwm_clk;
27
28DEFINE_MUTEX(jz4740_pwm_mutex);
29
30struct pwm_device {
31 unsigned int id;
32 unsigned int gpio;
33 bool used;
34};
35
36static struct pwm_device jz4740_pwm_list[] = {
37 { 2, JZ_GPIO_PWM2, false },
38 { 3, JZ_GPIO_PWM3, false },
39 { 4, JZ_GPIO_PWM4, false },
40 { 5, JZ_GPIO_PWM5, false },
41 { 6, JZ_GPIO_PWM6, false },
42 { 7, JZ_GPIO_PWM7, false },
43};
44
45struct pwm_device *pwm_request(int id, const char *label)
46{
47 int ret = 0;
48 struct pwm_device *pwm;
49
50 if (id < 2 || id > 7 || !jz4740_pwm_clk)
51 return ERR_PTR(-ENODEV);
52
53 mutex_lock(&jz4740_pwm_mutex);
54
55 pwm = &jz4740_pwm_list[id - 2];
56 if (pwm->used)
57 ret = -EBUSY;
58 else
59 pwm->used = true;
60
61 mutex_unlock(&jz4740_pwm_mutex);
62
63 if (ret)
64 return ERR_PTR(ret);
65
66 ret = gpio_request(pwm->gpio, label);
67
68 if (ret) {
69 printk(KERN_ERR "Failed to request pwm gpio: %d\n", ret);
70 pwm->used = false;
71 return ERR_PTR(ret);
72 }
73
74 jz_gpio_set_function(pwm->gpio, JZ_GPIO_FUNC_PWM);
75
76 jz4740_timer_start(id);
77
78 return pwm;
79}
80
81void pwm_free(struct pwm_device *pwm)
82{
83 pwm_disable(pwm);
84 jz4740_timer_set_ctrl(pwm->id, 0);
85
86 jz_gpio_set_function(pwm->gpio, JZ_GPIO_FUNC_NONE);
87 gpio_free(pwm->gpio);
88
89 jz4740_timer_stop(pwm->id);
90
91 pwm->used = false;
92}
93
94int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
95{
96 unsigned long long tmp;
97 unsigned long period, duty;
98 unsigned int prescaler = 0;
99 unsigned int id = pwm->id;
100 uint16_t ctrl;
101 bool is_enabled;
102
103 if (duty_ns < 0 || duty_ns > period_ns)
104 return -EINVAL;
105
106 tmp = (unsigned long long)clk_get_rate(jz4740_pwm_clk) * period_ns;
107 do_div(tmp, 1000000000);
108 period = tmp;
109
110 while (period > 0xffff && prescaler < 6) {
111 period >>= 2;
112 ++prescaler;
113 }
114
115 if (prescaler == 6)
116 return -EINVAL;
117
118 tmp = (unsigned long long)period * duty_ns;
119 do_div(tmp, period_ns);
120 duty = period - tmp;
121
122 if (duty >= period)
123 duty = period - 1;
124
125 is_enabled = jz4740_timer_is_enabled(id);
126 if (is_enabled)
127 pwm_disable(pwm);
128
129 jz4740_timer_set_count(id, 0);
130 jz4740_timer_set_duty(id, duty);
131 jz4740_timer_set_period(id, period);
132
133 ctrl = JZ_TIMER_CTRL_PRESCALER(prescaler) | JZ_TIMER_CTRL_SRC_EXT |
134 JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN;
135
136 jz4740_timer_set_ctrl(id, ctrl);
137
138 if (is_enabled)
139 pwm_enable(pwm);
140
141 return 0;
142}
143
144int pwm_enable(struct pwm_device *pwm)
145{
146 uint32_t ctrl = jz4740_timer_get_ctrl(pwm->id);
147
148 ctrl |= JZ_TIMER_CTRL_PWM_ENABLE;
149 jz4740_timer_set_ctrl(pwm->id, ctrl);
150 jz4740_timer_enable(pwm->id);
151
152 return 0;
153}
154
155void pwm_disable(struct pwm_device *pwm)
156{
157 uint32_t ctrl = jz4740_timer_get_ctrl(pwm->id);
158
159 ctrl &= ~JZ_TIMER_CTRL_PWM_ENABLE;
160 jz4740_timer_disable(pwm->id);
161 jz4740_timer_set_ctrl(pwm->id, ctrl);
162}
163
164static int __init jz4740_pwm_init(void)
165{
166 int ret = 0;
167
168 jz4740_pwm_clk = clk_get(NULL, "ext");
169
170 if (IS_ERR(jz4740_pwm_clk)) {
171 ret = PTR_ERR(jz4740_pwm_clk);
172 jz4740_pwm_clk = NULL;
173 }
174
175 return ret;
176}
177subsys_initcall(jz4740_pwm_init);
diff --git a/arch/mips/jz4740/reset.c b/arch/mips/jz4740/reset.c
new file mode 100644
index 000000000000..5f1fb95c0d0d
--- /dev/null
+++ b/arch/mips/jz4740/reset.c
@@ -0,0 +1,79 @@
1/*
2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * You should have received a copy of the GNU General Public License along
10 * with this program; if not, write to the Free Software Foundation, Inc.,
11 * 675 Mass Ave, Cambridge, MA 02139, USA.
12 *
13 */
14
15#include <linux/io.h>
16#include <linux/kernel.h>
17#include <linux/pm.h>
18
19#include <asm/reboot.h>
20
21#include <asm/mach-jz4740/base.h>
22#include <asm/mach-jz4740/timer.h>
23
24static void jz4740_halt(void)
25{
26 while (1) {
27 __asm__(".set push;\n"
28 ".set mips3;\n"
29 "wait;\n"
30 ".set pop;\n"
31 );
32 }
33}
34
35#define JZ_REG_WDT_DATA 0x00
36#define JZ_REG_WDT_COUNTER_ENABLE 0x04
37#define JZ_REG_WDT_COUNTER 0x08
38#define JZ_REG_WDT_CTRL 0x0c
39
40static void jz4740_restart(char *command)
41{
42 void __iomem *wdt_base = ioremap(JZ4740_WDT_BASE_ADDR, 0x0f);
43
44 jz4740_timer_enable_watchdog();
45
46 writeb(0, wdt_base + JZ_REG_WDT_COUNTER_ENABLE);
47
48 writew(0, wdt_base + JZ_REG_WDT_COUNTER);
49 writew(0, wdt_base + JZ_REG_WDT_DATA);
50 writew(BIT(2), wdt_base + JZ_REG_WDT_CTRL);
51
52 writeb(1, wdt_base + JZ_REG_WDT_COUNTER_ENABLE);
53 jz4740_halt();
54}
55
56#define JZ_REG_RTC_CTRL 0x00
57#define JZ_REG_RTC_HIBERNATE 0x20
58
59#define JZ_RTC_CTRL_WRDY BIT(7)
60
61static void jz4740_power_off(void)
62{
63 void __iomem *rtc_base = ioremap(JZ4740_RTC_BASE_ADDR, 0x24);
64 uint32_t ctrl;
65
66 do {
67 ctrl = readl(rtc_base + JZ_REG_RTC_CTRL);
68 } while (!(ctrl & JZ_RTC_CTRL_WRDY));
69
70 writel(1, rtc_base + JZ_REG_RTC_HIBERNATE);
71 jz4740_halt();
72}
73
74void jz4740_reset_init(void)
75{
76 _machine_restart = jz4740_restart;
77 _machine_halt = jz4740_halt;
78 pm_power_off = jz4740_power_off;
79}
diff --git a/arch/mips/jz4740/reset.h b/arch/mips/jz4740/reset.h
new file mode 100644
index 000000000000..5202ab4ad9db
--- /dev/null
+++ b/arch/mips/jz4740/reset.h
@@ -0,0 +1,6 @@
1#ifndef __MIPS_JZ4740_RESET_H__
2#define __MIPS_JZ4740_RESET_H__
3
4extern void jz4740_reset_init(void);
5
6#endif
diff --git a/arch/mips/jz4740/serial.c b/arch/mips/jz4740/serial.c
new file mode 100644
index 000000000000..d23de45826d1
--- /dev/null
+++ b/arch/mips/jz4740/serial.c
@@ -0,0 +1,33 @@
1/*
2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4740 serial support
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#include <linux/io.h>
17#include <linux/serial_core.h>
18#include <linux/serial_reg.h>
19
20void jz4740_serial_out(struct uart_port *p, int offset, int value)
21{
22 switch (offset) {
23 case UART_FCR:
24 value |= 0x10; /* Enable uart module */
25 break;
26 case UART_IER:
27 value |= (value & 0x4) << 2;
28 break;
29 default:
30 break;
31 }
32 writeb(value, p->membase + (offset << p->regshift));
33}
diff --git a/arch/mips/jz4740/serial.h b/arch/mips/jz4740/serial.h
new file mode 100644
index 000000000000..b9fe3ade0289
--- /dev/null
+++ b/arch/mips/jz4740/serial.h
@@ -0,0 +1,20 @@
1/*
2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4740 serial support
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#ifndef __MIPS_JZ4740_SERIAL_H__
17
18void jz4740_serial_out(struct uart_port *p, int offset, int value);
19
20#endif
diff --git a/arch/mips/jz4740/setup.c b/arch/mips/jz4740/setup.c
new file mode 100644
index 000000000000..6a9e14dab91e
--- /dev/null
+++ b/arch/mips/jz4740/setup.c
@@ -0,0 +1,29 @@
1/*
2 * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4740 setup code
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#include <linux/init.h>
17#include <linux/kernel.h>
18
19#include "reset.h"
20
21void __init plat_mem_setup(void)
22{
23 jz4740_reset_init();
24}
25
26const char *get_system_type(void)
27{
28 return "JZ4740";
29}
diff --git a/arch/mips/jz4740/time.c b/arch/mips/jz4740/time.c
new file mode 100644
index 000000000000..fe01678d94fd
--- /dev/null
+++ b/arch/mips/jz4740/time.c
@@ -0,0 +1,144 @@
1/*
2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4740 platform time support
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#include <linux/interrupt.h>
17#include <linux/kernel.h>
18#include <linux/time.h>
19
20#include <linux/clockchips.h>
21
22#include <asm/mach-jz4740/irq.h>
23#include <asm/time.h>
24
25#include "clock.h"
26#include "timer.h"
27
28#define TIMER_CLOCKEVENT 0
29#define TIMER_CLOCKSOURCE 1
30
31static uint16_t jz4740_jiffies_per_tick;
32
33static cycle_t jz4740_clocksource_read(struct clocksource *cs)
34{
35 return jz4740_timer_get_count(TIMER_CLOCKSOURCE);
36}
37
38static struct clocksource jz4740_clocksource = {
39 .name = "jz4740-timer",
40 .rating = 200,
41 .read = jz4740_clocksource_read,
42 .mask = CLOCKSOURCE_MASK(16),
43 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
44};
45
46static irqreturn_t jz4740_clockevent_irq(int irq, void *devid)
47{
48 struct clock_event_device *cd = devid;
49
50 jz4740_timer_ack_full(TIMER_CLOCKEVENT);
51
52 if (cd->mode != CLOCK_EVT_MODE_PERIODIC)
53 jz4740_timer_disable(TIMER_CLOCKEVENT);
54
55 cd->event_handler(cd);
56
57 return IRQ_HANDLED;
58}
59
60static void jz4740_clockevent_set_mode(enum clock_event_mode mode,
61 struct clock_event_device *cd)
62{
63 switch (mode) {
64 case CLOCK_EVT_MODE_PERIODIC:
65 jz4740_timer_set_count(TIMER_CLOCKEVENT, 0);
66 jz4740_timer_set_period(TIMER_CLOCKEVENT, jz4740_jiffies_per_tick);
67 case CLOCK_EVT_MODE_RESUME:
68 jz4740_timer_irq_full_enable(TIMER_CLOCKEVENT);
69 jz4740_timer_enable(TIMER_CLOCKEVENT);
70 break;
71 case CLOCK_EVT_MODE_ONESHOT:
72 case CLOCK_EVT_MODE_SHUTDOWN:
73 jz4740_timer_disable(TIMER_CLOCKEVENT);
74 break;
75 default:
76 break;
77 }
78}
79
80static int jz4740_clockevent_set_next(unsigned long evt,
81 struct clock_event_device *cd)
82{
83 jz4740_timer_set_count(TIMER_CLOCKEVENT, 0);
84 jz4740_timer_set_period(TIMER_CLOCKEVENT, evt);
85 jz4740_timer_enable(TIMER_CLOCKEVENT);
86
87 return 0;
88}
89
90static struct clock_event_device jz4740_clockevent = {
91 .name = "jz4740-timer",
92 .features = CLOCK_EVT_FEAT_PERIODIC,
93 .set_next_event = jz4740_clockevent_set_next,
94 .set_mode = jz4740_clockevent_set_mode,
95 .rating = 200,
96 .irq = JZ4740_IRQ_TCU0,
97};
98
99static struct irqaction timer_irqaction = {
100 .handler = jz4740_clockevent_irq,
101 .flags = IRQF_PERCPU | IRQF_TIMER,
102 .name = "jz4740-timerirq",
103 .dev_id = &jz4740_clockevent,
104};
105
106void __init plat_time_init(void)
107{
108 int ret;
109 uint32_t clk_rate;
110 uint16_t ctrl;
111
112 jz4740_timer_init();
113
114 clk_rate = jz4740_clock_bdata.ext_rate >> 4;
115 jz4740_jiffies_per_tick = DIV_ROUND_CLOSEST(clk_rate, HZ);
116
117 clockevent_set_clock(&jz4740_clockevent, clk_rate);
118 jz4740_clockevent.min_delta_ns = clockevent_delta2ns(100, &jz4740_clockevent);
119 jz4740_clockevent.max_delta_ns = clockevent_delta2ns(0xffff, &jz4740_clockevent);
120 jz4740_clockevent.cpumask = cpumask_of(0);
121
122 clockevents_register_device(&jz4740_clockevent);
123
124 clocksource_set_clock(&jz4740_clocksource, clk_rate);
125 ret = clocksource_register(&jz4740_clocksource);
126
127 if (ret)
128 printk(KERN_ERR "Failed to register clocksource: %d\n", ret);
129
130 setup_irq(JZ4740_IRQ_TCU0, &timer_irqaction);
131
132 ctrl = JZ_TIMER_CTRL_PRESCALE_16 | JZ_TIMER_CTRL_SRC_EXT;
133
134 jz4740_timer_set_ctrl(TIMER_CLOCKEVENT, ctrl);
135 jz4740_timer_set_ctrl(TIMER_CLOCKSOURCE, ctrl);
136
137 jz4740_timer_set_period(TIMER_CLOCKEVENT, jz4740_jiffies_per_tick);
138 jz4740_timer_irq_full_enable(TIMER_CLOCKEVENT);
139
140 jz4740_timer_set_period(TIMER_CLOCKSOURCE, 0xffff);
141
142 jz4740_timer_enable(TIMER_CLOCKEVENT);
143 jz4740_timer_enable(TIMER_CLOCKSOURCE);
144}
diff --git a/arch/mips/jz4740/timer.c b/arch/mips/jz4740/timer.c
new file mode 100644
index 000000000000..b2c015129055
--- /dev/null
+++ b/arch/mips/jz4740/timer.c
@@ -0,0 +1,48 @@
1/*
2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4740 platform timer support
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#include <linux/io.h>
17#include <linux/kernel.h>
18#include <linux/module.h>
19
20#include "timer.h"
21
22#include <asm/mach-jz4740/base.h>
23
24void __iomem *jz4740_timer_base;
25
26void jz4740_timer_enable_watchdog(void)
27{
28 writel(BIT(16), jz4740_timer_base + JZ_REG_TIMER_STOP_CLEAR);
29}
30
31void jz4740_timer_disable_watchdog(void)
32{
33 writel(BIT(16), jz4740_timer_base + JZ_REG_TIMER_STOP_SET);
34}
35
36void __init jz4740_timer_init(void)
37{
38 jz4740_timer_base = ioremap(JZ4740_TCU_BASE_ADDR, 0x100);
39
40 if (!jz4740_timer_base)
41 panic("Failed to ioremap timer registers");
42
43 /* Disable all timer clocks except for those used as system timers */
44 writel(0x000100fc, jz4740_timer_base + JZ_REG_TIMER_STOP_SET);
45
46 /* Timer irqs are unmasked by default, mask them */
47 writel(0x00ff00ff, jz4740_timer_base + JZ_REG_TIMER_MASK_SET);
48}
diff --git a/arch/mips/jz4740/timer.h b/arch/mips/jz4740/timer.h
new file mode 100644
index 000000000000..fca3994f2e6d
--- /dev/null
+++ b/arch/mips/jz4740/timer.h
@@ -0,0 +1,136 @@
1/*
2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4740 platform timer support
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#ifndef __MIPS_JZ4740_TIMER_H__
17#define __MIPS_JZ4740_TIMER_H__
18
19#include <linux/module.h>
20#include <linux/io.h>
21
22#define JZ_REG_TIMER_STOP 0x0C
23#define JZ_REG_TIMER_STOP_SET 0x1C
24#define JZ_REG_TIMER_STOP_CLEAR 0x2C
25#define JZ_REG_TIMER_ENABLE 0x00
26#define JZ_REG_TIMER_ENABLE_SET 0x04
27#define JZ_REG_TIMER_ENABLE_CLEAR 0x08
28#define JZ_REG_TIMER_FLAG 0x10
29#define JZ_REG_TIMER_FLAG_SET 0x14
30#define JZ_REG_TIMER_FLAG_CLEAR 0x18
31#define JZ_REG_TIMER_MASK 0x20
32#define JZ_REG_TIMER_MASK_SET 0x24
33#define JZ_REG_TIMER_MASK_CLEAR 0x28
34
35#define JZ_REG_TIMER_DFR(x) (((x) * 0x10) + 0x30)
36#define JZ_REG_TIMER_DHR(x) (((x) * 0x10) + 0x34)
37#define JZ_REG_TIMER_CNT(x) (((x) * 0x10) + 0x38)
38#define JZ_REG_TIMER_CTRL(x) (((x) * 0x10) + 0x3C)
39
40#define JZ_TIMER_IRQ_HALF(x) BIT((x) + 0x10)
41#define JZ_TIMER_IRQ_FULL(x) BIT(x)
42
43#define JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN BIT(9)
44#define JZ_TIMER_CTRL_PWM_ACTIVE_LOW BIT(8)
45#define JZ_TIMER_CTRL_PWM_ENABLE BIT(7)
46#define JZ_TIMER_CTRL_PRESCALE_MASK 0x1c
47#define JZ_TIMER_CTRL_PRESCALE_OFFSET 0x3
48#define JZ_TIMER_CTRL_PRESCALE_1 (0 << 3)
49#define JZ_TIMER_CTRL_PRESCALE_4 (1 << 3)
50#define JZ_TIMER_CTRL_PRESCALE_16 (2 << 3)
51#define JZ_TIMER_CTRL_PRESCALE_64 (3 << 3)
52#define JZ_TIMER_CTRL_PRESCALE_256 (4 << 3)
53#define JZ_TIMER_CTRL_PRESCALE_1024 (5 << 3)
54
55#define JZ_TIMER_CTRL_PRESCALER(x) ((x) << JZ_TIMER_CTRL_PRESCALE_OFFSET)
56
57#define JZ_TIMER_CTRL_SRC_EXT BIT(2)
58#define JZ_TIMER_CTRL_SRC_RTC BIT(1)
59#define JZ_TIMER_CTRL_SRC_PCLK BIT(0)
60
61extern void __iomem *jz4740_timer_base;
62void __init jz4740_timer_init(void);
63
64static inline void jz4740_timer_stop(unsigned int timer)
65{
66 writel(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_STOP_SET);
67}
68
69static inline void jz4740_timer_start(unsigned int timer)
70{
71 writel(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_STOP_CLEAR);
72}
73
74static inline bool jz4740_timer_is_enabled(unsigned int timer)
75{
76 return readb(jz4740_timer_base + JZ_REG_TIMER_ENABLE) & BIT(timer);
77}
78
79static inline void jz4740_timer_enable(unsigned int timer)
80{
81 writeb(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_ENABLE_SET);
82}
83
84static inline void jz4740_timer_disable(unsigned int timer)
85{
86 writeb(BIT(timer), jz4740_timer_base + JZ_REG_TIMER_ENABLE_CLEAR);
87}
88
89
90static inline void jz4740_timer_set_period(unsigned int timer, uint16_t period)
91{
92 writew(period, jz4740_timer_base + JZ_REG_TIMER_DFR(timer));
93}
94
95static inline void jz4740_timer_set_duty(unsigned int timer, uint16_t duty)
96{
97 writew(duty, jz4740_timer_base + JZ_REG_TIMER_DHR(timer));
98}
99
100static inline void jz4740_timer_set_count(unsigned int timer, uint16_t count)
101{
102 writew(count, jz4740_timer_base + JZ_REG_TIMER_CNT(timer));
103}
104
105static inline uint16_t jz4740_timer_get_count(unsigned int timer)
106{
107 return readw(jz4740_timer_base + JZ_REG_TIMER_CNT(timer));
108}
109
110static inline void jz4740_timer_ack_full(unsigned int timer)
111{
112 writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_FLAG_CLEAR);
113}
114
115static inline void jz4740_timer_irq_full_enable(unsigned int timer)
116{
117 writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_FLAG_CLEAR);
118 writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_MASK_CLEAR);
119}
120
121static inline void jz4740_timer_irq_full_disable(unsigned int timer)
122{
123 writel(JZ_TIMER_IRQ_FULL(timer), jz4740_timer_base + JZ_REG_TIMER_MASK_SET);
124}
125
126static inline void jz4740_timer_set_ctrl(unsigned int timer, uint16_t ctrl)
127{
128 writew(ctrl, jz4740_timer_base + JZ_REG_TIMER_CTRL(timer));
129}
130
131static inline uint16_t jz4740_timer_get_ctrl(unsigned int timer)
132{
133 return readw(jz4740_timer_base + JZ_REG_TIMER_CTRL(timer));
134}
135
136#endif