diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 57b3ca7..8228432 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -31,6 +31,15 @@ select HAS_DEBUG_LL select HAVE_MACH_ARM_HEAD +config ARCH_BCM2835 + bool "Broadcom BCM2835 boards" + select GPIOLIB + select CPU_ARM1176 + select CLKDEV_LOOKUP + select COMMON_CLK + select CLOCKSOURCE_BCM2835 + select ARM_AMBA + config ARCH_EP93XX bool "Cirrus Logic EP93xx" select CPU_ARM920T @@ -54,6 +63,7 @@ config ARCH_NOMADIK bool "STMicroelectronics Nomadik" select CPU_ARM926T + select CLOCKSOURCE_NOMADIK help Support for the Nomadik platform by ST-Ericsson @@ -87,6 +97,7 @@ config ARCH_VERSATILE bool "ARM Versatile boards (ARM926EJ-S)" select CPU_ARM926T + select GPIOLIB config ARCH_TEGRA bool "Nvidia Tegra-based boards" @@ -97,6 +108,7 @@ source arch/arm/cpu/Kconfig source arch/arm/mach-at91/Kconfig +source arch/arm/mach-bcm2835/Kconfig source arch/arm/mach-ep93xx/Kconfig source arch/arm/mach-imx/Kconfig source arch/arm/mach-mxs/Kconfig diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 855043a..5e8f509 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -52,6 +52,7 @@ # Machine directory name. This list is sorted alphanumerically # by CONFIG_* macro name. machine-$(CONFIG_ARCH_AT91) := at91 +machine-$(CONFIG_ARCH_BCM2835) := bcm2835 machine-$(CONFIG_ARCH_EP93XX) := ep93xx machine-$(CONFIG_ARCH_IMX) := imx machine-$(CONFIG_ARCH_MXS) := mxs @@ -112,6 +113,7 @@ board-$(CONFIG_MACH_PM9261) := pm9261 board-$(CONFIG_MACH_PM9263) := pm9263 board-$(CONFIG_MACH_PM9G45) := pm9g45 +board-$(CONFIG_MACH_RPI) := raspberry-pi board-$(CONFIG_MACH_SCB9328) := scb9328 board-$(CONFIG_MACH_NESO) := guf-neso board-$(CONFIG_MACH_MX23EVK) := freescale-mx23-evk diff --git a/arch/arm/boards/raspberry-pi/Makefile b/arch/arm/boards/raspberry-pi/Makefile new file mode 100644 index 0000000..6ce5ede --- /dev/null +++ b/arch/arm/boards/raspberry-pi/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_MACH_RPI) += rpi.o diff --git a/arch/arm/boards/raspberry-pi/config.h b/arch/arm/boards/raspberry-pi/config.h new file mode 100644 index 0000000..ca15136 --- /dev/null +++ b/arch/arm/boards/raspberry-pi/config.h @@ -0,0 +1,4 @@ +#ifndef __CONFIG_H +#define __CONFIG_H + +#endif /* __CONFIG_H */ diff --git a/arch/arm/boards/raspberry-pi/env/init/bootargs-base b/arch/arm/boards/raspberry-pi/env/init/bootargs-base new file mode 100644 index 0000000..d869754 --- /dev/null +++ b/arch/arm/boards/raspberry-pi/env/init/bootargs-base @@ -0,0 +1,8 @@ +#!/bin/sh + +if [ "$1" = menu ]; then + init-menu-add-entry "$0" "Base bootargs" + exit +fi + +global.linux.bootargs.base="console=ttymxc0,115200" diff --git a/arch/arm/boards/raspberry-pi/env/init/hostname b/arch/arm/boards/raspberry-pi/env/init/hostname new file mode 100644 index 0000000..7e8f294 --- /dev/null +++ b/arch/arm/boards/raspberry-pi/env/init/hostname @@ -0,0 +1,8 @@ +#!/bin/sh + +if [ "$1" = menu ]; then + init-menu-add-entry "$0" "hostname" + exit +fi + +global.hostname=Raspberry-Pi diff --git a/arch/arm/boards/raspberry-pi/rpi.c b/arch/arm/boards/raspberry-pi/rpi.c new file mode 100644 index 0000000..3be95ae --- /dev/null +++ b/arch/arm/boards/raspberry-pi/rpi.c @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2009 Carlo Caione + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include + +#include + +static int rpi_mem_init(void) +{ + bcm2835_add_device_sdram(0); + return 0; +} +mem_initcall(rpi_mem_init); + +static int rpi_console_init(void) +{ + bcm2835_register_uart(); + return 0; +} +console_initcall(rpi_console_init); + +static int rpi_devices_init(void) +{ + armlinux_set_architecture(MACH_TYPE_BCM2708); + armlinux_set_bootparams((void *)(0x00000100)); + return 0; +} + +device_initcall(rpi_devices_init); diff --git a/arch/arm/configs/rpi_defconfig b/arch/arm/configs/rpi_defconfig new file mode 100644 index 0000000..014e28c --- /dev/null +++ b/arch/arm/configs/rpi_defconfig @@ -0,0 +1,41 @@ +CONFIG_ARCH_BCM2835=y +CONFIG_GPIO_BCM2835=y +CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y +CONFIG_PROMPT="R-Pi> " +CONFIG_LONGHELP=y +CONFIG_GLOB=y +CONFIG_HUSH_FANCY_PROMPT=y +CONFIG_CMDLINE_EDITING=y +CONFIG_AUTO_COMPLETE=y +CONFIG_MENU=y +CONFIG_PARTITION=y +CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y +CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/raspberry-pi/env" +CONFIG_CMD_EDIT=y +CONFIG_CMD_SLEEP=y +CONFIG_CMD_SAVEENV=y +CONFIG_CMD_LOADENV=y +CONFIG_CMD_EXPORT=y +CONFIG_CMD_PRINTENV=y +CONFIG_CMD_READLINE=y +CONFIG_CMD_MENU=y +CONFIG_CMD_MENU_MANAGEMENT=y +CONFIG_CMD_PASSWD=y +CONFIG_CMD_ECHO_E=y +CONFIG_CMD_LOADB=y +CONFIG_CMD_MEMINFO=y +CONFIG_CMD_MTEST=y +CONFIG_CMD_MTEST_ALTERNATIVE=y +CONFIG_CMD_BOOTM_ZLIB=y +CONFIG_CMD_BOOTM_BZLIB=y +CONFIG_CMD_BOOTM_SHOW_TYPE=y +CONFIG_CMD_RESET=y +CONFIG_CMD_CLK=y +CONFIG_CMD_GO=y +CONFIG_CMD_TIMEOUT=y +CONFIG_CMD_PARTITION=y +CONFIG_CMD_UNCOMPRESS=y +CONFIG_CMD_GPIO=y +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SHA1=y +CONFIG_SHA256=y diff --git a/arch/arm/configs/versatilepb_defconfig b/arch/arm/configs/versatilepb_defconfig index eb29a22..8daf9ae 100644 --- a/arch/arm/configs/versatilepb_defconfig +++ b/arch/arm/configs/versatilepb_defconfig @@ -32,6 +32,7 @@ CONFIG_CMD_GO=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y +CONFIG_CMD_GPIO=y CONFIG_CMD_UNCOMPRESS=y CONFIG_CMD_I2C=y CONFIG_NET=y @@ -44,6 +45,7 @@ CONFIG_NET_RESOLV=y CONFIG_SERIAL_AMBA_PL011=y CONFIG_DRIVER_NET_SMC91111=y +CONFIG_GPIO_PL061=y CONFIG_I2C=y CONFIG_I2C_VERSATILE=y CONFIG_FS_CRAMFS=y diff --git a/arch/arm/cpu/Kconfig b/arch/arm/cpu/Kconfig index 2ed6789..d8a5fb1 100644 --- a/arch/arm/cpu/Kconfig +++ b/arch/arm/cpu/Kconfig @@ -8,6 +8,11 @@ # which CPUs we support in the kernel image, and the compiler instruction # optimiser behaviour. +# ARM1176 +config CPU_ARM1176 + bool + select CPU_V6 + # ARM920T config CPU_ARM920T bool diff --git a/arch/arm/mach-bcm2835/Kconfig b/arch/arm/mach-bcm2835/Kconfig new file mode 100644 index 0000000..9d97aea --- /dev/null +++ b/arch/arm/mach-bcm2835/Kconfig @@ -0,0 +1,18 @@ +if ARCH_BCM2835 + +config ARCH_TEXT_BASE + hex + default 0x04000000 if MACH_RPI + +config BOARDINFO + default "RaspberryPi (BCM2835/ARM1176JZF-S)" if MACH_RPI + +choice + prompt "Broadcom Board type" + +config MACH_RPI + bool "RaspberryPi (BCM2835/ARM1176JZF-S)" + +endchoice + +endif diff --git a/arch/arm/mach-bcm2835/Makefile b/arch/arm/mach-bcm2835/Makefile new file mode 100644 index 0000000..820eb10 --- /dev/null +++ b/arch/arm/mach-bcm2835/Makefile @@ -0,0 +1 @@ +obj-y += core.o diff --git a/arch/arm/mach-bcm2835/core.c b/arch/arm/mach-bcm2835/core.c new file mode 100644 index 0000000..b0fec8b --- /dev/null +++ b/arch/arm/mach-bcm2835/core.c @@ -0,0 +1,101 @@ +/* + * Author: Carlo Caione + * + * Based on mach-nomadik + * Copyright (C) 2009 Jean-Christophe PLAGNIOL-VILLARD + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +enum brcm_clks { + dummy, clk_ref_3, clk_ref_1, clks_max +}; + +static struct clk *clks[clks_max]; + +static int bcm2835_clk_init(void) +{ + int ret; + + clks[dummy] = clk_fixed("dummy", 0); + clks[clk_ref_3] = clk_fixed("ref3", 3 * 1000 * 1000); + clks[clk_ref_1] = clk_fixed("ref1", 1 * 1000 * 1000); + + ret = clk_register_clkdev(clks[dummy], "apb_pclk", NULL); + if (ret) + goto clk_err; + + ret = clk_register_clkdev(clks[clk_ref_3], NULL, "uart0-pl0110"); + if (ret) + goto clk_err; + + ret = clk_register_clkdev(clks[clk_ref_1], NULL, "bcm2835-cs"); + if (ret) + goto clk_err; + + return 0; + +clk_err: + return ret; + +} +postcore_initcall(bcm2835_clk_init); + +static int bcm2835_dev_init(void) +{ + add_generic_device("bcm2835-gpio", 0, NULL, BCM2835_GPIO_BASE, 0xB0, IORESOURCE_MEM, NULL); + add_generic_device("bcm2835-cs", DEVICE_ID_SINGLE, NULL, BCM2835_ST_BASE, 0x1C, IORESOURCE_MEM, NULL); + return 0; +} +coredevice_initcall(bcm2835_dev_init); + +void bcm2835_register_uart(void) +{ + amba_apb_device_add(NULL, "uart0-pl011", 0, BCM2835_UART0_BASE, 4096, NULL, 0); +} + +void bcm2835_add_device_sdram(u32 size) +{ + if (!size) + size = get_ram_size((ulong *) BCM2835_SDRAM_BASE, SZ_128M); + + arm_add_mem_device("ram0", BCM2835_SDRAM_BASE, size); +} +#define RESET_TIMEOUT 10 + +void __noreturn reset_cpu (unsigned long addr) +{ + uint32_t rstc; + + rstc = readl(PM_RSTC); + rstc &= ~PM_RSTC_WRCFG_SET; + rstc |= PM_RSTC_WRCFG_FULL_RESET; + writel(PM_PASSWORD | RESET_TIMEOUT, PM_WDOG); + writel(PM_PASSWORD | rstc, PM_RSTC); +} +EXPORT_SYMBOL(reset_cpu); diff --git a/arch/arm/mach-bcm2835/include/mach/clkdev.h b/arch/arm/mach-bcm2835/include/mach/clkdev.h new file mode 100644 index 0000000..04b37a8 --- /dev/null +++ b/arch/arm/mach-bcm2835/include/mach/clkdev.h @@ -0,0 +1,7 @@ +#ifndef __ASM_MACH_CLKDEV_H +#define __ASM_MACH_CLKDEV_H + +#define __clk_get(clk) ({ 1; }) +#define __clk_put(clk) do { } while (0) + +#endif diff --git a/arch/arm/mach-bcm2835/include/mach/core.h b/arch/arm/mach-bcm2835/include/mach/core.h new file mode 100644 index 0000000..9379af2 --- /dev/null +++ b/arch/arm/mach-bcm2835/include/mach/core.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2009 Carlo Caione + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __BCM2835_CORE_H__ +#define __BCM2835_CORE_H__ + +void bcm2835_register_uart(void); +void bcm2835_add_device_sdram(u32 size); + +#endif diff --git a/arch/arm/mach-bcm2835/include/mach/gpio.h b/arch/arm/mach-bcm2835/include/mach/gpio.h new file mode 100644 index 0000000..306ab4c --- /dev/null +++ b/arch/arm/mach-bcm2835/include/mach/gpio.h @@ -0,0 +1 @@ +#include diff --git a/arch/arm/mach-bcm2835/include/mach/platform.h b/arch/arm/mach-bcm2835/include/mach/platform.h new file mode 100644 index 0000000..e55085a --- /dev/null +++ b/arch/arm/mach-bcm2835/include/mach/platform.h @@ -0,0 +1,50 @@ +/* + * Extract from arch/arm/mach-bcm2708/include/mach/platform.h + * + * Copyright (C) 2010 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _BCM2835_PLATFORM_H +#define _BCM2835_PLATFORM_H + +/* + * SDRAM + */ +#define BCM2835_SDRAM_BASE 0x00000000 + +/* + * Definitions and addresses for the ARM CONTROL logic + * This file is manually generated. + */ + +#define BCM2835_PERI_BASE 0x20000000 +#define BCM2835_ST_BASE (BCM2835_PERI_BASE + 0x3000) /* System Timer */ +#define BCM2835_DMA_BASE (BCM2835_PERI_BASE + 0x7000) /* DMA controller */ +#define BCM2835_ARM_BASE (BCM2835_PERI_BASE + 0xB000) /* BCM2708 ARM control block */ +#define BCM2835_PM_BASE (BCM2835_PERI_BASE + 0x100000) /* Power Management, Reset controller and Watchdog registers */ +#define BCM2835_GPIO_BASE (BCM2835_PERI_BASE + 0x200000) /* GPIO */ +#define BCM2835_UART0_BASE (BCM2835_PERI_BASE + 0x201000) /* Uart 0 */ +#define BCM2835_MMCI0_BASE (BCM2835_PERI_BASE + 0x202000) /* MMC interface */ +#define BCM2835_SPI0_BASE (BCM2835_PERI_BASE + 0x204000) /* SPI0 */ +#define BCM2835_BSC0_BASE (BCM2835_PERI_BASE + 0x205000) /* BSC0 I2C/TWI */ +#define BCM2835_UART1_BASE (BCM2835_PERI_BASE + 0x215000) /* Uart 1 */ +#define BCM2835_EMMC_BASE (BCM2835_PERI_BASE + 0x300000) /* eMMC interface */ +#define BCM2835_SMI_BASE (BCM2835_PERI_BASE + 0x600000) /* SMI */ +#define BCM2835_BSC1_BASE (BCM2835_PERI_BASE + 0x804000) /* BSC1 I2C/TWI */ +#define BCM2835_USB_BASE (BCM2835_PERI_BASE + 0x980000) /* DTC_OTG USB controller */ +#define BCM2835_MCORE_BASE (BCM2835_PERI_BASE + 0x0000) /* Fake frame buffer device (actually the multicore sync block*/ + +#endif + +/* END */ diff --git a/arch/arm/mach-bcm2835/include/mach/wd.h b/arch/arm/mach-bcm2835/include/mach/wd.h new file mode 100644 index 0000000..ad8b762 --- /dev/null +++ b/arch/arm/mach-bcm2835/include/mach/wd.h @@ -0,0 +1,47 @@ +/* + * Extract from arch/arm/mach-bcm2708/include/mach/platform.h + * + * Copyright (C) 2010 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _WD_H +#define _WD_H + +/* + * Watchdog + */ +#define PM_RSTC (BCM2835_PM_BASE+0x1c) +#define PM_RSTS (BCM2835_PM_BASE+0x20) +#define PM_WDOG (BCM2835_PM_BASE+0x24) + +#define PM_WDOG_RESET 0000000000 +#define PM_PASSWORD 0x5a000000 +#define PM_WDOG_TIME_SET 0x000fffff +#define PM_RSTC_WRCFG_CLR 0xffffffcf +#define PM_RSTC_WRCFG_SET 0x00000030 +#define PM_RSTC_WRCFG_FULL_RESET 0x00000020 +#define PM_RSTC_RESET 0x00000102 + +#define PM_RSTS_HADPOR_SET 0x00001000 +#define PM_RSTS_HADSRH_SET 0x00000400 +#define PM_RSTS_HADSRF_SET 0x00000200 +#define PM_RSTS_HADSRQ_SET 0x00000100 +#define PM_RSTS_HADWRH_SET 0x00000040 +#define PM_RSTS_HADWRF_SET 0x00000020 +#define PM_RSTS_HADWRQ_SET 0x00000010 +#define PM_RSTS_HADDRH_SET 0x00000004 +#define PM_RSTS_HADDRF_SET 0x00000002 +#define PM_RSTS_HADDRQ_SET 0x00000001 + +#endif diff --git a/arch/arm/mach-ep93xx/include/mach/gpio.h b/arch/arm/mach-ep93xx/include/mach/gpio.h index 5f1b4bc..306ab4c 100644 --- a/arch/arm/mach-ep93xx/include/mach/gpio.h +++ b/arch/arm/mach-ep93xx/include/mach/gpio.h @@ -1,26 +1 @@ -/* - * Copyright (C) 2010 Matthias Kaehlcke - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - */ - -#ifndef __ASM_ARCH_GPIO_H -#define __ASM_ARCH_GPIO_H - -void gpio_set_value(unsigned gpio, int value); -int gpio_get_value(unsigned gpio); -int gpio_direction_output(unsigned gpio, int value); -int gpio_direction_input(unsigned gpio); - -#endif /* __ASM_ARCH_GPIO_H */ - +#include diff --git a/arch/arm/mach-imx/include/mach/gpio.h b/arch/arm/mach-imx/include/mach/gpio.h index 0ebc3f9..489ae2c 100644 --- a/arch/arm/mach-imx/include/mach/gpio.h +++ b/arch/arm/mach-imx/include/mach/gpio.h @@ -1,11 +1,8 @@ #ifndef __ASM_ARCH_GPIO_H #define __ASM_ARCH_GPIO_H +#include + void imx_gpio_mode(int gpio_mode); -void gpio_set_value(unsigned gpio, int value); -int gpio_get_value(unsigned gpio); -int gpio_direction_output(unsigned gpio, int value); -int gpio_direction_input(unsigned gpio); #endif /* __ASM_ARCH_GPIO_H */ - diff --git a/arch/arm/mach-mxs/include/mach/gpio.h b/arch/arm/mach-mxs/include/mach/gpio.h index 1e575fa..4e7c8fe 100644 --- a/arch/arm/mach-mxs/include/mach/gpio.h +++ b/arch/arm/mach-mxs/include/mach/gpio.h @@ -25,10 +25,8 @@ # include #endif +#include + void imx_gpio_mode(uint32_t); -void gpio_set_value(unsigned, int); -int gpio_direction_input(unsigned); -int gpio_direction_output(unsigned, int); -int gpio_get_value(unsigned); #endif /* __ASM_MACH_GPIO_H */ diff --git a/arch/arm/mach-nomadik/8815.c b/arch/arm/mach-nomadik/8815.c index 81c5ce1..c5cac58 100644 --- a/arch/arm/mach-nomadik/8815.c +++ b/arch/arm/mach-nomadik/8815.c @@ -29,6 +29,10 @@ .rate = 48 * 1000 * 1000, }; +static struct clk st8815_clk_2_4 = { + .rate = 2400000, +}; + static struct clk st8815_dummy; void st8815_add_device_sdram(u32 size) @@ -38,6 +42,7 @@ static struct clk_lookup clocks_lookups[] = { CLKDEV_CON_ID("apb_pclk", &st8815_dummy), + CLKDEV_CON_ID("nomadik_mtu", &st8815_clk_2_4), CLKDEV_DEV_ID("uart-pl0110", &st8815_clk_48), CLKDEV_DEV_ID("uart-pl0111", &st8815_clk_48), }; diff --git a/arch/arm/mach-nomadik/include/mach/mtu.h b/arch/arm/mach-nomadik/include/mach/mtu.h deleted file mode 100644 index 9095d86..0000000 --- a/arch/arm/mach-nomadik/include/mach/mtu.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef __ASM_ARCH_MTU_H -#define __ASM_ARCH_MTU_H - -/* - * The MTU device hosts four different counters, with 4 set of - * registers. These are register names. - */ - -#define MTU_IMSC 0x00 /* Interrupt mask set/clear */ -#define MTU_RIS 0x04 /* Raw interrupt status */ -#define MTU_MIS 0x08 /* Masked interrupt status */ -#define MTU_ICR 0x0C /* Interrupt clear register */ - -/* per-timer registers take 0..3 as argument */ -#define MTU_LR(x) (0x10 + 0x10 * (x) + 0x00) /* Load value */ -#define MTU_VAL(x) (0x10 + 0x10 * (x) + 0x04) /* Current value */ - -#define MTU_CR(x) (0x10 + 0x10 * (x) + 0x08) /* Control reg */ -#define MTU_BGLR(x) (0x10 + 0x10 * (x) + 0x0c) /* At next overflow */ - - -/* bits for the control register */ -#define MTU_CRn_ENA 0x80 -#define MTU_CRn_PERIODIC 0x40 /* if 0 = free-running */ -#define MTU_CRn_PRESCALE_MASK 0x0c -#define MTU_CRn_PRESCALE_1 0x00 -#define MTU_CRn_PRESCALE_16 0x04 -#define MTU_CRn_PRESCALE_256 0x08 -#define MTU_CRn_32BITS 0x02 -#define MTU_CRn_ONESHOT 0x01 /* if 0 = wraps reloading from BGLR*/ - -/* Other registers are usual amba/primecell registers, currently not used */ -#define MTU_ITCR 0xff0 -#define MTU_ITOP 0xff4 - -#define MTU_PERIPH_ID0 0xfe0 -#define MTU_PERIPH_ID1 0xfe4 -#define MTU_PERIPH_ID2 0xfe8 -#define MTU_PERIPH_ID3 0xfeC - -#define MTU_PCELL0 0xff0 -#define MTU_PCELL1 0xff4 -#define MTU_PCELL2 0xff8 -#define MTU_PCELL3 0xffC - -#endif /* __ASM_ARCH_MTU_H */ diff --git a/arch/arm/mach-nomadik/include/mach/timex.h b/arch/arm/mach-nomadik/include/mach/timex.h deleted file mode 100644 index b2b41fa..0000000 --- a/arch/arm/mach-nomadik/include/mach/timex.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __ASM_ARCH_TIMEX_H -#define __ASM_ARCH_TIMEX_H - -#define CLOCK_TICK_RATE 2400000 - -#endif diff --git a/arch/arm/mach-nomadik/timer.c b/arch/arm/mach-nomadik/timer.c index becd363..0b8dc86 100644 --- a/arch/arm/mach-nomadik/timer.c +++ b/arch/arm/mach-nomadik/timer.c @@ -10,55 +10,16 @@ */ #include #include -#include #include #include -#include -#include /* Initial value for SRC control register: all timers use MXTAL/8 source */ #define SRC_CR_INIT_MASK 0x00007fff #define SRC_CR_INIT_VAL 0x2aaa8000 -static u32 nmdk_cycle; /* write-once */ -static __iomem void *mtu_base; - -/* - * clocksource: the MTU device is a decrementing counters, so we negate - * the value being read. - */ -static uint64_t nmdk_read_timer(void) -{ - return nmdk_cycle - readl(mtu_base + MTU_VAL(0)); -} - -static struct clocksource nmdk_clksrc = { - .read = nmdk_read_timer, - .shift = 20, - .mask = CLOCKSOURCE_MASK(32), -}; - -static void nmdk_timer_reset(void) -{ - u32 cr; - - writel(0, mtu_base + MTU_CR(0)); /* off */ - - /* configure load and background-load, and fire it up */ - writel(nmdk_cycle, mtu_base + MTU_LR(0)); - writel(nmdk_cycle, mtu_base + MTU_BGLR(0)); - cr = MTU_CRn_PRESCALE_1 | MTU_CRn_32BITS; - writel(cr, mtu_base + MTU_CR(0)); - writel(cr | MTU_CRn_ENA, mtu_base + MTU_CR(0)); -} - -static int nmdk_timer_init(void) +static int st8815_timer_init(void) { u32 src_cr; - unsigned long rate; - - rate = CLOCK_TICK_RATE; /* 2.4MHz */ - nmdk_cycle = (rate + 1000 / 2) / 1000; /* Configure timer sources in "system reset controller" ctrl reg */ src_cr = readl(NOMADIK_SRC_BASE); @@ -66,16 +27,7 @@ src_cr |= SRC_CR_INIT_VAL; writel(src_cr, NOMADIK_SRC_BASE); - /* Save global pointer to mtu, used by functions above */ - mtu_base = (void *)NOMADIK_MTU0_BASE; - - /* Init the timer and register clocksource */ - nmdk_timer_reset(); - - nmdk_clksrc.mult = clocksource_hz2mult(rate, nmdk_clksrc.shift); - - init_clock(&nmdk_clksrc); - + add_generic_device("nomadik_mtu", DEVICE_ID_SINGLE, NULL, NOMADIK_MTU0_BASE, 0x1000, IORESOURCE_MEM, NULL); return 0; } -core_initcall(nmdk_timer_init); +coredevice_initcall(st8815_timer_init); diff --git a/arch/arm/mach-omap/include/mach/gpio.h b/arch/arm/mach-omap/include/mach/gpio.h index 79bf448..306ab4c 100644 --- a/arch/arm/mach-omap/include/mach/gpio.h +++ b/arch/arm/mach-omap/include/mach/gpio.h @@ -1,42 +1 @@ -/* - * Copyright (c) 2009 Wind River Systems, Inc. - * Tom Rix - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - * This work is derived from the linux 2.6.27 kernel source - * To fetch, use the kernel repository - * git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git - * Use the v2.6.27 tag. - * - * Below is the original's header including its copyright - * - * linux/arch/arm/plat-omap/gpio.c - * - * Support functions for OMAP GPIO - * - * Copyright (C) 2003-2005 Nokia Corporation - * Written by Juha Yrjölä - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#ifndef _GPIO_H -#define _GPIO_H - -void gpio_set_value(unsigned gpio, int value); -int gpio_get_value(unsigned gpio); -int gpio_direction_output(unsigned gpio, int value); -int gpio_direction_input(unsigned gpio); - -#endif /* _GPIO_H_ */ +#include diff --git a/arch/arm/mach-samsung/include/mach/gpio.h b/arch/arm/mach-samsung/include/mach/gpio.h index 2b45695..9e64a84 100644 --- a/arch/arm/mach-samsung/include/mach/gpio.h +++ b/arch/arm/mach-samsung/include/mach/gpio.h @@ -23,10 +23,8 @@ # include #endif -void gpio_set_value(unsigned, int); -int gpio_direction_input(unsigned); -int gpio_direction_output(unsigned, int); -int gpio_get_value(unsigned); +#include + void s3c_gpio_mode(unsigned); #endif /* __ASM_MACH_GPIO_H */ diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index 8534379..8aca2a1 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -203,3 +203,13 @@ while(1); } EXPORT_SYMBOL(reset_cpu); + +static int versatile_init(void) +{ + amba_apb_device_add(NULL, "pl061_gpio", 0, 0x101e4000, 4096, NULL, 0); + amba_apb_device_add(NULL, "pl061_gpio", 1, 0x101e5000, 4096, NULL, 0); + amba_apb_device_add(NULL, "pl061_gpio", 2, 0x101e6000, 4096, NULL, 0); + amba_apb_device_add(NULL, "pl061_gpio", 3, 0x101e7000, 4096, NULL, 0); + return 0; +} +coredevice_initcall(versatile_init); diff --git a/arch/arm/mach-versatile/include/mach/gpio.h b/arch/arm/mach-versatile/include/mach/gpio.h new file mode 100644 index 0000000..306ab4c --- /dev/null +++ b/arch/arm/mach-versatile/include/mach/gpio.h @@ -0,0 +1 @@ +#include diff --git a/drivers/Kconfig b/drivers/Kconfig index 945fe02..f6446e8 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -11,6 +11,7 @@ source "drivers/video/Kconfig" source "drivers/mci/Kconfig" source "drivers/clk/Kconfig" +source "drivers/clocksource/Kconfig" source "drivers/mfd/Kconfig" source "drivers/misc/Kconfig" source "drivers/led/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index e6cdf39..1fddee0 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_MCI) += mci/ obj-$(CONFIG_VIDEO) += video/ obj-y += clk/ +obj-y += clocksource/ obj-y += mfd/ obj-$(CONFIG_LED) += led/ obj-y += eeprom/ diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index 1ae822f..5441eeb 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -178,6 +178,27 @@ } EXPORT_SYMBOL(clkdev_alloc); +int clk_register_clkdev(struct clk *clk, const char *con_id, + const char *dev_fmt, ...) +{ + struct clk_lookup *cl; + va_list ap; + + if (IS_ERR(clk)) + return PTR_ERR(clk); + + va_start(ap, dev_fmt); + cl = clkdev_alloc(clk, con_id, dev_fmt, ap); + va_end(ap); + + if (!cl) + return -ENOMEM; + + clkdev_add(cl); + + return 0; +} + int clk_add_alias(const char *alias, const char *alias_dev_name, char *id, struct device_d *dev) { diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig new file mode 100644 index 0000000..09acdd7 --- /dev/null +++ b/drivers/clocksource/Kconfig @@ -0,0 +1,11 @@ +config ARM_SMP_TWD + bool + depends on ARM && CPU_V7 + +config CLOCKSOURCE_BCM2835 + bool + depends on ARCH_BCM2835 + +config CLOCKSOURCE_NOMADIK + bool + depends on ARM diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile new file mode 100644 index 0000000..92d7c13 --- /dev/null +++ b/drivers/clocksource/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_ARM_SMP_TWD) += arm_smp_twd.o +obj-$(CONFIG_CLOCKSOURCE_BCM2835) += bcm2835.o +obj-$(CONFIG_CLOCKSOURCE_NOMADIK) += nomadik.o diff --git a/drivers/clocksource/arm_smp_twd.c b/drivers/clocksource/arm_smp_twd.c new file mode 100644 index 0000000..746d566 --- /dev/null +++ b/drivers/clocksource/arm_smp_twd.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD + * + * Under GPL v2 + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define TWD_TIMER_LOAD 0x00 +#define TWD_TIMER_COUNTER 0x04 +#define TWD_TIMER_CONTROL 0x08 +#define TWD_TIMER_INTSTAT 0x0C + +#define TWD_TIMER_CONTROL_ENABLE (1 << 0) +#define TWD_TIMER_CONTROL_ONESHOT (0 << 1) +#define TWD_TIMER_CONTROL_PERIODIC (1 << 1) +#define TWD_TIMER_CONTROL_IT_ENABLE (1 << 2) + +#define TWD_TIMER_CONTROL_PRESC(x) (((x) & 0xff) << 8) + +static __iomem void *twd_base; +static struct clk *twd_clk; + +static uint64_t smp_twd_read(void) +{ + return ~readl(twd_base + TWD_TIMER_COUNTER); +} + +static struct clocksource smp_twd_clksrc = { + .read = smp_twd_read, + .shift = 20, + .mask = CLOCKSOURCE_MASK(32), +}; + +#define SMP_TWD_MAX_FREQ (25 *1000 * 1000) + +static int smp_twd_probe(struct device_d *dev) +{ + u32 tick_rate; + u32 val; + int ret; + u32 presc = 0; + + twd_clk = clk_get(dev, NULL); + if (IS_ERR(twd_clk)) { + ret = PTR_ERR(twd_clk); + dev_err(dev, "clock not found: %d\n", ret); + return ret; + } + + ret = clk_enable(twd_clk); + if (ret < 0) { + dev_err(dev, "clock failed to enable: %d\n", ret); + clk_put(twd_clk); + return ret; + } + + twd_base = dev_request_mem_region(dev, 0); + + tick_rate = clk_get_rate(twd_clk); + if (tick_rate > SMP_TWD_MAX_FREQ) { + presc = tick_rate / SMP_TWD_MAX_FREQ; + if (presc) + presc--; + presc = min((u32)0xff, presc); + tick_rate /= presc + 1; + } + + val = TWD_TIMER_CONTROL_PRESC(presc) | + TWD_TIMER_CONTROL_PERIODIC; + writel(val, twd_base + TWD_TIMER_CONTROL); + + writel(0xffffffff, twd_base + TWD_TIMER_LOAD); + + val = readl(twd_base + TWD_TIMER_CONTROL); + val |= TWD_TIMER_CONTROL_ENABLE; + writel(val, twd_base + TWD_TIMER_CONTROL); + + smp_twd_clksrc.mult = clocksource_hz2mult(tick_rate, smp_twd_clksrc.shift); + + init_clock(&smp_twd_clksrc); + + return 0; +} + +static struct driver_d smp_twd_driver = { + .name = "smp_twd", + .probe = smp_twd_probe, +}; + +static int smp_twd_init(void) +{ + return platform_driver_register(&smp_twd_driver); +} +coredevice_initcall(smp_twd_init); diff --git a/drivers/clocksource/bcm2835.c b/drivers/clocksource/bcm2835.c new file mode 100644 index 0000000..d5fe0f0 --- /dev/null +++ b/drivers/clocksource/bcm2835.c @@ -0,0 +1,90 @@ +/* + * Author: Carlo Caione + * + * Based on clocksource for nomadik + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Registers */ +#define ST_CLO 0x04 + +static __iomem void *stc_base; + +static uint64_t stc_read_cycles(void) +{ + return readl(stc_base + ST_CLO); +} + +static struct clocksource bcm2835_stc = { + .read = stc_read_cycles, + .mask = CLOCKSOURCE_MASK(32), +}; + +static int bcm2835_cs_probe(struct device_d *dev) +{ + static struct clk *stc_clk; + u32 rate; + int ret; + + stc_clk = clk_get(dev, NULL); + if (IS_ERR(stc_clk)) { + ret = PTR_ERR(stc_clk); + dev_err(dev, "clock not found: %d\n", ret); + return ret; + } + + ret = clk_enable(stc_clk); + if (ret) { + dev_err(dev, "clock failed to enable: %d\n", ret); + clk_put(stc_clk); + return ret; + } + + rate = clk_get_rate(stc_clk); + stc_base = dev_request_mem_region(dev, 0); + + clocks_calc_mult_shift(&bcm2835_stc.mult, &bcm2835_stc.shift, rate, NSEC_PER_SEC, 60); + init_clock(&bcm2835_stc); + + return 0; +} + +static __maybe_unused struct of_device_id bcm2835_cs_dt_ids[] = { + { + .compatible = "brcm,bcm2835-system-timer", + }, { + /* sentinel */ + } +}; + +static struct driver_d bcm2835_cs_driver = { + .name = "bcm2835-cs", + .probe = bcm2835_cs_probe, + .of_compatible = DRV_OF_COMPAT(bcm2835_cs_dt_ids), +}; + +static int bcm2835_cs_init(void) +{ + return platform_driver_register(&bcm2835_cs_driver); +} +coredevice_initcall(bcm2835_cs_init); diff --git a/drivers/clocksource/nomadik.c b/drivers/clocksource/nomadik.c new file mode 100644 index 0000000..8a3e6d9 --- /dev/null +++ b/drivers/clocksource/nomadik.c @@ -0,0 +1,147 @@ +/* + * linux/arch/arm/mach-nomadik/timer.c + * + * Copyright (C) 2008 STMicroelectronics + * Copyright (C) 2009 Alessandro Rubini, somewhat based on at91sam926x + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * The MTU device hosts four different counters, with 4 set of + * registers. These are register names. + */ + +#define MTU_IMSC 0x00 /* Interrupt mask set/clear */ +#define MTU_RIS 0x04 /* Raw interrupt status */ +#define MTU_MIS 0x08 /* Masked interrupt status */ +#define MTU_ICR 0x0C /* Interrupt clear register */ + +/* per-timer registers take 0..3 as argument */ +#define MTU_LR(x) (0x10 + 0x10 * (x) + 0x00) /* Load value */ +#define MTU_VAL(x) (0x10 + 0x10 * (x) + 0x04) /* Current value */ +#define MTU_CR(x) (0x10 + 0x10 * (x) + 0x08) /* Control reg */ +#define MTU_BGLR(x) (0x10 + 0x10 * (x) + 0x0c) /* At next overflow */ + +/* bits for the control register */ +#define MTU_CRn_ENA 0x80 +#define MTU_CRn_PERIODIC 0x40 /* if 0 = free-running */ +#define MTU_CRn_PRESCALE_MASK 0x0c +#define MTU_CRn_PRESCALE_1 0x00 +#define MTU_CRn_PRESCALE_16 0x04 +#define MTU_CRn_PRESCALE_256 0x08 +#define MTU_CRn_32BITS 0x02 +#define MTU_CRn_ONESHOT 0x01 /* if 0 = wraps reloading from BGLR*/ + +/* Other registers are usual amba/primecell registers, currently not used */ +#define MTU_ITCR 0xff0 +#define MTU_ITOP 0xff4 + +#define MTU_PERIPH_ID0 0xfe0 +#define MTU_PERIPH_ID1 0xfe4 +#define MTU_PERIPH_ID2 0xfe8 +#define MTU_PERIPH_ID3 0xfeC + +#define MTU_PCELL0 0xff0 +#define MTU_PCELL1 0xff4 +#define MTU_PCELL2 0xff8 +#define MTU_PCELL3 0xffC + +static __iomem void *mtu_base; +static u32 clk_prescale; +static u32 nmdk_cycle; /* write-once */ + +/* + * clocksource: the MTU device is a decrementing counters, so we negate + * the value being read. + */ +static uint64_t nmdk_read_timer(void) +{ + return nmdk_cycle - readl(mtu_base + MTU_VAL(0)); +} + +static struct clocksource nmdk_clksrc = { + .read = nmdk_read_timer, + .shift = 20, + .mask = CLOCKSOURCE_MASK(32), +}; + +static void nmdk_timer_reset(void) +{ + u32 cr; + + /* Disable */ + writel(0, mtu_base + MTU_CR(0)); /* off */ + + /* configure load and background-load, and fire it up */ + writel(nmdk_cycle, mtu_base + MTU_LR(0)); + writel(nmdk_cycle, mtu_base + MTU_BGLR(0)); + + cr = clk_prescale | MTU_CRn_32BITS; + writel(cr, mtu_base + MTU_CR(0)); + writel(cr | MTU_CRn_ENA, mtu_base + MTU_CR(0)); +} + +static int nmdk_mtu_probe(struct device_d *dev) +{ + static struct clk *mtu_clk; + u32 rate; + int ret; + + mtu_clk = clk_get(dev, NULL); + if (IS_ERR(mtu_clk)) { + ret = PTR_ERR(mtu_clk); + dev_err(dev, "clock not found: %d\n", ret); + return ret; + } + + ret = clk_enable(mtu_clk); + if (ret < 0) { + dev_err(dev, "clock failed to enable: %d\n", ret); + clk_put(mtu_clk); + return ret; + } + + rate = clk_get_rate(mtu_clk); + if (rate > 32000000) { + rate /= 16; + clk_prescale = MTU_CRn_PRESCALE_16; + } else { + clk_prescale = MTU_CRn_PRESCALE_1; + } + + nmdk_cycle = (rate + 1000 / 2) / 1000; + + /* Save global pointer to mtu, used by functions above */ + mtu_base = dev_request_mem_region(dev, 0); + + /* Init the timer and register clocksource */ + nmdk_timer_reset(); + + nmdk_clksrc.mult = clocksource_hz2mult(rate, nmdk_clksrc.shift); + + init_clock(&nmdk_clksrc); + + return 0; +} + +static struct driver_d nmdk_mtu_driver = { + .name = "nomadik_mtu", + .probe = nmdk_mtu_probe, +}; + +static int nmdk_mtu_init(void) +{ + return platform_driver_register(&nmdk_mtu_driver); +} +coredevice_initcall(nmdk_mtu_init); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 022a309..e8eeb6d 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1,10 +1,21 @@ config GPIOLIB bool + select GENERIC_GPIO if GPIOLIB menu "GPIO " +config GPIO_BCM2835 + bool "GPIO support for BCM2835" + depends on ARCH_BCM2835 + +config GPIO_PL061 + bool "PrimeCell PL061 GPIO support" + depends on ARM_AMBA + help + Say yes here to support the PrimeCell PL061 GPIO device + config GPIO_STMPE depends on I2C_STMPE bool "STMPE GPIO Expander" diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 945122b..993ab89 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -1,2 +1,4 @@ obj-$(CONFIG_GPIOLIB) += gpio.o +obj-$(CONFIG_GPIO_BCM2835) += gpio-bcm2835.o +obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o diff --git a/drivers/gpio/gpio-bcm2835.c b/drivers/gpio/gpio-bcm2835.c new file mode 100644 index 0000000..cec15c9 --- /dev/null +++ b/drivers/gpio/gpio-bcm2835.c @@ -0,0 +1,158 @@ +/* + * Author: Carlo Caione + * + * Based on linux/arch/arm/mach-bcm2708/bcm2708_gpio.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include + +#define GPIOFSEL(x) (0x00+(x)*4) +#define GPIOSET(x) (0x1c+(x)*4) +#define GPIOCLR(x) (0x28+(x)*4) +#define GPIOLEV(x) (0x34+(x)*4) +#define GPIOEDS(x) (0x40+(x)*4) +#define GPIOREN(x) (0x4c+(x)*4) +#define GPIOFEN(x) (0x58+(x)*4) +#define GPIOHEN(x) (0x64+(x)*4) +#define GPIOLEN(x) (0x70+(x)*4) +#define GPIOAREN(x) (0x7c+(x)*4) +#define GPIOAFEN(x) (0x88+(x)*4) +#define GPIOUD(x) (0x94+(x)*4) +#define GPIOUDCLK(x) (0x98+(x)*4) + +enum { + GPIO_FSEL_INPUT, GPIO_FSEL_OUTPUT, + GPIO_FSEL_ALT5, GPIO_FSEL_ALT_4, + GPIO_FSEL_ALT0, GPIO_FSEL_ALT1, + GPIO_FSEL_ALT2, GPIO_FSEL_ALT3, +}; + +struct bcm2835_gpio_chip { + void __iomem *base; + struct gpio_chip chip; +}; + +static int bcm2835_set_function(struct gpio_chip *chip, unsigned gpio, int function) +{ + struct bcm2835_gpio_chip *bcmgpio = container_of(chip, struct bcm2835_gpio_chip, chip); + void __iomem *base = bcmgpio->base; + unsigned gpiodir; + unsigned gpio_bank = gpio / 10; + unsigned gpio_field_offset = (gpio - 10 * gpio_bank) * 3; + + gpiodir = readl(base + GPIOFSEL(gpio_bank)); + gpiodir &= ~(7 << gpio_field_offset); + gpiodir |= function << gpio_field_offset; + writel(gpiodir, base + GPIOFSEL(gpio_bank)); + gpiodir = readl(base + GPIOFSEL(gpio_bank)); + + return 0; +} + +static void bcm2835_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value) +{ + struct bcm2835_gpio_chip *bcmgpio = container_of(chip, struct bcm2835_gpio_chip, chip); + void __iomem *base = bcmgpio->base; + unsigned gpio_bank = gpio / 32; + unsigned gpio_field_offset = gpio % 32; + + if (value) + writel(1 << gpio_field_offset, base + GPIOSET(gpio_bank)); + else + writel(1 << gpio_field_offset, base + GPIOCLR(gpio_bank)); +} + +static int bcm2835_gpio_get_value(struct gpio_chip *chip, unsigned gpio) +{ + struct bcm2835_gpio_chip *bcmgpio = container_of(chip, struct bcm2835_gpio_chip, chip); + void __iomem *base = bcmgpio->base; + unsigned gpio_bank = gpio / 32; + unsigned gpio_field_offset = gpio % 32; + unsigned lev; + + lev = readl(base + GPIOLEV(gpio_bank)); + return 0x1 & (lev >> gpio_field_offset); +} + +static int bcm2835_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) +{ + return bcm2835_set_function(chip, gpio, GPIO_FSEL_INPUT); +} + +static int bcm2835_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value) +{ + bcm2835_set_function(chip, gpio, GPIO_FSEL_OUTPUT); + bcm2835_gpio_set_value(chip, gpio, value); + + return 0; +} + +static struct gpio_ops bcm2835_gpio_ops = { + .direction_input = bcm2835_gpio_direction_input, + .direction_output = bcm2835_gpio_direction_output, + .get = bcm2835_gpio_get_value, + .set = bcm2835_gpio_set_value, +}; + +static int bcm2835_gpio_probe(struct device_d *dev) +{ + struct bcm2835_gpio_chip *bcmgpio; + int ret; + + bcmgpio = xzalloc(sizeof(*bcmgpio)); + bcmgpio->base = dev_request_mem_region(dev, 0); + bcmgpio->chip.ops = &bcm2835_gpio_ops; + bcmgpio->chip.base = 0; + bcmgpio->chip.ngpio = 54; + bcmgpio->chip.dev = dev; + + ret = gpiochip_add(&bcmgpio->chip); + if (ret) { + dev_err(dev, "couldn't add gpiochip, ret = %d\n", ret); + goto err; + } + dev_info(dev, "probed gpiochip%d with base %d\n", dev->id, bcmgpio->chip.base); + + return 0; + +err: + kfree(bcmgpio); + + return ret; +} + +static __maybe_unused struct of_device_id bcm2835_gpio_dt_ids[] = { + { + .compatible = "brcm,bcm2835-gpio", + }, { + /* sentinel */ + } +}; + +static struct driver_d bcm2835_gpio_driver = { + .name = "bcm2835-gpio", + .probe = bcm2835_gpio_probe, + .of_compatible = DRV_OF_COMPAT(bcm2835_gpio_dt_ids), +}; + +static int bcm2835_gpio_add(void) +{ + return platform_driver_register(&bcm2835_gpio_driver); +} +coredevice_initcall(bcm2835_gpio_add); diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c new file mode 100644 index 0000000..f34aba9 --- /dev/null +++ b/drivers/gpio/gpio-pl061.c @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2008, 2009 Provigent Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Driver for the ARM PrimeCell(tm) General Purpose Input/Output (PL061) + * + * Data sheet: ARM DDI 0190B, September 2000 + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#define GPIODIR 0x400 +#define GPIOIS 0x404 +#define GPIOIBE 0x408 +#define GPIOIEV 0x40C +#define GPIOIE 0x410 +#define GPIORIS 0x414 +#define GPIOMIS 0x418 +#define GPIOIC 0x41C + +#define PL061_GPIO_NR 8 + +struct pl061_gpio { + void __iomem *base; + struct gpio_chip gc; +}; + +static int pl061_direction_input(struct gpio_chip *gc, unsigned offset) +{ + struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); + unsigned char gpiodir; + + if (offset >= gc->ngpio) + return -EINVAL; + + gpiodir = readb(chip->base + GPIODIR); + gpiodir &= ~(1 << offset); + writeb(gpiodir, chip->base + GPIODIR); + + return 0; +} + +static int pl061_direction_output(struct gpio_chip *gc, unsigned offset, + int value) +{ + struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); + unsigned char gpiodir; + + if (offset >= gc->ngpio) + return -EINVAL; + + writeb(!!value << offset, chip->base + (1 << (offset + 2))); + gpiodir = readb(chip->base + GPIODIR); + gpiodir |= 1 << offset; + writeb(gpiodir, chip->base + GPIODIR); + + /* + * gpio value is set again, because pl061 doesn't allow to set value of + * a gpio pin before configuring it in OUT mode. + */ + writeb(!!value << offset, chip->base + (1 << (offset + 2))); + + return 0; +} + +static int pl061_get_value(struct gpio_chip *gc, unsigned offset) +{ + struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); + + return !!readb(chip->base + (1 << (offset + 2))); +} + +static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value) +{ + struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); + + writeb(!!value << offset, chip->base + (1 << (offset + 2))); +} + +static struct gpio_ops pl061_gpio_ops = { + .direction_input = pl061_direction_input, + .direction_output = pl061_direction_output, + .get = pl061_get_value, + .set = pl061_set_value, +}; + +static int pl061_probe(struct amba_device *dev, const struct amba_id *id) +{ + struct pl061_platform_data *pdata; + struct pl061_gpio *chip; + int ret; + + chip = xzalloc(sizeof(*chip)); + + pdata = dev->dev.platform_data; + if (pdata) { + chip->gc.base = pdata->gpio_base; + } else { + chip->gc.base = -1; + } + + chip->base = amba_get_mem_region(dev); + + chip->gc.ops = &pl061_gpio_ops; + chip->gc.ngpio = PL061_GPIO_NR; + chip->gc.dev = &dev->dev; + + ret = gpiochip_add(&chip->gc); + if (ret) { + dev_err(&dev->dev, "couldn't add gpiochip, ret = %d\n", ret); + goto free_mem; + } + + writeb(0, chip->base + GPIOIE); /* disable irqs */ + + return 0; + +free_mem: + kfree(chip); + + return ret; +} + +static struct amba_id pl061_ids[] = { + { + .id = 0x00041061, + .mask = 0x000fffff, + }, + { 0, 0 }, +}; + +static struct amba_driver pl061_gpio_driver = { + .drv = { + .name = "pl061_gpio", + }, + .id_table = pl061_ids, + .probe = pl061_probe, +}; + +static int __init pl061_gpio_init(void) +{ + return amba_driver_register(&pl061_gpio_driver); +} +coredevice_initcall(pl061_gpio_init); + +MODULE_AUTHOR("Baruch Siach "); +MODULE_DESCRIPTION("PL061 GPIO driver"); +MODULE_LICENSE("GPL"); diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h new file mode 100644 index 0000000..1997888 --- /dev/null +++ b/include/asm-generic/gpio.h @@ -0,0 +1,10 @@ +#ifndef __ASM_GENERIC_GPIO_H +#define __ASM_GENERIC_GPIO_H + +void gpio_set_value(unsigned gpio, int value); +int gpio_get_value(unsigned gpio); +int gpio_direction_output(unsigned gpio, int value); +int gpio_direction_input(unsigned gpio); + +#endif /* __ASM_GENERIC_GPIO_H */ + diff --git a/include/linux/amba/pl061.h b/include/linux/amba/pl061.h new file mode 100644 index 0000000..d498cd7 --- /dev/null +++ b/include/linux/amba/pl061.h @@ -0,0 +1,12 @@ +#ifndef __AMBA_PL061_H__ +#define __AMBA_PL061_H__ + +#include + +/* platform data for the PL061 GPIO driver */ + +struct pl061_platform_data { + /* number of the first GPIO */ + unsigned gpio_base; +}; +#endif /* __AMBA_PL061_H__ */ diff --git a/include/linux/clkdev.h b/include/linux/clkdev.h index d2f0d89..1fc0ab9 100644 --- a/include/linux/clkdev.h +++ b/include/linux/clkdev.h @@ -33,6 +33,7 @@ void clkdev_add_table(struct clk_lookup *, size_t); int clk_add_alias(const char *, const char *, char *, struct device_d *); +int clk_register_clkdev(struct clk *, const char *, const char *, ...); int clkdev_add_physbase(struct clk *clk, unsigned long base, const char *id);