diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-01 18:46:13 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-01 18:46:13 -0700 |
commit | 8f446a7a069e0af0639385f67c78ee2279bca04c (patch) | |
tree | 580cf495616b36ca0af0826afa87c430cdc1e7cb | |
parent | 84be4ae2c038e2b03d650cbf2a7cfd9e8d6e9e51 (diff) | |
parent | 04ef037c926ddb31088c976538e29eada4fd1490 (diff) | |
download | lwn-8f446a7a069e0af0639385f67c78ee2279bca04c.tar.gz lwn-8f446a7a069e0af0639385f67c78ee2279bca04c.zip |
Merge tag 'drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM soc driver specific changes from Olof Johansson:
- A long-coming conversion of various platforms to a common LED
infrastructure
- AT91 is moved over to use the newer MCI driver for MMC
- Pincontrol conversions for samsung platforms
- DT bindings for gscaler on samsung
- i2c driver fixes for tegra, acked by i2c maintainer
Fix up conflicts as per Olof.
* tag 'drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (48 commits)
drivers: bus: omap_l3: use resources instead of hardcoded irqs
pinctrl: exynos: Fix wakeup IRQ domain registration check
pinctrl: samsung: Uninline samsung_pinctrl_get_soc_data
pinctrl: exynos: Correct the detection of wakeup-eint node
pinctrl: exynos: Mark exynos_irq_demux_eint as inline
pinctrl: exynos: Handle only unmasked wakeup interrupts
pinctrl: exynos: Fix typos in gpio/wkup _irq_mask
pinctrl: exynos: Set pin function to EINT in irq_set_type of GPIO EINTa
drivers: bus: Move the OMAP interconnect driver to drivers/bus/
i2c: tegra: dynamically control fast clk
i2c: tegra: I2_M_NOSTART functionality not supported in Tegra20
ARM: tegra: clock: remove unused clock entry for i2c
ARM: tegra: clock: add connection name in i2c clock entry
i2c: tegra: pass proper name for getting clock
ARM: tegra: clock: add i2c fast clock entry in clock table
ARM: EXYNOS: Adds G-Scaler device from Device Tree
ARM: EXYNOS: Add clock support for G-Scaler
ARM: EXYNOS: Enable pinctrl driver support for EXYNOS4 device tree enabled platform
ARM: dts: Add pinctrl node entries for SAMSUNG EXYNOS4210 SoC
ARM: EXYNOS: skip wakeup interrupt setup if pinctrl driver is used
...
162 files changed, 4908 insertions, 3542 deletions
diff --git a/Documentation/devicetree/bindings/bus/omap-ocp2scp.txt b/Documentation/devicetree/bindings/bus/omap-ocp2scp.txt new file mode 100644 index 000000000000..d2fe064a828b --- /dev/null +++ b/Documentation/devicetree/bindings/bus/omap-ocp2scp.txt @@ -0,0 +1,10 @@ +* OMAP OCP2SCP - ocp interface to scp interface + +properties: +- compatible : Should be "ti,omap-ocp2scp" +- #address-cells, #size-cells : Must be present if the device has sub-nodes +- ranges : the child address space are mapped 1:1 onto the parent address space +- ti,hwmods : must be "ocp2scp_usb_phy" + +Sub-nodes: +All the devices connected to ocp2scp are described using sub-node to ocp2scp diff --git a/Documentation/devicetree/bindings/media/exynos5-gsc.txt b/Documentation/devicetree/bindings/media/exynos5-gsc.txt new file mode 100644 index 000000000000..0604d42f38d1 --- /dev/null +++ b/Documentation/devicetree/bindings/media/exynos5-gsc.txt @@ -0,0 +1,30 @@ +* Samsung Exynos5 G-Scaler device + +G-Scaler is used for scaling and color space conversion on EXYNOS5 SoCs. + +Required properties: +- compatible: should be "samsung,exynos5-gsc" +- reg: should contain G-Scaler physical address location and length. +- interrupts: should contain G-Scaler interrupt number + +Example: + +gsc_0: gsc@0x13e00000 { + compatible = "samsung,exynos5-gsc"; + reg = <0x13e00000 0x1000>; + interrupts = <0 85 0>; +}; + +Aliases: +Each G-Scaler node should have a numbered alias in the aliases node, +in the form of gscN, N = 0...3. G-Scaler driver uses these aliases +to retrieve the device IDs using "of_alias_get_id()" call. + +Example: + +aliases { + gsc0 =&gsc_0; + gsc1 =&gsc_1; + gsc2 =&gsc_2; + gsc3 =&gsc_3; +}; diff --git a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt new file mode 100644 index 000000000000..03dee50532f5 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt @@ -0,0 +1,196 @@ +Samsung GPIO and Pin Mux/Config controller + +Samsung's ARM based SoC's integrates a GPIO and Pin mux/config hardware +controller. It controls the input/output settings on the available pads/pins +and also provides ability to multiplex and configure the output of various +on-chip controllers onto these pads. + +Required Properties: +- compatible: should be one of the following. + - "samsung,pinctrl-exynos4210": for Exynos4210 compatible pin-controller. + - "samsung,pinctrl-exynos5250": for Exynos5250 compatible pin-controller. + +- reg: Base address of the pin controller hardware module and length of + the address space it occupies. + +- interrupts: interrupt specifier for the controller. The format and value of + the interrupt specifier depends on the interrupt parent for the controller. + +- Pin mux/config groups as child nodes: The pin mux (selecting pin function + mode) and pin config (pull up/down, driver strength) settings are represented + as child nodes of the pin-controller node. There should be atleast one + child node and there is no limit on the count of these child nodes. + + The child node should contain a list of pin(s) on which a particular pin + function selection or pin configuration (or both) have to applied. This + list of pins is specified using the property name "samsung,pins". There + should be atleast one pin specfied for this property and there is no upper + limit on the count of pins that can be specified. The pins are specified + using pin names which are derived from the hardware manual of the SoC. As + an example, the pins in GPA0 bank of the pin controller can be represented + as "gpa0-0", "gpa0-1", "gpa0-2" and so on. The names should be in lower case. + The format of the pin names should be (as per the hardware manual) + "[pin bank name]-[pin number within the bank]". + + The pin function selection that should be applied on the pins listed in the + child node is specified using the "samsung,pin-function" property. The value + of this property that should be applied to each of the pins listed in the + "samsung,pins" property should be picked from the hardware manual of the SoC + for the specified pin group. This property is optional in the child node if + no specific function selection is desired for the pins listed in the child + node. The value of this property is used as-is to program the pin-controller + function selector register of the pin-bank. + + The child node can also optionally specify one or more of the pin + configuration that should be applied on all the pins listed in the + "samsung,pins" property of the child node. The following pin configuration + properties are supported. + + - samsung,pin-pud: Pull up/down configuration. + - samsung,pin-drv: Drive strength configuration. + - samsung,pin-pud-pdn: Pull up/down configuration in power down mode. + - samsung,pin-drv-pdn: Drive strength configuration in power down mode. + + The values specified by these config properties should be derived from the + hardware manual and these values are programmed as-is into the pin + pull up/down and driver strength register of the pin-controller. + + Note: A child should include atleast a pin function selection property or + pin configuration property (one or more) or both. + + The client nodes that require a particular pin function selection and/or + pin configuration should use the bindings listed in the "pinctrl-bindings.txt" + file. + +External GPIO and Wakeup Interrupts: + +The controller supports two types of external interrupts over gpio. The first +is the external gpio interrupt and second is the external wakeup interrupts. +The difference between the two is that the external wakeup interrupts can be +used as system wakeup events. + +A. External GPIO Interrupts: For supporting external gpio interrupts, the + following properties should be specified in the pin-controller device node. + +- interrupt-controller: identifies the controller node as interrupt-parent. +- #interrupt-cells: the value of this property should be 2. + - First Cell: represents the external gpio interrupt number local to the + external gpio interrupt space of the controller. + - Second Cell: flags to identify the type of the interrupt + - 1 = rising edge triggered + - 2 = falling edge triggered + - 3 = rising and falling edge triggered + - 4 = high level triggered + - 8 = low level triggered + +B. External Wakeup Interrupts: For supporting external wakeup interrupts, a + child node representing the external wakeup interrupt controller should be + included in the pin-controller device node. This child node should include + the following properties. + + - compatible: identifies the type of the external wakeup interrupt controller + The possible values are: + - samsung,exynos4210-wakeup-eint: represents wakeup interrupt controller + found on Samsung Exynos4210 SoC. + - interrupt-parent: phandle of the interrupt parent to which the external + wakeup interrupts are forwarded to. + - interrupt-controller: identifies the node as interrupt-parent. + - #interrupt-cells: the value of this property should be 2 + - First Cell: represents the external wakeup interrupt number local to + the external wakeup interrupt space of the controller. + - Second Cell: flags to identify the type of the interrupt + - 1 = rising edge triggered + - 2 = falling edge triggered + - 3 = rising and falling edge triggered + - 4 = high level triggered + - 8 = low level triggered + +Aliases: + +All the pin controller nodes should be represented in the aliases node using +the following format 'pinctrl{n}' where n is a unique number for the alias. + +Example 1: A pin-controller node with pin groups. + + pinctrl_0: pinctrl@11400000 { + compatible = "samsung,pinctrl-exynos4210"; + reg = <0x11400000 0x1000>; + interrupts = <0 47 0>; + + uart0_data: uart0-data { + samsung,pins = "gpa0-0", "gpa0-1"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + uart0_fctl: uart0-fctl { + samsung,pins = "gpa0-2", "gpa0-3"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + uart1_data: uart1-data { + samsung,pins = "gpa0-4", "gpa0-5"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + uart1_fctl: uart1-fctl { + samsung,pins = "gpa0-6", "gpa0-7"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + i2c2_bus: i2c2-bus { + samsung,pins = "gpa0-6", "gpa0-7"; + samsung,pin-function = <3>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + }; + +Example 2: A pin-controller node with external wakeup interrupt controller node. + + pinctrl_1: pinctrl@11000000 { + compatible = "samsung,pinctrl-exynos4210"; + reg = <0x11000000 0x1000>; + interrupts = <0 46 0>; + interrupt-controller; + #interrupt-cells = <2>; + + wakup_eint: wakeup-interrupt-controller { + compatible = "samsung,exynos4210-wakeup-eint"; + interrupt-parent = <&gic>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <0 16 0>, <0 17 0>, <0 18 0>, <0 19 0>, + <0 20 0>, <0 21 0>, <0 22 0>, <0 23 0>, + <0 24 0>, <0 25 0>, <0 26 0>, <0 27 0>, + <0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>, + <0 32 0>; + }; + }; + +Example 3: A uart client node that supports 'default' and 'flow-control' states. + + uart@13800000 { + compatible = "samsung,exynos4210-uart"; + reg = <0x13800000 0x100>; + interrupts = <0 52 0>; + pinctrl-names = "default", "flow-control; + pinctrl-0 = <&uart0_data>; + pinctrl-1 = <&uart0_data &uart0_fctl>; + }; + +Example 4: Set up the default pin state for uart controller. + + static int s3c24xx_serial_probe(struct platform_device *pdev) { + struct pinctrl *pinctrl; + ... + ... + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + } diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index ad790fc25ed4..2201ff3002a7 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1768,59 +1768,6 @@ config FORCE_MAX_ZONEORDER This config option is actually maximum order plus one. For example, a value of 11 means that the largest free memory block is 2^10 pages. -config LEDS - bool "Timer and CPU usage LEDs" - depends on ARCH_CDB89712 || ARCH_EBSA110 || \ - ARCH_EBSA285 || ARCH_INTEGRATOR || \ - ARCH_LUBBOCK || MACH_MAINSTONE || ARCH_NETWINDER || \ - ARCH_OMAP || ARCH_P720T || ARCH_PXA_IDP || \ - ARCH_SA1100 || ARCH_SHARK || ARCH_VERSATILE || \ - ARCH_AT91 || ARCH_DAVINCI || \ - ARCH_KS8695 || MACH_RD88F5182 || ARCH_REALVIEW - help - If you say Y here, the LEDs on your machine will be used - to provide useful information about your current system status. - - If you are compiling a kernel for a NetWinder or EBSA-285, you will - be able to select which LEDs are active using the options below. If - you are compiling a kernel for the EBSA-110 or the LART however, the - red LED will simply flash regularly to indicate that the system is - still functional. It is safe to say Y here if you have a CATS - system, but the driver will do nothing. - -config LEDS_TIMER - bool "Timer LED" if (!ARCH_CDB89712 && !ARCH_OMAP) || \ - OMAP_OSK_MISTRAL || MACH_OMAP_H2 \ - || MACH_OMAP_PERSEUS2 - depends on LEDS - depends on !GENERIC_CLOCKEVENTS - default y if ARCH_EBSA110 - help - If you say Y here, one of the system LEDs (the green one on the - NetWinder, the amber one on the EBSA285, or the red one on the LART) - will flash regularly to indicate that the system is still - operational. This is mainly useful to kernel hackers who are - debugging unstable kernels. - - The LART uses the same LED for both Timer LED and CPU usage LED - functions. You may choose to use both, but the Timer LED function - will overrule the CPU usage LED. - -config LEDS_CPU - bool "CPU usage LED" if (!ARCH_CDB89712 && !ARCH_EBSA110 && \ - !ARCH_OMAP) \ - || OMAP_OSK_MISTRAL || MACH_OMAP_H2 \ - || MACH_OMAP_PERSEUS2 - depends on LEDS - help - If you say Y here, the red LED will be used to give a good real - time indication of CPU usage, by lighting whenever the idle task - is not currently executing. - - The LART uses the same LED for both Timer LED and CPU usage LED - functions. You may choose to use both, but the Timer LED function - will overrule the CPU usage LED. - config ALIGNMENT_TRAP bool depends on CPU_CP15_MMU diff --git a/arch/arm/boot/dts/exynos4210-pinctrl.dtsi b/arch/arm/boot/dts/exynos4210-pinctrl.dtsi new file mode 100644 index 000000000000..b12cf272ad0d --- /dev/null +++ b/arch/arm/boot/dts/exynos4210-pinctrl.dtsi @@ -0,0 +1,457 @@ +/* + * Samsung's Exynos4210 SoC pin-mux and pin-config device tree source + * + * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * Copyright (c) 2011-2012 Linaro Ltd. + * www.linaro.org + * + * Samsung's Exynos4210 SoC pin-mux and pin-config optiosn are listed as device + * tree nodes are listed in this file. + * + * 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. +*/ + +/ { + pinctrl@11400000 { + uart0_data: uart0-data { + samsung,pins = "gpa0-0", "gpa0-1"; + samsung,pin-function = <0x2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + uart0_fctl: uart0-fctl { + samsung,pins = "gpa0-2", "gpa0-3"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + uart1_data: uart1-data { + samsung,pins = "gpa0-4", "gpa0-5"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + uart1_fctl: uart1-fctl { + samsung,pins = "gpa0-6", "gpa0-7"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + i2c2_bus: i2c2-bus { + samsung,pins = "gpa0-6", "gpa0-7"; + samsung,pin-function = <3>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + uart2_data: uart2-data { + samsung,pins = "gpa1-0", "gpa1-1"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + uart2_fctl: uart2-fctl { + samsung,pins = "gpa1-2", "gpa1-3"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + uart_audio_a: uart-audio-a { + samsung,pins = "gpa1-0", "gpa1-1"; + samsung,pin-function = <4>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + i2c3_bus: i2c3-bus { + samsung,pins = "gpa1-2", "gpa1-3"; + samsung,pin-function = <3>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + uart3_data: uart3-data { + samsung,pins = "gpa1-4", "gpa1-5"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + uart_audio_b: uart-audio-b { + samsung,pins = "gpa1-4", "gpa1-5"; + samsung,pin-function = <4>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + spi0_bus: spi0-bus { + samsung,pins = "gpb-0", "gpb-2", "gpb-3"; + samsung,pin-function = <2>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + i2c4_bus: i2c4-bus { + samsung,pins = "gpb-2", "gpb-3"; + samsung,pin-function = <3>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + spi1_bus: spi1-bus { + samsung,pins = "gpb-4", "gpb-6", "gpb-7"; + samsung,pin-function = <2>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + i2c5_bus: i2c5-bus { + samsung,pins = "gpb-6", "gpb-7"; + samsung,pin-function = <3>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + i2s1_bus: i2s1-bus { + samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3", + "gpc0-4"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + pcm1_bus: pcm1-bus { + samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3", + "gpc0-4"; + samsung,pin-function = <3>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + ac97_bus: ac97-bus { + samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3", + "gpc0-4"; + samsung,pin-function = <4>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + i2s2_bus: i2s2-bus { + samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3", + "gpc1-4"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + pcm2_bus: pcm2-bus { + samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3", + "gpc1-4"; + samsung,pin-function = <3>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + spdif_bus: spdif-bus { + samsung,pins = "gpc1-0", "gpc1-1"; + samsung,pin-function = <4>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + i2c6_bus: i2c6-bus { + samsung,pins = "gpc1-3", "gpc1-4"; + samsung,pin-function = <4>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + spi2_bus: spi2-bus { + samsung,pins = "gpc1-1", "gpc1-2", "gpc1-3", "gpc1-4"; + samsung,pin-function = <5>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + i2c7_bus: i2c7-bus { + samsung,pins = "gpd0-2", "gpd0-3"; + samsung,pin-function = <3>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + i2c0_bus: i2c0-bus { + samsung,pins = "gpd1-0", "gpd1-1"; + samsung,pin-function = <2>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + i2c1_bus: i2c1-bus { + samsung,pins = "gpd1-2", "gpd1-3"; + samsung,pin-function = <2>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + }; + + pinctrl@11000000 { + sd0_clk: sd0-clk { + samsung,pins = "gpk0-0"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + sd0_cmd: sd0-cmd { + samsung,pins = "gpk0-1"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + sd0_cd: sd0-cd { + samsung,pins = "gpk0-2"; + samsung,pin-function = <2>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + sd0_bus1: sd0-bus-width1 { + samsung,pins = "gpk0-3"; + samsung,pin-function = <2>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + sd0_bus4: sd0-bus-width4 { + samsung,pins = "gpk0-3", "gpk0-4", "gpk0-5", "gpk0-6"; + samsung,pin-function = <2>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + sd0_bus8: sd0-bus-width8 { + samsung,pins = "gpk1-3", "gpk1-4", "gpk1-5", "gpk1-6"; + samsung,pin-function = <3>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + sd4_clk: sd4-clk { + samsung,pins = "gpk0-0"; + samsung,pin-function = <3>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + sd4_cmd: sd4-cmd { + samsung,pins = "gpk0-1"; + samsung,pin-function = <3>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + sd4_cd: sd4-cd { + samsung,pins = "gpk0-2"; + samsung,pin-function = <3>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + sd4_bus1: sd4-bus-width1 { + samsung,pins = "gpk0-3"; + samsung,pin-function = <3>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + sd4_bus4: sd4-bus-width4 { + samsung,pins = "gpk0-3", "gpk0-4", "gpk0-5", "gpk0-6"; + samsung,pin-function = <3>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + sd4_bus8: sd4-bus-width8 { + samsung,pins = "gpk1-3", "gpk1-4", "gpk1-5", "gpk1-6"; + samsung,pin-function = <3>; + samsung,pin-pud = <4>; + samsung,pin-drv = <0>; + }; + + sd1_clk: sd1-clk { + samsung,pins = "gpk1-0"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + sd1_cmd: sd1-cmd { + samsung,pins = "gpk1-1"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + sd1_cd: sd1-cd { + samsung,pins = "gpk1-2"; + samsung,pin-function = <2>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + sd1_bus1: sd1-bus-width1 { + samsung,pins = "gpk1-3"; + samsung,pin-function = <2>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + sd1_bus4: sd1-bus-width4 { + samsung,pins = "gpk1-3", "gpk1-4", "gpk1-5", "gpk1-6"; + samsung,pin-function = <2>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + sd2_clk: sd2-clk { + samsung,pins = "gpk2-0"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + sd2_cmd: sd2-cmd { + samsung,pins = "gpk2-1"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + sd2_cd: sd2-cd { + samsung,pins = "gpk2-2"; + samsung,pin-function = <2>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + sd2_bus1: sd2-bus-width1 { + samsung,pins = "gpk2-3"; + samsung,pin-function = <2>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + sd2_bus4: sd2-bus-width4 { + samsung,pins = "gpk2-3", "gpk2-4", "gpk2-5", "gpk2-6"; + samsung,pin-function = <2>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + sd2_bus8: sd2-bus-width8 { + samsung,pins = "gpk3-3", "gpk3-4", "gpk3-5", "gpk3-6"; + samsung,pin-function = <3>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + sd3_clk: sd3-clk { + samsung,pins = "gpk3-0"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + sd3_cmd: sd3-cmd { + samsung,pins = "gpk3-1"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + sd3_cd: sd3-cd { + samsung,pins = "gpk3-2"; + samsung,pin-function = <2>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + sd3_bus1: sd3-bus-width1 { + samsung,pins = "gpk3-3"; + samsung,pin-function = <2>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + sd3_bus4: sd3-bus-width4 { + samsung,pins = "gpk3-3", "gpk3-4", "gpk3-5", "gpk3-6"; + samsung,pin-function = <2>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + }; + + eint0: ext-int0 { + samsung,pins = "gpx0-0"; + samsung,pin-function = <0xf>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + eint8: ext-int8 { + samsung,pins = "gpx1-0"; + samsung,pin-function = <0xf>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + eint15: ext-int15 { + samsung,pins = "gpx1-7"; + samsung,pin-function = <0xf>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + eint16: ext-int16 { + samsung,pins = "gpx2-0"; + samsung,pin-function = <0xf>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + eint31: ext-int31 { + samsung,pins = "gpx3-7"; + samsung,pin-function = <0xf>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + }; + + pinctrl@03860000 { + i2s0_bus: i2s0-bus { + samsung,pins = "gpz-0", "gpz-1", "gpz-2", "gpz-3", + "gpz-4", "gpz-5", "gpz-6"; + samsung,pin-function = <0x2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + pcm0_bus: pcm0-bus { + samsung,pins = "gpz-0", "gpz-1", "gpz-2", "gpz-3", + "gpz-4"; + samsung,pin-function = <0x3>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + }; +}; diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi index 02891fe876e4..a4bd0c9a206e 100644 --- a/arch/arm/boot/dts/exynos4210.dtsi +++ b/arch/arm/boot/dts/exynos4210.dtsi @@ -20,6 +20,7 @@ */ /include/ "skeleton.dtsi" +/include/ "exynos4210-pinctrl.dtsi" / { compatible = "samsung,exynos4210"; @@ -29,6 +30,9 @@ spi0 = &spi_0; spi1 = &spi_1; spi2 = &spi_2; + pinctrl0 = &pinctrl_0; + pinctrl1 = &pinctrl_1; + pinctrl2 = &pinctrl_2; }; gic:interrupt-controller@10490000 { @@ -50,6 +54,39 @@ <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>; }; + pinctrl_0: pinctrl@11400000 { + compatible = "samsung,pinctrl-exynos4210"; + reg = <0x11400000 0x1000>; + interrupts = <0 47 0>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + pinctrl_1: pinctrl@11000000 { + compatible = "samsung,pinctrl-exynos4210"; + reg = <0x11000000 0x1000>; + interrupts = <0 46 0>; + interrupt-controller; + #interrupt-cells = <2>; + + wakup_eint: wakeup-interrupt-controller { + compatible = "samsung,exynos4210-wakeup-eint"; + interrupt-parent = <&gic>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <0 16 0>, <0 17 0>, <0 18 0>, <0 19 0>, + <0 20 0>, <0 21 0>, <0 22 0>, <0 23 0>, + <0 24 0>, <0 25 0>, <0 26 0>, <0 27 0>, + <0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>, + <0 32 0>; + }; + }; + + pinctrl_2: pinctrl@03860000 { + compatible = "samsung,pinctrl-exynos4210"; + reg = <0x03860000 0x1000>; + }; + watchdog@10060000 { compatible = "samsung,s3c2410-wdt"; reg = <0x10060000 0x100>; diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi index 004aaa8d123c..b55794b494b4 100644 --- a/arch/arm/boot/dts/exynos5250.dtsi +++ b/arch/arm/boot/dts/exynos5250.dtsi @@ -27,6 +27,10 @@ spi0 = &spi_0; spi1 = &spi_1; spi2 = &spi_2; + gsc0 = &gsc_0; + gsc1 = &gsc_1; + gsc2 = &gsc_2; + gsc3 = &gsc_3; }; gic:interrupt-controller@10481000 { @@ -460,4 +464,28 @@ #gpio-cells = <4>; }; }; + + gsc_0: gsc@0x13e00000 { + compatible = "samsung,exynos5-gsc"; + reg = <0x13e00000 0x1000>; + interrupts = <0 85 0>; + }; + + gsc_1: gsc@0x13e10000 { + compatible = "samsung,exynos5-gsc"; + reg = <0x13e10000 0x1000>; + interrupts = <0 86 0>; + }; + + gsc_2: gsc@0x13e20000 { + compatible = "samsung,exynos5-gsc"; + reg = <0x13e20000 0x1000>; + interrupts = <0 87 0>; + }; + + gsc_3: gsc@0x13e30000 { + compatible = "samsung,exynos5-gsc"; + reg = <0x13e30000 0x1000>; + interrupts = <0 88 0>; + }; }; diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi index 5d1c48459e6e..3883f94fdbd0 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -430,5 +430,13 @@ hw-caps-ll-interface; hw-caps-temp-alert; }; + + ocp2scp { + compatible = "ti,omap-ocp2scp"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + ti,hwmods = "ocp2scp_usb_phy"; + }; }; }; diff --git a/arch/arm/configs/afeb9260_defconfig b/arch/arm/configs/afeb9260_defconfig index 2afdf67c2127..c285a9d777d9 100644 --- a/arch/arm/configs/afeb9260_defconfig +++ b/arch/arm/configs/afeb9260_defconfig @@ -39,7 +39,6 @@ CONFIG_MTD_BLOCK=y CONFIG_MTD_DATAFLASH=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_ATMEL=y -CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_ATMEL_SSC=y diff --git a/arch/arm/configs/at91rm9200_defconfig b/arch/arm/configs/at91rm9200_defconfig index d54e2acd3ab1..4ae57a34a582 100644 --- a/arch/arm/configs/at91rm9200_defconfig +++ b/arch/arm/configs/at91rm9200_defconfig @@ -232,7 +232,7 @@ CONFIG_USB_GADGET=y CONFIG_USB_ETH=m CONFIG_USB_MASS_STORAGE=m CONFIG_MMC=y -CONFIG_MMC_AT91=y +CONFIG_MMC_ATMELMCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_GPIO=y diff --git a/arch/arm/configs/at91sam9261_defconfig b/arch/arm/configs/at91sam9261_defconfig index ade6b2f23116..1e8712ef062e 100644 --- a/arch/arm/configs/at91sam9261_defconfig +++ b/arch/arm/configs/at91sam9261_defconfig @@ -128,7 +128,7 @@ CONFIG_USB_GADGETFS=m CONFIG_USB_FILE_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_MMC=y -CONFIG_MMC_AT91=m +CONFIG_MMC_ATMELMCI=m CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_GPIO=y diff --git a/arch/arm/configs/at91sam9263_defconfig b/arch/arm/configs/at91sam9263_defconfig index 1cf96264cba1..d2050cada82d 100644 --- a/arch/arm/configs/at91sam9263_defconfig +++ b/arch/arm/configs/at91sam9263_defconfig @@ -61,7 +61,6 @@ CONFIG_MTD_DATAFLASH=y CONFIG_MTD_BLOCK2MTD=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_ATMEL=y -CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y CONFIG_MTD_UBI=y CONFIG_MTD_UBI_GLUEBI=y CONFIG_BLK_DEV_LOOP=y @@ -138,7 +137,7 @@ CONFIG_USB_FILE_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_MMC=y CONFIG_SDIO_UART=m -CONFIG_MMC_AT91=m +CONFIG_MMC_ATMELMCI=m CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_ATMEL_PWM=y diff --git a/arch/arm/configs/at91sam9g20_defconfig b/arch/arm/configs/at91sam9g20_defconfig index 994d331b2319..e1b0e80b54a5 100644 --- a/arch/arm/configs/at91sam9g20_defconfig +++ b/arch/arm/configs/at91sam9g20_defconfig @@ -99,7 +99,7 @@ CONFIG_USB_GADGETFS=m CONFIG_USB_FILE_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_MMC=y -CONFIG_MMC_AT91=m +CONFIG_MMC_ATMELMCI=m CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_GPIO=y diff --git a/arch/arm/configs/at91sam9rl_defconfig b/arch/arm/configs/at91sam9rl_defconfig index ad562ee64209..7cf87856d63c 100644 --- a/arch/arm/configs/at91sam9rl_defconfig +++ b/arch/arm/configs/at91sam9rl_defconfig @@ -60,7 +60,7 @@ CONFIG_AT91SAM9X_WATCHDOG=y CONFIG_FB=y CONFIG_FB_ATMEL=y CONFIG_MMC=y -CONFIG_MMC_AT91=m +CONFIG_MMC_ATMELMCI=m CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_AT91SAM9=y CONFIG_EXT2_FS=y diff --git a/arch/arm/configs/cpu9260_defconfig b/arch/arm/configs/cpu9260_defconfig index bbf729e2fb6f..921480c23b98 100644 --- a/arch/arm/configs/cpu9260_defconfig +++ b/arch/arm/configs/cpu9260_defconfig @@ -82,7 +82,7 @@ CONFIG_USB_STORAGE=y CONFIG_USB_GADGET=y CONFIG_USB_ETH=m CONFIG_MMC=y -CONFIG_MMC_AT91=m +CONFIG_MMC_ATMELMCI=m CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_GPIO=y diff --git a/arch/arm/configs/cpu9g20_defconfig b/arch/arm/configs/cpu9g20_defconfig index e7d7942927f3..ea116cbdffa1 100644 --- a/arch/arm/configs/cpu9g20_defconfig +++ b/arch/arm/configs/cpu9g20_defconfig @@ -82,7 +82,7 @@ CONFIG_USB_STORAGE=y CONFIG_USB_GADGET=y CONFIG_USB_ETH=m CONFIG_MMC=y -CONFIG_MMC_AT91=m +CONFIG_MMC_ATMELMCI=m CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_GPIO=y diff --git a/arch/arm/configs/qil-a9260_defconfig b/arch/arm/configs/qil-a9260_defconfig index 9160f3b7751f..42d5db1876ab 100644 --- a/arch/arm/configs/qil-a9260_defconfig +++ b/arch/arm/configs/qil-a9260_defconfig @@ -50,7 +50,6 @@ CONFIG_MTD_BLOCK=y CONFIG_MTD_DATAFLASH=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_ATMEL=y -CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y CONFIG_BLK_DEV_LOOP=y # CONFIG_MISC_DEVICES is not set CONFIG_SCSI=y @@ -87,7 +86,7 @@ CONFIG_USB_STORAGE=y CONFIG_USB_GADGET=y CONFIG_USB_ETH=m CONFIG_MMC=y -CONFIG_MMC_AT91=m +CONFIG_MMC_ATMELMCI=m CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_GPIO=y diff --git a/arch/arm/configs/stamp9g20_defconfig b/arch/arm/configs/stamp9g20_defconfig index d5e260b8b160..52f1488591c7 100644 --- a/arch/arm/configs/stamp9g20_defconfig +++ b/arch/arm/configs/stamp9g20_defconfig @@ -100,7 +100,6 @@ CONFIG_USB_ETH=m CONFIG_USB_FILE_STORAGE=m CONFIG_USB_G_SERIAL=m CONFIG_MMC=y -# CONFIG_MMC_AT91 is not set CONFIG_MMC_ATMELMCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y diff --git a/arch/arm/configs/usb-a9260_defconfig b/arch/arm/configs/usb-a9260_defconfig index 2e39f38b9627..a1501e1e1a90 100644 --- a/arch/arm/configs/usb-a9260_defconfig +++ b/arch/arm/configs/usb-a9260_defconfig @@ -49,7 +49,6 @@ CONFIG_MTD_BLOCK=y CONFIG_MTD_DATAFLASH=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_ATMEL=y -CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y CONFIG_BLK_DEV_LOOP=y # CONFIG_MISC_DEVICES is not set CONFIG_SCSI=y diff --git a/arch/arm/include/asm/leds.h b/arch/arm/include/asm/leds.h deleted file mode 100644 index c545739f39b7..000000000000 --- a/arch/arm/include/asm/leds.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * arch/arm/include/asm/leds.h - * - * Copyright (C) 1998 Russell King - * - * 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. - * - * Event-driven interface for LEDs on machines - * Added led_start and led_stop- Alex Holden, 28th Dec 1998. - */ -#ifndef ASM_ARM_LEDS_H -#define ASM_ARM_LEDS_H - - -typedef enum { - led_idle_start, - led_idle_end, - led_timer, - led_start, - led_stop, - led_claim, /* override idle & timer leds */ - led_release, /* restore idle & timer leds */ - led_start_timer_mode, - led_stop_timer_mode, - led_green_on, - led_green_off, - led_amber_on, - led_amber_off, - led_red_on, - led_red_off, - led_blue_on, - led_blue_off, - /* - * I want this between led_timer and led_start, but - * someone has decided to export this to user space - */ - led_halted -} led_event_t; - -/* Use this routine to handle LEDs */ - -#ifdef CONFIG_LEDS -extern void (*leds_event)(led_event_t); -#else -#define leds_event(e) -#endif - -#endif diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 1c4321430737..d81f3a6d9ad8 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -21,7 +21,6 @@ obj-y := elf.o entry-armv.o entry-common.o irq.o opcodes.o \ obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += compat.o -obj-$(CONFIG_LEDS) += leds.o obj-$(CONFIG_OC_ETM) += etm.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_ISA_DMA_API) += dma.o diff --git a/arch/arm/kernel/leds.c b/arch/arm/kernel/leds.c deleted file mode 100644 index 1911dae19e4f..000000000000 --- a/arch/arm/kernel/leds.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * LED support code, ripped out of arch/arm/kernel/time.c - * - * Copyright (C) 1994-2001 Russell King - * - * 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 <linux/export.h> -#include <linux/init.h> -#include <linux/device.h> -#include <linux/syscore_ops.h> -#include <linux/string.h> - -#include <asm/leds.h> - -static void dummy_leds_event(led_event_t evt) -{ -} - -void (*leds_event)(led_event_t) = dummy_leds_event; - -struct leds_evt_name { - const char name[8]; - int on; - int off; -}; - -static const struct leds_evt_name evt_names[] = { - { "amber", led_amber_on, led_amber_off }, - { "blue", led_blue_on, led_blue_off }, - { "green", led_green_on, led_green_off }, - { "red", led_red_on, led_red_off }, -}; - -static ssize_t leds_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - int ret = -EINVAL, len = strcspn(buf, " "); - - if (len > 0 && buf[len] == '\0') - len--; - - if (strncmp(buf, "claim", len) == 0) { - leds_event(led_claim); - ret = size; - } else if (strncmp(buf, "release", len) == 0) { - leds_event(led_release); - ret = size; - } else { - int i; - - for (i = 0; i < ARRAY_SIZE(evt_names); i++) { - if (strlen(evt_names[i].name) != len || - strncmp(buf, evt_names[i].name, len) != 0) - continue; - if (strncmp(buf+len, " on", 3) == 0) { - leds_event(evt_names[i].on); - ret = size; - } else if (strncmp(buf+len, " off", 4) == 0) { - leds_event(evt_names[i].off); - ret = size; - } - break; - } - } - return ret; -} - -static DEVICE_ATTR(event, 0200, NULL, leds_store); - -static struct bus_type leds_subsys = { - .name = "leds", - .dev_name = "leds", -}; - -static struct device leds_device = { - .id = 0, - .bus = &leds_subsys, -}; - -static int leds_suspend(void) -{ - leds_event(led_stop); - return 0; -} - -static void leds_resume(void) -{ - leds_event(led_start); -} - -static void leds_shutdown(void) -{ - leds_event(led_halted); -} - -static struct syscore_ops leds_syscore_ops = { - .shutdown = leds_shutdown, - .suspend = leds_suspend, - .resume = leds_resume, -}; - -static int __init leds_init(void) -{ - int ret; - ret = subsys_system_register(&leds_subsys, NULL); - if (ret == 0) - ret = device_register(&leds_device); - if (ret == 0) - ret = device_create_file(&leds_device, &dev_attr_event); - if (ret == 0) - register_syscore_ops(&leds_syscore_ops); - return ret; -} - -device_initcall(leds_init); - -EXPORT_SYMBOL(leds_event); diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 693b744fd572..04eea22d7958 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -31,9 +31,9 @@ #include <linux/random.h> #include <linux/hw_breakpoint.h> #include <linux/cpuidle.h> +#include <linux/leds.h> #include <asm/cacheflush.h> -#include <asm/leds.h> #include <asm/processor.h> #include <asm/thread_notify.h> #include <asm/stacktrace.h> @@ -189,7 +189,7 @@ void cpu_idle(void) while (1) { tick_nohz_idle_enter(); rcu_idle_enter(); - leds_event(led_idle_start); + ledtrig_cpu(CPU_LED_IDLE_START); while (!need_resched()) { #ifdef CONFIG_HOTPLUG_CPU if (cpu_is_offline(smp_processor_id())) @@ -220,7 +220,7 @@ void cpu_idle(void) } else local_irq_enable(); } - leds_event(led_idle_end); + ledtrig_cpu(CPU_LED_IDLE_END); rcu_idle_exit(); tick_nohz_idle_exit(); schedule_preempt_disabled(); diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index af2afb019672..09be0c3c9069 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -25,7 +25,6 @@ #include <linux/timer.h> #include <linux/irq.h> -#include <asm/leds.h> #include <asm/thread_info.h> #include <asm/sched_clock.h> #include <asm/stacktrace.h> @@ -80,21 +79,6 @@ u32 arch_gettimeoffset(void) } #endif /* CONFIG_ARCH_USES_GETTIMEOFFSET */ -#ifdef CONFIG_LEDS_TIMER -static inline void do_leds(void) -{ - static unsigned int count = HZ/2; - - if (--count == 0) { - count = HZ/2; - leds_event(led_timer); - } -} -#else -#define do_leds() -#endif - - #ifndef CONFIG_GENERIC_CLOCKEVENTS /* * Kernel system timer support. @@ -102,7 +86,6 @@ static inline void do_leds(void) void timer_tick(void) { profile_tick(CPU_PROFILING); - do_leds(); xtime_update(1); #ifndef CONFIG_SMP update_process_times(user_mode(get_irq_regs())); diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c index 01fb7325fecc..9ac427a702da 100644 --- a/arch/arm/mach-at91/at91rm9200_devices.c +++ b/arch/arm/mach-at91/at91rm9200_devices.c @@ -294,9 +294,9 @@ void __init at91_add_device_cf(struct at91_cf_data *data) {} * MMC / SD * -------------------------------------------------------------------- */ -#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE) +#if IS_ENABLED(CONFIG_MMC_ATMELMCI) static u64 mmc_dmamask = DMA_BIT_MASK(32); -static struct at91_mmc_data mmc_data; +static struct mci_platform_data mmc_data; static struct resource mmc_resources[] = { [0] = { @@ -312,7 +312,7 @@ static struct resource mmc_resources[] = { }; static struct platform_device at91rm9200_mmc_device = { - .name = "at91_mci", + .name = "atmel_mci", .id = -1, .dev = { .dma_mask = &mmc_dmamask, @@ -323,53 +323,69 @@ static struct platform_device at91rm9200_mmc_device = { .num_resources = ARRAY_SIZE(mmc_resources), }; -void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) +void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) { + unsigned int i; + unsigned int slot_count = 0; + if (!data) return; - /* input/irq */ - if (gpio_is_valid(data->det_pin)) { - at91_set_gpio_input(data->det_pin, 1); - at91_set_deglitch(data->det_pin, 1); - } - if (gpio_is_valid(data->wp_pin)) - at91_set_gpio_input(data->wp_pin, 1); - if (gpio_is_valid(data->vcc_pin)) - at91_set_gpio_output(data->vcc_pin, 0); - - /* CLK */ - at91_set_A_periph(AT91_PIN_PA27, 0); + for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { - if (data->slot_b) { - /* CMD */ - at91_set_B_periph(AT91_PIN_PA8, 1); + if (!data->slot[i].bus_width) + continue; - /* DAT0, maybe DAT1..DAT3 */ - at91_set_B_periph(AT91_PIN_PA9, 1); - if (data->wire4) { - at91_set_B_periph(AT91_PIN_PA10, 1); - at91_set_B_periph(AT91_PIN_PA11, 1); - at91_set_B_periph(AT91_PIN_PA12, 1); + /* input/irq */ + if (gpio_is_valid(data->slot[i].detect_pin)) { + at91_set_gpio_input(data->slot[i].detect_pin, 1); + at91_set_deglitch(data->slot[i].detect_pin, 1); } - } else { - /* CMD */ - at91_set_A_periph(AT91_PIN_PA28, 1); - - /* DAT0, maybe DAT1..DAT3 */ - at91_set_A_periph(AT91_PIN_PA29, 1); - if (data->wire4) { - at91_set_B_periph(AT91_PIN_PB3, 1); - at91_set_B_periph(AT91_PIN_PB4, 1); - at91_set_B_periph(AT91_PIN_PB5, 1); + if (gpio_is_valid(data->slot[i].wp_pin)) + at91_set_gpio_input(data->slot[i].wp_pin, 1); + + switch (i) { + case 0: /* slot A */ + /* CMD */ + at91_set_A_periph(AT91_PIN_PA28, 1); + /* DAT0, maybe DAT1..DAT3 */ + at91_set_A_periph(AT91_PIN_PA29, 1); + if (data->slot[i].bus_width == 4) { + at91_set_B_periph(AT91_PIN_PB3, 1); + at91_set_B_periph(AT91_PIN_PB4, 1); + at91_set_B_periph(AT91_PIN_PB5, 1); + } + slot_count++; + break; + case 1: /* slot B */ + /* CMD */ + at91_set_B_periph(AT91_PIN_PA8, 1); + /* DAT0, maybe DAT1..DAT3 */ + at91_set_B_periph(AT91_PIN_PA9, 1); + if (data->slot[i].bus_width == 4) { + at91_set_B_periph(AT91_PIN_PA10, 1); + at91_set_B_periph(AT91_PIN_PA11, 1); + at91_set_B_periph(AT91_PIN_PA12, 1); + } + slot_count++; + break; + default: + printk(KERN_ERR + "AT91: SD/MMC slot %d not available\n", i); + break; + } + if (slot_count) { + /* CLK */ + at91_set_A_periph(AT91_PIN_PA27, 0); + + mmc_data = *data; + platform_device_register(&at91rm9200_mmc_device); } } - mmc_data = *data; - platform_device_register(&at91rm9200_mmc_device); } #else -void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {} +void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {} #endif diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c index bce572a530ef..af50ff3281c7 100644 --- a/arch/arm/mach-at91/at91sam9260_devices.c +++ b/arch/arm/mach-at91/at91sam9260_devices.c @@ -209,92 +209,10 @@ void __init at91_add_device_eth(struct macb_platform_data *data) {} /* -------------------------------------------------------------------- - * MMC / SD - * -------------------------------------------------------------------- */ - -#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE) -static u64 mmc_dmamask = DMA_BIT_MASK(32); -static struct at91_mmc_data mmc_data; - -static struct resource mmc_resources[] = { - [0] = { - .start = AT91SAM9260_BASE_MCI, - .end = AT91SAM9260_BASE_MCI + SZ_16K - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI, - .end = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device at91sam9260_mmc_device = { - .name = "at91_mci", - .id = -1, - .dev = { - .dma_mask = &mmc_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(32), - .platform_data = &mmc_data, - }, - .resource = mmc_resources, - .num_resources = ARRAY_SIZE(mmc_resources), -}; - -void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) -{ - if (!data) - return; - - /* input/irq */ - if (gpio_is_valid(data->det_pin)) { - at91_set_gpio_input(data->det_pin, 1); - at91_set_deglitch(data->det_pin, 1); - } - if (gpio_is_valid(data->wp_pin)) - at91_set_gpio_input(data->wp_pin, 1); - if (gpio_is_valid(data->vcc_pin)) - at91_set_gpio_output(data->vcc_pin, 0); - - /* CLK */ - at91_set_A_periph(AT91_PIN_PA8, 0); - - if (data->slot_b) { - /* CMD */ - at91_set_B_periph(AT91_PIN_PA1, 1); - - /* DAT0, maybe DAT1..DAT3 */ - at91_set_B_periph(AT91_PIN_PA0, 1); - if (data->wire4) { - at91_set_B_periph(AT91_PIN_PA5, 1); - at91_set_B_periph(AT91_PIN_PA4, 1); - at91_set_B_periph(AT91_PIN_PA3, 1); - } - } else { - /* CMD */ - at91_set_A_periph(AT91_PIN_PA7, 1); - - /* DAT0, maybe DAT1..DAT3 */ - at91_set_A_periph(AT91_PIN_PA6, 1); - if (data->wire4) { - at91_set_A_periph(AT91_PIN_PA9, 1); - at91_set_A_periph(AT91_PIN_PA10, 1); - at91_set_A_periph(AT91_PIN_PA11, 1); - } - } - - mmc_data = *data; - platform_device_register(&at91sam9260_mmc_device); -} -#else -void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {} -#endif - -/* -------------------------------------------------------------------- * MMC / SD Slot for Atmel MCI Driver * -------------------------------------------------------------------- */ -#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE) +#if IS_ENABLED(CONFIG_MMC_ATMELMCI) static u64 mmc_dmamask = DMA_BIT_MASK(32); static struct mci_platform_data mmc_data; diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c index bc2590d712d0..11e9fa835cde 100644 --- a/arch/arm/mach-at91/at91sam9261_devices.c +++ b/arch/arm/mach-at91/at91sam9261_devices.c @@ -137,9 +137,9 @@ void __init at91_add_device_udc(struct at91_udc_data *data) {} * MMC / SD * -------------------------------------------------------------------- */ -#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE) +#if IS_ENABLED(CONFIG_MMC_ATMELMCI) static u64 mmc_dmamask = DMA_BIT_MASK(32); -static struct at91_mmc_data mmc_data; +static struct mci_platform_data mmc_data; static struct resource mmc_resources[] = { [0] = { @@ -155,7 +155,7 @@ static struct resource mmc_resources[] = { }; static struct platform_device at91sam9261_mmc_device = { - .name = "at91_mci", + .name = "atmel_mci", .id = -1, .dev = { .dma_mask = &mmc_dmamask, @@ -166,40 +166,40 @@ static struct platform_device at91sam9261_mmc_device = { .num_resources = ARRAY_SIZE(mmc_resources), }; -void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) +void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) { if (!data) return; - /* input/irq */ - if (gpio_is_valid(data->det_pin)) { - at91_set_gpio_input(data->det_pin, 1); - at91_set_deglitch(data->det_pin, 1); - } - if (gpio_is_valid(data->wp_pin)) - at91_set_gpio_input(data->wp_pin, 1); - if (gpio_is_valid(data->vcc_pin)) - at91_set_gpio_output(data->vcc_pin, 0); - - /* CLK */ - at91_set_B_periph(AT91_PIN_PA2, 0); - - /* CMD */ - at91_set_B_periph(AT91_PIN_PA1, 1); - - /* DAT0, maybe DAT1..DAT3 */ - at91_set_B_periph(AT91_PIN_PA0, 1); - if (data->wire4) { - at91_set_B_periph(AT91_PIN_PA4, 1); - at91_set_B_periph(AT91_PIN_PA5, 1); - at91_set_B_periph(AT91_PIN_PA6, 1); - } + if (data->slot[0].bus_width) { + /* input/irq */ + if (gpio_is_valid(data->slot[0].detect_pin)) { + at91_set_gpio_input(data->slot[0].detect_pin, 1); + at91_set_deglitch(data->slot[0].detect_pin, 1); + } + if (gpio_is_valid(data->slot[0].wp_pin)) + at91_set_gpio_input(data->slot[0].wp_pin, 1); + + /* CLK */ + at91_set_B_periph(AT91_PIN_PA2, 0); - mmc_data = *data; - platform_device_register(&at91sam9261_mmc_device); + /* CMD */ + at91_set_B_periph(AT91_PIN_PA1, 1); + + /* DAT0, maybe DAT1..DAT3 */ + at91_set_B_periph(AT91_PIN_PA0, 1); + if (data->slot[0].bus_width == 4) { + at91_set_B_periph(AT91_PIN_PA4, 1); + at91_set_B_periph(AT91_PIN_PA5, 1); + at91_set_B_periph(AT91_PIN_PA6, 1); + } + + mmc_data = *data; + platform_device_register(&at91sam9261_mmc_device); + } } #else -void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {} +void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {} #endif diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c index 84b38105231e..144ef5de51b6 100644 --- a/arch/arm/mach-at91/at91sam9263.c +++ b/arch/arm/mach-at91/at91sam9263.c @@ -188,8 +188,8 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_ID("hclk", &macb_clk), CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk), CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk), - CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.0", &mmc0_clk), - CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.1", &mmc1_clk), + CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.0", &mmc0_clk), + CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.1", &mmc1_clk), CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk), CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk), CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk), diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c index 9b6ca734f1a9..7c0898fe20fa 100644 --- a/arch/arm/mach-at91/at91sam9263_devices.c +++ b/arch/arm/mach-at91/at91sam9263_devices.c @@ -218,9 +218,9 @@ void __init at91_add_device_eth(struct macb_platform_data *data) {} * MMC / SD * -------------------------------------------------------------------- */ -#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE) +#if IS_ENABLED(CONFIG_MMC_ATMELMCI) static u64 mmc_dmamask = DMA_BIT_MASK(32); -static struct at91_mmc_data mmc0_data, mmc1_data; +static struct mci_platform_data mmc0_data, mmc1_data; static struct resource mmc0_resources[] = { [0] = { @@ -236,7 +236,7 @@ static struct resource mmc0_resources[] = { }; static struct platform_device at91sam9263_mmc0_device = { - .name = "at91_mci", + .name = "atmel_mci", .id = 0, .dev = { .dma_mask = &mmc_dmamask, @@ -261,7 +261,7 @@ static struct resource mmc1_resources[] = { }; static struct platform_device at91sam9263_mmc1_device = { - .name = "at91_mci", + .name = "atmel_mci", .id = 1, .dev = { .dma_mask = &mmc_dmamask, @@ -272,85 +272,110 @@ static struct platform_device at91sam9263_mmc1_device = { .num_resources = ARRAY_SIZE(mmc1_resources), }; -void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) +void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) { + unsigned int i; + unsigned int slot_count = 0; + if (!data) return; - /* input/irq */ - if (gpio_is_valid(data->det_pin)) { - at91_set_gpio_input(data->det_pin, 1); - at91_set_deglitch(data->det_pin, 1); - } - if (gpio_is_valid(data->wp_pin)) - at91_set_gpio_input(data->wp_pin, 1); - if (gpio_is_valid(data->vcc_pin)) - at91_set_gpio_output(data->vcc_pin, 0); + for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { - if (mmc_id == 0) { /* MCI0 */ - /* CLK */ - at91_set_A_periph(AT91_PIN_PA12, 0); + if (!data->slot[i].bus_width) + continue; - if (data->slot_b) { - /* CMD */ - at91_set_A_periph(AT91_PIN_PA16, 1); + /* input/irq */ + if (gpio_is_valid(data->slot[i].detect_pin)) { + at91_set_gpio_input(data->slot[i].detect_pin, + 1); + at91_set_deglitch(data->slot[i].detect_pin, + 1); + } + if (gpio_is_valid(data->slot[i].wp_pin)) + at91_set_gpio_input(data->slot[i].wp_pin, 1); + + if (mmc_id == 0) { /* MCI0 */ + switch (i) { + case 0: /* slot A */ + /* CMD */ + at91_set_A_periph(AT91_PIN_PA1, 1); + /* DAT0, maybe DAT1..DAT3 */ + at91_set_A_periph(AT91_PIN_PA0, 1); + if (data->slot[i].bus_width == 4) { + at91_set_A_periph(AT91_PIN_PA3, 1); + at91_set_A_periph(AT91_PIN_PA4, 1); + at91_set_A_periph(AT91_PIN_PA5, 1); + } + slot_count++; + break; + case 1: /* slot B */ + /* CMD */ + at91_set_A_periph(AT91_PIN_PA16, 1); + /* DAT0, maybe DAT1..DAT3 */ + at91_set_A_periph(AT91_PIN_PA17, 1); + if (data->slot[i].bus_width == 4) { + at91_set_A_periph(AT91_PIN_PA18, 1); + at91_set_A_periph(AT91_PIN_PA19, 1); + at91_set_A_periph(AT91_PIN_PA20, 1); + } + slot_count++; + break; + default: + printk(KERN_ERR + "AT91: SD/MMC slot %d not available\n", i); + break; + } + if (slot_count) { + /* CLK */ + at91_set_A_periph(AT91_PIN_PA12, 0); - /* DAT0, maybe DAT1..DAT3 */ - at91_set_A_periph(AT91_PIN_PA17, 1); - if (data->wire4) { - at91_set_A_periph(AT91_PIN_PA18, 1); - at91_set_A_periph(AT91_PIN_PA19, 1); - at91_set_A_periph(AT91_PIN_PA20, 1); + mmc0_data = *data; + platform_device_register(&at91sam9263_mmc0_device); } - } else { - /* CMD */ - at91_set_A_periph(AT91_PIN_PA1, 1); - - /* DAT0, maybe DAT1..DAT3 */ - at91_set_A_periph(AT91_PIN_PA0, 1); - if (data->wire4) { - at91_set_A_periph(AT91_PIN_PA3, 1); - at91_set_A_periph(AT91_PIN_PA4, 1); - at91_set_A_periph(AT91_PIN_PA5, 1); + } else if (mmc_id == 1) { /* MCI1 */ + switch (i) { + case 0: /* slot A */ + /* CMD */ + at91_set_A_periph(AT91_PIN_PA7, 1); + /* DAT0, maybe DAT1..DAT3 */ + at91_set_A_periph(AT91_PIN_PA8, 1); + if (data->slot[i].bus_width == 4) { + at91_set_A_periph(AT91_PIN_PA9, 1); + at91_set_A_periph(AT91_PIN_PA10, 1); + at91_set_A_periph(AT91_PIN_PA11, 1); + } + slot_count++; + break; + case 1: /* slot B */ + /* CMD */ + at91_set_A_periph(AT91_PIN_PA21, 1); + /* DAT0, maybe DAT1..DAT3 */ + at91_set_A_periph(AT91_PIN_PA22, 1); + if (data->slot[i].bus_width == 4) { + at91_set_A_periph(AT91_PIN_PA23, 1); + at91_set_A_periph(AT91_PIN_PA24, 1); + at91_set_A_periph(AT91_PIN_PA25, 1); + } + slot_count++; + break; + default: + printk(KERN_ERR + "AT91: SD/MMC slot %d not available\n", i); + break; } - } + if (slot_count) { + /* CLK */ + at91_set_A_periph(AT91_PIN_PA6, 0); - mmc0_data = *data; - platform_device_register(&at91sam9263_mmc0_device); - } else { /* MCI1 */ - /* CLK */ - at91_set_A_periph(AT91_PIN_PA6, 0); - - if (data->slot_b) { - /* CMD */ - at91_set_A_periph(AT91_PIN_PA21, 1); - - /* DAT0, maybe DAT1..DAT3 */ - at91_set_A_periph(AT91_PIN_PA22, 1); - if (data->wire4) { - at91_set_A_periph(AT91_PIN_PA23, 1); - at91_set_A_periph(AT91_PIN_PA24, 1); - at91_set_A_periph(AT91_PIN_PA25, 1); - } - } else { - /* CMD */ - at91_set_A_periph(AT91_PIN_PA7, 1); - - /* DAT0, maybe DAT1..DAT3 */ - at91_set_A_periph(AT91_PIN_PA8, 1); - if (data->wire4) { - at91_set_A_periph(AT91_PIN_PA9, 1); - at91_set_A_periph(AT91_PIN_PA10, 1); - at91_set_A_periph(AT91_PIN_PA11, 1); + mmc1_data = *data; + platform_device_register(&at91sam9263_mmc1_device); } } - - mmc1_data = *data; - platform_device_register(&at91sam9263_mmc1_device); } } #else -void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {} +void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {} #endif /* -------------------------------------------------------------------- diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c index b3d365dadef5..1fad22f7e21f 100644 --- a/arch/arm/mach-at91/at91sam9rl_devices.c +++ b/arch/arm/mach-at91/at91sam9rl_devices.c @@ -161,9 +161,9 @@ void __init at91_add_device_usba(struct usba_platform_data *data) {} * MMC / SD * -------------------------------------------------------------------- */ -#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE) +#if IS_ENABLED(CONFIG_MMC_ATMELMCI) static u64 mmc_dmamask = DMA_BIT_MASK(32); -static struct at91_mmc_data mmc_data; +static struct mci_platform_data mmc_data; static struct resource mmc_resources[] = { [0] = { @@ -179,7 +179,7 @@ static struct resource mmc_resources[] = { }; static struct platform_device at91sam9rl_mmc_device = { - .name = "at91_mci", + .name = "atmel_mci", .id = -1, .dev = { .dma_mask = &mmc_dmamask, @@ -190,40 +190,40 @@ static struct platform_device at91sam9rl_mmc_device = { .num_resources = ARRAY_SIZE(mmc_resources), }; -void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) +void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) { if (!data) return; - /* input/irq */ - if (gpio_is_valid(data->det_pin)) { - at91_set_gpio_input(data->det_pin, 1); - at91_set_deglitch(data->det_pin, 1); - } - if (gpio_is_valid(data->wp_pin)) - at91_set_gpio_input(data->wp_pin, 1); - if (gpio_is_valid(data->vcc_pin)) - at91_set_gpio_output(data->vcc_pin, 0); - - /* CLK */ - at91_set_A_periph(AT91_PIN_PA2, 0); - - /* CMD */ - at91_set_A_periph(AT91_PIN_PA1, 1); - - /* DAT0, maybe DAT1..DAT3 */ - at91_set_A_periph(AT91_PIN_PA0, 1); - if (data->wire4) { - at91_set_A_periph(AT91_PIN_PA3, 1); - at91_set_A_periph(AT91_PIN_PA4, 1); - at91_set_A_periph(AT91_PIN_PA5, 1); + if (data->slot[0].bus_width) { + /* input/irq */ + if (gpio_is_valid(data->slot[0].detect_pin)) { + at91_set_gpio_input(data->slot[0].detect_pin, 1); + at91_set_deglitch(data->slot[0].detect_pin, 1); + } + if (gpio_is_valid(data->slot[0].wp_pin)) + at91_set_gpio_input(data->slot[0].wp_pin, 1); + + /* CLK */ + at91_set_A_periph(AT91_PIN_PA2, 0); + + /* CMD */ + at91_set_A_periph(AT91_PIN_PA1, 1); + + /* DAT0, maybe DAT1..DAT3 */ + at91_set_A_periph(AT91_PIN_PA0, 1); + if (data->slot[0].bus_width == 4) { + at91_set_A_periph(AT91_PIN_PA3, 1); + at91_set_A_periph(AT91_PIN_PA4, 1); + at91_set_A_periph(AT91_PIN_PA5, 1); + } + + mmc_data = *data; + platform_device_register(&at91sam9rl_mmc_device); } - - mmc_data = *data; - platform_device_register(&at91sam9rl_mmc_device); } #else -void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {} +void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {} #endif diff --git a/arch/arm/mach-at91/board-afeb-9260v1.c b/arch/arm/mach-at91/board-afeb-9260v1.c index de7be1931817..93a832f70232 100644 --- a/arch/arm/mach-at91/board-afeb-9260v1.c +++ b/arch/arm/mach-at91/board-afeb-9260v1.c @@ -133,12 +133,12 @@ static struct atmel_nand_data __initdata afeb9260_nand_data = { /* * MCI (SD/MMC) */ -static struct at91_mmc_data __initdata afeb9260_mmc_data = { - .det_pin = AT91_PIN_PC9, - .wp_pin = AT91_PIN_PC4, - .slot_b = 1, - .wire4 = 1, - .vcc_pin = -EINVAL, +static struct mci_platform_data __initdata afeb9260_mci0_data = { + .slot[1] = { + .bus_width = 4, + .detect_pin = AT91_PIN_PC9, + .wp_pin = AT91_PIN_PC4, + }, }; @@ -199,7 +199,7 @@ static void __init afeb9260_board_init(void) at91_set_B_periph(AT91_PIN_PA10, 0); /* ETX2 */ at91_set_B_periph(AT91_PIN_PA11, 0); /* ETX3 */ /* MMC */ - at91_add_device_mmc(0, &afeb9260_mmc_data); + at91_add_device_mci(0, &afeb9260_mci0_data); /* I2C */ at91_add_device_i2c(afeb9260_i2c_devices, ARRAY_SIZE(afeb9260_i2c_devices)); diff --git a/arch/arm/mach-at91/board-carmeva.c b/arch/arm/mach-at91/board-carmeva.c index a5b002f32a61..71d8f362a1d5 100644 --- a/arch/arm/mach-at91/board-carmeva.c +++ b/arch/arm/mach-at91/board-carmeva.c @@ -71,12 +71,12 @@ static struct at91_udc_data __initdata carmeva_udc_data = { // .vcc_pin = -EINVAL, // }; -static struct at91_mmc_data __initdata carmeva_mmc_data = { - .slot_b = 0, - .wire4 = 1, - .det_pin = AT91_PIN_PB10, - .wp_pin = AT91_PIN_PC14, - .vcc_pin = -EINVAL, +static struct mci_platform_data __initdata carmeva_mci0_data = { + .slot[0] = { + .bus_width = 4, + .detect_pin = AT91_PIN_PB10, + .wp_pin = AT91_PIN_PC14, + }, }; static struct spi_board_info carmeva_spi_devices[] = { @@ -150,7 +150,7 @@ static void __init carmeva_board_init(void) /* Compact Flash */ // at91_add_device_cf(&carmeva_cf_data); /* MMC */ - at91_add_device_mmc(0, &carmeva_mmc_data); + at91_add_device_mci(0, &carmeva_mci0_data); /* LEDs */ at91_gpio_leds(carmeva_leds, ARRAY_SIZE(carmeva_leds)); } diff --git a/arch/arm/mach-at91/board-cpu9krea.c b/arch/arm/mach-at91/board-cpu9krea.c index ecbc13b594de..e71c473316e3 100644 --- a/arch/arm/mach-at91/board-cpu9krea.c +++ b/arch/arm/mach-at91/board-cpu9krea.c @@ -254,8 +254,7 @@ static struct gpio_led cpu9krea_leds[] = { static struct i2c_board_info __initdata cpu9krea_i2c_devices[] = { { - I2C_BOARD_INFO("rtc-ds1307", 0x68), - .type = "ds1339", + I2C_BOARD_INFO("ds1339", 0x68), }, }; @@ -312,12 +311,12 @@ static void __init cpu9krea_add_device_buttons(void) /* * MCI (SD/MMC) */ -static struct at91_mmc_data __initdata cpu9krea_mmc_data = { - .slot_b = 0, - .wire4 = 1, - .det_pin = AT91_PIN_PA29, - .wp_pin = -EINVAL, - .vcc_pin = -EINVAL, +static struct mci_platform_data __initdata cpu9krea_mci0_data = { + .slot[0] = { + .bus_width = 4, + .detect_pin = AT91_PIN_PA29, + .wp_pin = -EINVAL, + }, }; static void __init cpu9krea_board_init(void) @@ -359,7 +358,7 @@ static void __init cpu9krea_board_init(void) /* Ethernet */ at91_add_device_eth(&cpu9krea_macb_data); /* MMC */ - at91_add_device_mmc(0, &cpu9krea_mmc_data); + at91_add_device_mci(0, &cpu9krea_mci0_data); /* I2C */ at91_add_device_i2c(cpu9krea_i2c_devices, ARRAY_SIZE(cpu9krea_i2c_devices)); diff --git a/arch/arm/mach-at91/board-cpuat91.c b/arch/arm/mach-at91/board-cpuat91.c index 2e6d043c82f2..2cbd1a2b6c35 100644 --- a/arch/arm/mach-at91/board-cpuat91.c +++ b/arch/arm/mach-at91/board-cpuat91.c @@ -78,11 +78,12 @@ static struct at91_udc_data __initdata cpuat91_udc_data = { .pullup_pin = AT91_PIN_PC14, }; -static struct at91_mmc_data __initdata cpuat91_mmc_data = { - .det_pin = AT91_PIN_PC2, - .wire4 = 1, - .wp_pin = -EINVAL, - .vcc_pin = -EINVAL, +static struct mci_platform_data __initdata cpuat91_mci0_data = { + .slot[0] = { + .bus_width = 4, + .detect_pin = AT91_PIN_PC2, + .wp_pin = -EINVAL, + }, }; static struct physmap_flash_data cpuat91_flash_data = { @@ -168,7 +169,7 @@ static void __init cpuat91_board_init(void) /* USB Device */ at91_add_device_udc(&cpuat91_udc_data); /* MMC */ - at91_add_device_mmc(0, &cpuat91_mmc_data); + at91_add_device_mci(0, &cpuat91_mci0_data); /* I2C */ at91_add_device_i2c(NULL, 0); /* Platform devices */ diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c index 462bc319cbc5..3e37437a7a61 100644 --- a/arch/arm/mach-at91/board-csb337.c +++ b/arch/arm/mach-at91/board-csb337.c @@ -87,12 +87,12 @@ static struct at91_cf_data __initdata csb337_cf_data = { .rst_pin = AT91_PIN_PD2, }; -static struct at91_mmc_data __initdata csb337_mmc_data = { - .det_pin = AT91_PIN_PD5, - .slot_b = 0, - .wire4 = 1, - .wp_pin = AT91_PIN_PD6, - .vcc_pin = -EINVAL, +static struct mci_platform_data __initdata csb337_mci0_data = { + .slot[0] = { + .bus_width = 4, + .detect_pin = AT91_PIN_PD5, + .wp_pin = AT91_PIN_PD6, + }, }; static struct spi_board_info csb337_spi_devices[] = { @@ -220,8 +220,6 @@ static struct gpio_led csb_leds[] = { static void __init csb337_board_init(void) { - /* Setup the LEDs */ - at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1); /* Serial */ /* DBGU on ttyS0 */ at91_register_uart(0, 0, 0); @@ -240,7 +238,7 @@ static void __init csb337_board_init(void) /* SPI */ at91_add_device_spi(csb337_spi_devices, ARRAY_SIZE(csb337_spi_devices)); /* MMC */ - at91_add_device_mmc(0, &csb337_mmc_data); + at91_add_device_mci(0, &csb337_mci0_data); /* NOR flash */ platform_device_register(&csb_flash); /* LEDs */ diff --git a/arch/arm/mach-at91/board-eb9200.c b/arch/arm/mach-at91/board-eb9200.c index d1e1f3fc0a47..0cfac16ee9d5 100644 --- a/arch/arm/mach-at91/board-eb9200.c +++ b/arch/arm/mach-at91/board-eb9200.c @@ -70,12 +70,12 @@ static struct at91_cf_data __initdata eb9200_cf_data = { .rst_pin = AT91_PIN_PC5, }; -static struct at91_mmc_data __initdata eb9200_mmc_data = { - .slot_b = 0, - .wire4 = 1, - .det_pin = -EINVAL, - .wp_pin = -EINVAL, - .vcc_pin = -EINVAL, +static struct mci_platform_data __initdata eb9200_mci0_data = { + .slot[0] = { + .bus_width = 4, + .detect_pin = -EINVAL, + .wp_pin = -EINVAL, + }, }; static struct i2c_board_info __initdata eb9200_i2c_devices[] = { @@ -113,7 +113,7 @@ static void __init eb9200_board_init(void) at91_add_device_spi(NULL, 0); /* MMC */ /* only supports 1 or 4 bit interface, not wired through to SPI */ - at91_add_device_mmc(0, &eb9200_mmc_data); + at91_add_device_mci(0, &eb9200_mci0_data); } MACHINE_START(ATEB9200, "Embest ATEB9200") diff --git a/arch/arm/mach-at91/board-ecbat91.c b/arch/arm/mach-at91/board-ecbat91.c index 9c24cb25707c..3d931ffac4bf 100644 --- a/arch/arm/mach-at91/board-ecbat91.c +++ b/arch/arm/mach-at91/board-ecbat91.c @@ -64,12 +64,12 @@ static struct at91_usbh_data __initdata ecb_at91usbh_data = { .overcurrent_pin= {-EINVAL, -EINVAL}, }; -static struct at91_mmc_data __initdata ecb_at91mmc_data = { - .slot_b = 0, - .wire4 = 1, - .det_pin = -EINVAL, - .wp_pin = -EINVAL, - .vcc_pin = -EINVAL, +static struct mci_platform_data __initdata ecbat91_mci0_data = { + .slot[0] = { + .bus_width = 4, + .detect_pin = -EINVAL, + .wp_pin = -EINVAL, + }, }; @@ -138,11 +138,20 @@ static struct spi_board_info __initdata ecb_at91spi_devices[] = { }, }; +/* + * LEDs + */ +static struct gpio_led ecb_leds[] = { + { /* D1 */ + .name = "led1", + .gpio = AT91_PIN_PC7, + .active_low = 1, + .default_trigger = "heartbeat", + } +}; + static void __init ecb_at91board_init(void) { - /* Setup the LEDs */ - at91_init_leds(AT91_PIN_PC7, AT91_PIN_PC7); - /* Serial */ /* DBGU on ttyS0. (Rx & Tx only) */ at91_register_uart(0, 0, 0); @@ -161,10 +170,13 @@ static void __init ecb_at91board_init(void) at91_add_device_i2c(NULL, 0); /* MMC */ - at91_add_device_mmc(0, &ecb_at91mmc_data); + at91_add_device_mci(0, &ecbat91_mci0_data); /* SPI */ at91_add_device_spi(ecb_at91spi_devices, ARRAY_SIZE(ecb_at91spi_devices)); + + /* LEDs */ + at91_gpio_leds(ecb_leds, ARRAY_SIZE(ecb_leds)); } MACHINE_START(ECBAT91, "emQbit's ECB_AT91") diff --git a/arch/arm/mach-at91/board-eco920.c b/arch/arm/mach-at91/board-eco920.c index 82bdfde3405f..d93658a2b128 100644 --- a/arch/arm/mach-at91/board-eco920.c +++ b/arch/arm/mach-at91/board-eco920.c @@ -56,12 +56,12 @@ static struct at91_udc_data __initdata eco920_udc_data = { .pullup_pin = AT91_PIN_PB13, }; -static struct at91_mmc_data __initdata eco920_mmc_data = { - .slot_b = 0, - .wire4 = 0, - .det_pin = -EINVAL, - .wp_pin = -EINVAL, - .vcc_pin = -EINVAL, +static struct mci_platform_data __initdata eco920_mci0_data = { + .slot[0] = { + .bus_width = 1, + .detect_pin = -EINVAL, + .wp_pin = -EINVAL, + }, }; static struct physmap_flash_data eco920_flash_data = { @@ -93,10 +93,26 @@ static struct spi_board_info eco920_spi_devices[] = { }, }; +/* + * LEDs + */ +static struct gpio_led eco920_leds[] = { + { /* D1 */ + .name = "led1", + .gpio = AT91_PIN_PB0, + .active_low = 1, + .default_trigger = "heartbeat", + }, + { /* D2 */ + .name = "led2", + .gpio = AT91_PIN_PB1, + .active_low = 1, + .default_trigger = "timer", + } +}; + static void __init eco920_board_init(void) { - /* Setup the LEDs */ - at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1); /* DBGU on ttyS0. (Rx & Tx only */ at91_register_uart(0, 0, 0); at91_add_device_serial(); @@ -104,7 +120,7 @@ static void __init eco920_board_init(void) at91_add_device_usbh(&eco920_usbh_data); at91_add_device_udc(&eco920_udc_data); - at91_add_device_mmc(0, &eco920_mmc_data); + at91_add_device_mci(0, &eco920_mci0_data); platform_device_register(&eco920_flash); at91_ramc_write(0, AT91_SMC_CSR(7), AT91_SMC_RWHOLD_(1) @@ -127,6 +143,8 @@ static void __init eco920_board_init(void) ); at91_add_device_spi(eco920_spi_devices, ARRAY_SIZE(eco920_spi_devices)); + /* LEDs */ + at91_gpio_leds(eco920_leds, ARRAY_SIZE(eco920_leds)); } MACHINE_START(ECO920, "eco920") diff --git a/arch/arm/mach-at91/board-flexibity.c b/arch/arm/mach-at91/board-flexibity.c index 6cc83a87d77c..fa98abacb1ba 100644 --- a/arch/arm/mach-at91/board-flexibity.c +++ b/arch/arm/mach-at91/board-flexibity.c @@ -75,12 +75,12 @@ static struct spi_board_info flexibity_spi_devices[] = { }; /* MCI (SD/MMC) */ -static struct at91_mmc_data __initdata flexibity_mmc_data = { - .slot_b = 0, - .wire4 = 1, - .det_pin = AT91_PIN_PC9, - .wp_pin = AT91_PIN_PC4, - .vcc_pin = -EINVAL, +static struct mci_platform_data __initdata flexibity_mci0_data = { + .slot[0] = { + .bus_width = 4, + .detect_pin = AT91_PIN_PC9, + .wp_pin = AT91_PIN_PC4, + }, }; /* LEDs */ @@ -152,7 +152,7 @@ static void __init flexibity_board_init(void) at91_add_device_spi(flexibity_spi_devices, ARRAY_SIZE(flexibity_spi_devices)); /* MMC */ - at91_add_device_mmc(0, &flexibity_mmc_data); + at91_add_device_mci(0, &flexibity_mci0_data); /* LEDs */ at91_gpio_leds(flexibity_leds, ARRAY_SIZE(flexibity_leds)); } diff --git a/arch/arm/mach-at91/board-foxg20.c b/arch/arm/mach-at91/board-foxg20.c index 69ab1247ef81..6e47071d8206 100644 --- a/arch/arm/mach-at91/board-foxg20.c +++ b/arch/arm/mach-at91/board-foxg20.c @@ -86,7 +86,7 @@ static struct at91_udc_data __initdata foxg20_udc_data = { * SPI devices. */ static struct spi_board_info foxg20_spi_devices[] = { -#if !defined(CONFIG_MMC_AT91) +#if !IS_ENABLED(CONFIG_MMC_ATMELMCI) { .modalias = "mtd_dataflash", .chip_select = 1, @@ -109,12 +109,12 @@ static struct macb_platform_data __initdata foxg20_macb_data = { * MCI (SD/MMC) * det_pin, wp_pin and vcc_pin are not connected */ -static struct at91_mmc_data __initdata foxg20_mmc_data = { - .slot_b = 1, - .wire4 = 1, - .det_pin = -EINVAL, - .wp_pin = -EINVAL, - .vcc_pin = -EINVAL, +static struct mci_platform_data __initdata foxg20_mci0_data = { + .slot[1] = { + .bus_width = 4, + .detect_pin = -EINVAL, + .wp_pin = -EINVAL, + }, }; @@ -247,7 +247,7 @@ static void __init foxg20_board_init(void) /* Ethernet */ at91_add_device_eth(&foxg20_macb_data); /* MMC */ - at91_add_device_mmc(0, &foxg20_mmc_data); + at91_add_device_mci(0, &foxg20_mci0_data); /* I2C */ at91_add_device_i2c(foxg20_i2c_devices, ARRAY_SIZE(foxg20_i2c_devices)); /* LEDs */ diff --git a/arch/arm/mach-at91/board-kafa.c b/arch/arm/mach-at91/board-kafa.c index 64c1dbf88a07..86050da3ba53 100644 --- a/arch/arm/mach-at91/board-kafa.c +++ b/arch/arm/mach-at91/board-kafa.c @@ -66,11 +66,20 @@ static struct at91_udc_data __initdata kafa_udc_data = { .pullup_pin = AT91_PIN_PB7, }; +/* + * LEDs + */ +static struct gpio_led kafa_leds[] = { + { /* D1 */ + .name = "led1", + .gpio = AT91_PIN_PB4, + .active_low = 1, + .default_trigger = "heartbeat", + }, +}; + static void __init kafa_board_init(void) { - /* Set up the LEDs */ - at91_init_leds(AT91_PIN_PB4, AT91_PIN_PB4); - /* Serial */ /* DBGU on ttyS0. (Rx & Tx only) */ at91_register_uart(0, 0, 0); @@ -88,6 +97,8 @@ static void __init kafa_board_init(void) at91_add_device_i2c(NULL, 0); /* SPI */ at91_add_device_spi(NULL, 0); + /* LEDs */ + at91_gpio_leds(kafa_leds, ARRAY_SIZE(kafa_leds)); } MACHINE_START(KAFA, "Sperry-Sun KAFA") diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c index 5d96cb85175f..abe9fed7a3e0 100644 --- a/arch/arm/mach-at91/board-kb9202.c +++ b/arch/arm/mach-at91/board-kb9202.c @@ -69,12 +69,12 @@ static struct at91_udc_data __initdata kb9202_udc_data = { .pullup_pin = AT91_PIN_PB22, }; -static struct at91_mmc_data __initdata kb9202_mmc_data = { - .det_pin = AT91_PIN_PB2, - .slot_b = 0, - .wire4 = 1, - .wp_pin = -EINVAL, - .vcc_pin = -EINVAL, +static struct mci_platform_data __initdata kb9202_mci0_data = { + .slot[0] = { + .bus_width = 4, + .detect_pin = AT91_PIN_PB2, + .wp_pin = -EINVAL, + }, }; static struct mtd_partition __initdata kb9202_nand_partition[] = { @@ -96,11 +96,26 @@ static struct atmel_nand_data __initdata kb9202_nand_data = { .num_parts = ARRAY_SIZE(kb9202_nand_partition), }; +/* + * LEDs + */ +static struct gpio_led kb9202_leds[] = { + { /* D1 */ + .name = "led1", + .gpio = AT91_PIN_PC19, + .active_low = 1, + .default_trigger = "heartbeat", + }, + { /* D2 */ + .name = "led2", + .gpio = AT91_PIN_PC18, + .active_low = 1, + .default_trigger = "timer", + } +}; + static void __init kb9202_board_init(void) { - /* Set up the LEDs */ - at91_init_leds(AT91_PIN_PC19, AT91_PIN_PC18); - /* Serial */ /* DBGU on ttyS0. (Rx & Tx only) */ at91_register_uart(0, 0, 0); @@ -121,13 +136,15 @@ static void __init kb9202_board_init(void) /* USB Device */ at91_add_device_udc(&kb9202_udc_data); /* MMC */ - at91_add_device_mmc(0, &kb9202_mmc_data); + at91_add_device_mci(0, &kb9202_mci0_data); /* I2C */ at91_add_device_i2c(NULL, 0); /* SPI */ at91_add_device_spi(NULL, 0); /* NAND */ at91_add_device_nand(&kb9202_nand_data); + /* LEDs */ + at91_gpio_leds(kb9202_leds, ARRAY_SIZE(kb9202_leds)); } MACHINE_START(KB9200, "KB920x") diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c index 18103c5d993c..9cda3fd346ae 100644 --- a/arch/arm/mach-at91/board-neocore926.c +++ b/arch/arm/mach-at91/board-neocore926.c @@ -138,11 +138,12 @@ static struct spi_board_info neocore926_spi_devices[] = { /* * MCI (SD/MMC) */ -static struct at91_mmc_data __initdata neocore926_mmc_data = { - .wire4 = 1, - .det_pin = AT91_PIN_PE18, - .wp_pin = AT91_PIN_PE19, - .vcc_pin = -EINVAL, +static struct mci_platform_data __initdata neocore926_mci0_data = { + .slot[0] = { + .bus_width = 4, + .detect_pin = AT91_PIN_PE18, + .wp_pin = AT91_PIN_PE19, + }, }; @@ -354,7 +355,7 @@ static void __init neocore926_board_init(void) neocore926_add_device_ts(); /* MMC */ - at91_add_device_mmc(1, &neocore926_mmc_data); + at91_add_device_mci(0, &neocore926_mci0_data); /* Ethernet */ at91_add_device_eth(&neocore926_macb_data); diff --git a/arch/arm/mach-at91/board-picotux200.c b/arch/arm/mach-at91/board-picotux200.c index 127065504508..f83e1de699e6 100644 --- a/arch/arm/mach-at91/board-picotux200.c +++ b/arch/arm/mach-at91/board-picotux200.c @@ -62,12 +62,12 @@ static struct at91_usbh_data __initdata picotux200_usbh_data = { .overcurrent_pin= {-EINVAL, -EINVAL}, }; -static struct at91_mmc_data __initdata picotux200_mmc_data = { - .det_pin = AT91_PIN_PB27, - .slot_b = 0, - .wire4 = 1, - .wp_pin = AT91_PIN_PA17, - .vcc_pin = -EINVAL, +static struct mci_platform_data __initdata picotux200_mci0_data = { + .slot[0] = { + .bus_width = 4, + .detect_pin = AT91_PIN_PB27, + .wp_pin = AT91_PIN_PA17, + }, }; #define PICOTUX200_FLASH_BASE AT91_CHIPSELECT_0 @@ -112,7 +112,7 @@ static void __init picotux200_board_init(void) at91_add_device_i2c(NULL, 0); /* MMC */ at91_set_gpio_output(AT91_PIN_PB22, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */ - at91_add_device_mmc(0, &picotux200_mmc_data); + at91_add_device_mci(0, &picotux200_mci0_data); /* NOR Flash */ platform_device_register(&picotux200_flash); } diff --git a/arch/arm/mach-at91/board-qil-a9260.c b/arch/arm/mach-at91/board-qil-a9260.c index bf351e285422..799f214edebe 100644 --- a/arch/arm/mach-at91/board-qil-a9260.c +++ b/arch/arm/mach-at91/board-qil-a9260.c @@ -156,12 +156,12 @@ static void __init ek_add_device_nand(void) /* * MCI (SD/MMC) */ -static struct at91_mmc_data __initdata ek_mmc_data = { - .slot_b = 0, - .wire4 = 1, - .det_pin = -EINVAL, - .wp_pin = -EINVAL, - .vcc_pin = -EINVAL, +static struct mci_platform_data __initdata ek_mci0_data = { + .slot[0] = { + .bus_width = 4, + .detect_pin = -EINVAL, + .wp_pin = -EINVAL, + }, }; /* @@ -245,7 +245,7 @@ static void __init ek_board_init(void) /* Ethernet */ at91_add_device_eth(&ek_macb_data); /* MMC */ - at91_add_device_mmc(0, &ek_mmc_data); + at91_add_device_mci(0, &ek_mci0_data); /* Push Buttons */ ek_add_device_buttons(); /* LEDs */ diff --git a/arch/arm/mach-at91/board-rm9200dk.c b/arch/arm/mach-at91/board-rm9200dk.c index cc2bf9796073..66338e7ebfba 100644 --- a/arch/arm/mach-at91/board-rm9200dk.c +++ b/arch/arm/mach-at91/board-rm9200dk.c @@ -77,12 +77,12 @@ static struct at91_cf_data __initdata dk_cf_data = { }; #ifndef CONFIG_MTD_AT91_DATAFLASH_CARD -static struct at91_mmc_data __initdata dk_mmc_data = { - .slot_b = 0, - .wire4 = 1, - .det_pin = -EINVAL, - .wp_pin = -EINVAL, - .vcc_pin = -EINVAL, +static struct mci_platform_data __initdata dk_mci0_data = { + .slot[0] = { + .bus_width = 4, + .detect_pin = -EINVAL, + .wp_pin = -EINVAL, + }, }; #endif @@ -177,9 +177,6 @@ static struct gpio_led dk_leds[] = { static void __init dk_board_init(void) { - /* Setup the LEDs */ - at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2); - /* Serial */ /* DBGU on ttyS0. (Rx & Tx only) */ at91_register_uart(0, 0, 0); @@ -208,7 +205,7 @@ static void __init dk_board_init(void) #else /* MMC */ at91_set_gpio_output(AT91_PIN_PB7, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */ - at91_add_device_mmc(0, &dk_mmc_data); + at91_add_device_mci(0, &dk_mci0_data); #endif /* NAND */ at91_add_device_nand(&dk_nand_data); diff --git a/arch/arm/mach-at91/board-rm9200ek.c b/arch/arm/mach-at91/board-rm9200ek.c index 62e19e64c9d3..5d1b5729dc69 100644 --- a/arch/arm/mach-at91/board-rm9200ek.c +++ b/arch/arm/mach-at91/board-rm9200ek.c @@ -70,12 +70,12 @@ static struct at91_udc_data __initdata ek_udc_data = { }; #ifndef CONFIG_MTD_AT91_DATAFLASH_CARD -static struct at91_mmc_data __initdata ek_mmc_data = { - .det_pin = AT91_PIN_PB27, - .slot_b = 0, - .wire4 = 1, - .wp_pin = AT91_PIN_PA17, - .vcc_pin = -EINVAL, +static struct mci_platform_data __initdata ek_mci0_data = { + .slot[0] = { + .bus_width = 4, + .detect_pin = AT91_PIN_PB27, + .wp_pin = AT91_PIN_PA17, + } }; #endif @@ -148,9 +148,6 @@ static struct gpio_led ek_leds[] = { static void __init ek_board_init(void) { - /* Setup the LEDs */ - at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2); - /* Serial */ /* DBGU on ttyS0. (Rx & Tx only) */ at91_register_uart(0, 0, 0); @@ -177,7 +174,7 @@ static void __init ek_board_init(void) #else /* MMC */ at91_set_gpio_output(AT91_PIN_PB22, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */ - at91_add_device_mmc(0, &ek_mmc_data); + at91_add_device_mci(0, &ek_mci0_data); #endif /* NOR Flash */ platform_device_register(&ek_flash); diff --git a/arch/arm/mach-at91/board-rsi-ews.c b/arch/arm/mach-at91/board-rsi-ews.c index c3b43aefdb75..a0ecf04e9ae3 100644 --- a/arch/arm/mach-at91/board-rsi-ews.c +++ b/arch/arm/mach-at91/board-rsi-ews.c @@ -58,11 +58,12 @@ static struct at91_usbh_data rsi_ews_usbh_data __initdata = { /* * SD/MC */ -static struct at91_mmc_data rsi_ews_mmc_data __initdata = { - .slot_b = 0, - .wire4 = 1, - .det_pin = AT91_PIN_PB27, - .wp_pin = AT91_PIN_PB29, +static struct mci_platform_data __initdata rsi_ews_mci0_data = { + .slot[0] = { + .bus_width = 4, + .detect_pin = AT91_PIN_PB27, + .wp_pin = AT91_PIN_PB29, + }, }; /* @@ -185,9 +186,6 @@ static struct platform_device rsiews_nor_flash = { */ static void __init rsi_ews_board_init(void) { - /* Setup the LEDs */ - at91_init_leds(AT91_PIN_PB6, AT91_PIN_PB9); - /* Serial */ /* DBGU on ttyS0. (Rx & Tx only) */ /* This one is for debugging */ @@ -215,7 +213,7 @@ static void __init rsi_ews_board_init(void) at91_add_device_spi(rsi_ews_spi_devices, ARRAY_SIZE(rsi_ews_spi_devices)); /* MMC */ - at91_add_device_mmc(0, &rsi_ews_mmc_data); + at91_add_device_mci(0, &rsi_ews_mci0_data); /* NOR Flash */ platform_device_register(&rsiews_nor_flash); /* LEDs */ diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c index 7bf6da70d7d5..c5f01acce3c0 100644 --- a/arch/arm/mach-at91/board-sam9-l9260.c +++ b/arch/arm/mach-at91/board-sam9-l9260.c @@ -73,7 +73,7 @@ static struct at91_udc_data __initdata ek_udc_data = { * SPI devices. */ static struct spi_board_info ek_spi_devices[] = { -#if !defined(CONFIG_MMC_AT91) +#if !IS_ENABLED(CONFIG_MMC_ATMELMCI) { /* DataFlash chip */ .modalias = "mtd_dataflash", .chip_select = 1, @@ -158,19 +158,34 @@ static void __init ek_add_device_nand(void) /* * MCI (SD/MMC) */ -static struct at91_mmc_data __initdata ek_mmc_data = { - .slot_b = 1, - .wire4 = 1, - .det_pin = AT91_PIN_PC8, - .wp_pin = AT91_PIN_PC4, - .vcc_pin = -EINVAL, +static struct mci_platform_data __initdata ek_mci0_data = { + .slot[1] = { + .bus_width = 4, + .detect_pin = AT91_PIN_PC8, + .wp_pin = AT91_PIN_PC4, + }, +}; + +/* + * LEDs + */ +static struct gpio_led ek_leds[] = { + { /* D1 */ + .name = "led1", + .gpio = AT91_PIN_PA9, + .active_low = 1, + .default_trigger = "heartbeat", + }, + { /* D2 */ + .name = "led2", + .gpio = AT91_PIN_PA6, + .active_low = 1, + .default_trigger = "timer", + } }; static void __init ek_board_init(void) { - /* Setup the LEDs */ - at91_init_leds(AT91_PIN_PA9, AT91_PIN_PA6); - /* Serial */ /* DBGU on ttyS0. (Rx & Tx only) */ at91_register_uart(0, 0, 0); @@ -194,9 +209,11 @@ static void __init ek_board_init(void) /* Ethernet */ at91_add_device_eth(&ek_macb_data); /* MMC */ - at91_add_device_mmc(0, &ek_mmc_data); + at91_add_device_mci(0, &ek_mci0_data); /* I2C */ at91_add_device_i2c(NULL, 0); + /* LEDs */ + at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds)); } MACHINE_START(SAM9_L9260, "Olimex SAM9-L9260") diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c index 889c1bf71eb5..8cd6e679fbe0 100644 --- a/arch/arm/mach-at91/board-sam9260ek.c +++ b/arch/arm/mach-at91/board-sam9260ek.c @@ -108,7 +108,7 @@ static void __init at73c213_set_clk(struct at73c213_board_info *info) {} * SPI devices. */ static struct spi_board_info ek_spi_devices[] = { -#if !defined(CONFIG_MMC_AT91) +#if !IS_ENABLED(CONFIG_MMC_ATMELMCI) { /* DataFlash chip */ .modalias = "mtd_dataflash", .chip_select = 1, @@ -211,12 +211,12 @@ static void __init ek_add_device_nand(void) /* * MCI (SD/MMC) */ -static struct at91_mmc_data __initdata ek_mmc_data = { - .slot_b = 1, - .wire4 = 1, - .det_pin = -EINVAL, - .wp_pin = -EINVAL, - .vcc_pin = -EINVAL, +static struct mci_platform_data __initdata ek_mci0_data = { + .slot[1] = { + .bus_width = 4, + .detect_pin = -EINVAL, + .wp_pin = -EINVAL, + }, }; @@ -329,7 +329,7 @@ static void __init ek_board_init(void) /* Ethernet */ at91_add_device_eth(&ek_macb_data); /* MMC */ - at91_add_device_mmc(0, &ek_mmc_data); + at91_add_device_mci(0, &ek_mci0_data); /* I2C */ at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices)); /* SSC (to AT73C213) */ diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c index 2269be5fa384..27b3af1a3047 100644 --- a/arch/arm/mach-at91/board-sam9261ek.c +++ b/arch/arm/mach-at91/board-sam9261ek.c @@ -340,11 +340,12 @@ static struct spi_board_info ek_spi_devices[] = { * MCI (SD/MMC) * det_pin, wp_pin and vcc_pin are not connected */ -static struct at91_mmc_data __initdata ek_mmc_data = { - .wire4 = 1, - .det_pin = -EINVAL, - .wp_pin = -EINVAL, - .vcc_pin = -EINVAL, +static struct mci_platform_data __initdata mci0_data = { + .slot[0] = { + .bus_width = 4, + .detect_pin = -EINVAL, + .wp_pin = -EINVAL, + }, }; #endif /* CONFIG_SPI_ATMEL_* */ @@ -569,9 +570,6 @@ static struct gpio_led ek_leds[] = { static void __init ek_board_init(void) { - /* Setup the LEDs */ - at91_init_leds(AT91_PIN_PA13, AT91_PIN_PA14); - /* Serial */ /* DBGU on ttyS0. (Rx & Tx only) */ at91_register_uart(0, 0, 0); @@ -598,7 +596,7 @@ static void __init ek_board_init(void) at91_add_device_ssc(AT91SAM9261_ID_SSC1, ATMEL_SSC_TX); #else /* MMC */ - at91_add_device_mmc(0, &ek_mmc_data); + at91_add_device_mci(0, &mci0_data); #endif /* LCD Controller */ at91_add_device_lcdc(&ek_lcdc_data); diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c index 82adf581afc2..073e17403d98 100644 --- a/arch/arm/mach-at91/board-sam9263ek.c +++ b/arch/arm/mach-at91/board-sam9263ek.c @@ -141,11 +141,12 @@ static struct spi_board_info ek_spi_devices[] = { /* * MCI (SD/MMC) */ -static struct at91_mmc_data __initdata ek_mmc_data = { - .wire4 = 1, - .det_pin = AT91_PIN_PE18, - .wp_pin = AT91_PIN_PE19, - .vcc_pin = -EINVAL, +static struct mci_platform_data __initdata mci1_data = { + .slot[0] = { + .bus_width = 4, + .detect_pin = AT91_PIN_PE18, + .wp_pin = AT91_PIN_PE19, + }, }; @@ -420,7 +421,7 @@ static void __init ek_board_init(void) /* Touchscreen */ ek_add_device_ts(); /* MMC */ - at91_add_device_mmc(1, &ek_mmc_data); + at91_add_device_mci(1, &mci1_data); /* Ethernet */ at91_add_device_eth(&ek_macb_data); /* NAND */ diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c index 4ea4ee00364b..3ab2b86a3762 100644 --- a/arch/arm/mach-at91/board-sam9g20ek.c +++ b/arch/arm/mach-at91/board-sam9g20ek.c @@ -92,7 +92,7 @@ static struct at91_udc_data __initdata ek_udc_data = { * SPI devices. */ static struct spi_board_info ek_spi_devices[] = { -#if !(defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_AT91)) +#if !IS_ENABLED(CONFIG_MMC_ATMELMCI) { /* DataFlash chip */ .modalias = "mtd_dataflash", .chip_select = 1, @@ -199,7 +199,6 @@ static void __init ek_add_device_nand(void) * MCI (SD/MMC) * wp_pin and vcc_pin are not connected */ -#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE) static struct mci_platform_data __initdata ek_mmc_data = { .slot[1] = { .bus_width = 4, @@ -208,28 +207,15 @@ static struct mci_platform_data __initdata ek_mmc_data = { }, }; -#else -static struct at91_mmc_data __initdata ek_mmc_data = { - .slot_b = 1, /* Only one slot so use slot B */ - .wire4 = 1, - .det_pin = AT91_PIN_PC9, - .wp_pin = -EINVAL, - .vcc_pin = -EINVAL, -}; -#endif static void __init ek_add_device_mmc(void) { -#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE) if (ek_have_2mmc()) { ek_mmc_data.slot[0].bus_width = 4; ek_mmc_data.slot[0].detect_pin = AT91_PIN_PC2; ek_mmc_data.slot[0].wp_pin = -1; } at91_add_device_mci(0, &ek_mmc_data); -#else - at91_add_device_mmc(0, &ek_mmc_data); -#endif } /* diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c index e7dc3ead7045..fb89ea92e3f2 100644 --- a/arch/arm/mach-at91/board-sam9rlek.c +++ b/arch/arm/mach-at91/board-sam9rlek.c @@ -56,11 +56,12 @@ static struct usba_platform_data __initdata ek_usba_udc_data = { /* * MCI (SD/MMC) */ -static struct at91_mmc_data __initdata ek_mmc_data = { - .wire4 = 1, - .det_pin = AT91_PIN_PA15, - .wp_pin = -EINVAL, - .vcc_pin = -EINVAL, +static struct mci_platform_data __initdata mci0_data = { + .slot[0] = { + .bus_width = 4, + .detect_pin = AT91_PIN_PA15, + .wp_pin = -EINVAL, + }, }; @@ -303,7 +304,7 @@ static void __init ek_board_init(void) /* SPI */ at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices)); /* MMC */ - at91_add_device_mmc(0, &ek_mmc_data); + at91_add_device_mci(0, &mci0_data); /* LCD Controller */ at91_add_device_lcdc(&ek_lcdc_data); /* AC97 */ diff --git a/arch/arm/mach-at91/board-stamp9g20.c b/arch/arm/mach-at91/board-stamp9g20.c index 29eae1626bf7..c3fb31d5116e 100644 --- a/arch/arm/mach-at91/board-stamp9g20.c +++ b/arch/arm/mach-at91/board-stamp9g20.c @@ -83,7 +83,6 @@ static void __init add_device_nand(void) * MCI (SD/MMC) * det_pin, wp_pin and vcc_pin are not connected */ -#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE) static struct mci_platform_data __initdata mmc_data = { .slot[0] = { .bus_width = 4, @@ -91,15 +90,6 @@ static struct mci_platform_data __initdata mmc_data = { .wp_pin = -1, }, }; -#else -static struct at91_mmc_data __initdata mmc_data = { - .slot_b = 0, - .wire4 = 1, - .det_pin = -EINVAL, - .wp_pin = -EINVAL, - .vcc_pin = -EINVAL, -}; -#endif /* @@ -223,11 +213,7 @@ void __init stamp9g20_board_init(void) /* NAND */ add_device_nand(); /* MMC */ -#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE) at91_add_device_mci(0, &mmc_data); -#else - at91_add_device_mmc(0, &mmc_data); -#endif /* W1 */ add_w1(); } diff --git a/arch/arm/mach-at91/board-usb-a926x.c b/arch/arm/mach-at91/board-usb-a926x.c index c1476b9fe7b9..6ea069b57335 100644 --- a/arch/arm/mach-at91/board-usb-a926x.c +++ b/arch/arm/mach-at91/board-usb-a926x.c @@ -109,14 +109,12 @@ static struct mmc_spi_platform_data at91_mmc_spi_pdata = { * SPI devices. */ static struct spi_board_info usb_a9263_spi_devices[] = { -#if !defined(CONFIG_MMC_AT91) { /* DataFlash chip */ .modalias = "mtd_dataflash", .chip_select = 0, .max_speed_hz = 15 * 1000 * 1000, .bus_num = 0, } -#endif }; static struct spi_board_info usb_a9g20_spi_devices[] = { diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c index 516d340549d8..f162fdfd66eb 100644 --- a/arch/arm/mach-at91/board-yl-9200.c +++ b/arch/arm/mach-at91/board-yl-9200.c @@ -119,11 +119,12 @@ static struct at91_udc_data __initdata yl9200_udc_data = { /* * MMC */ -static struct at91_mmc_data __initdata yl9200_mmc_data = { - .det_pin = AT91_PIN_PB9, - .wire4 = 1, - .wp_pin = -EINVAL, - .vcc_pin = -EINVAL, +static struct mci_platform_data __initdata yl9200_mci0_data = { + .slot[0] = { + .bus_width = 4, + .detect_pin = AT91_PIN_PB9, + .wp_pin = -EINVAL, + }, }; /* @@ -541,9 +542,6 @@ void __init yl9200_add_device_video(void) {} static void __init yl9200_board_init(void) { - /* Setup the LEDs D2=PB17 (timer), D3=PB16 (cpu) */ - at91_init_leds(AT91_PIN_PB16, AT91_PIN_PB17); - /* Serial */ /* DBGU on ttyS0. (Rx & Tx only) */ at91_register_uart(0, 0, 0); @@ -568,7 +566,7 @@ static void __init yl9200_board_init(void) /* I2C */ at91_add_device_i2c(yl9200_i2c_devices, ARRAY_SIZE(yl9200_i2c_devices)); /* MMC */ - at91_add_device_mmc(0, &yl9200_mmc_data); + at91_add_device_mci(0, &yl9200_mci0_data); /* NAND */ at91_add_device_nand(&yl9200_nand_data); /* NOR Flash */ diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h index 369afc2ffc5b..c55a4364ffb4 100644 --- a/arch/arm/mach-at91/include/mach/board.h +++ b/arch/arm/mach-at91/include/mach/board.h @@ -187,7 +187,6 @@ struct at91_can_data { extern void __init at91_add_device_can(struct at91_can_data *data); /* LEDs */ -extern void __init at91_init_leds(u8 cpu_led, u8 timer_led); extern void __init at91_gpio_leds(struct gpio_led *leds, int nr); extern void __init at91_pwm_leds(struct gpio_led *leds, int nr); diff --git a/arch/arm/mach-at91/leds.c b/arch/arm/mach-at91/leds.c index 8dfafe76ffe6..1b1e62b5f41b 100644 --- a/arch/arm/mach-at91/leds.c +++ b/arch/arm/mach-at91/leds.c @@ -90,108 +90,3 @@ void __init at91_pwm_leds(struct gpio_led *leds, int nr) #else void __init at91_pwm_leds(struct gpio_led *leds, int nr){} #endif - - -/* ------------------------------------------------------------------------- */ - -#if defined(CONFIG_LEDS) - -#include <asm/leds.h> - -/* - * Old ARM-specific LED framework; not fully functional when generic time is - * in use. - */ - -static u8 at91_leds_cpu; -static u8 at91_leds_timer; - -static inline void at91_led_on(unsigned int led) -{ - at91_set_gpio_value(led, 0); -} - -static inline void at91_led_off(unsigned int led) -{ - at91_set_gpio_value(led, 1); -} - -static inline void at91_led_toggle(unsigned int led) -{ - unsigned long is_off = at91_get_gpio_value(led); - if (is_off) - at91_led_on(led); - else - at91_led_off(led); -} - - -/* - * Handle LED events. - */ -static void at91_leds_event(led_event_t evt) -{ - unsigned long flags; - - local_irq_save(flags); - - switch(evt) { - case led_start: /* System startup */ - at91_led_on(at91_leds_cpu); - break; - - case led_stop: /* System stop / suspend */ - at91_led_off(at91_leds_cpu); - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: /* Every 50 timer ticks */ - at91_led_toggle(at91_leds_timer); - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: /* Entering idle state */ - at91_led_off(at91_leds_cpu); - break; - - case led_idle_end: /* Exit idle state */ - at91_led_on(at91_leds_cpu); - break; -#endif - - default: - break; - } - - local_irq_restore(flags); -} - - -static int __init leds_init(void) -{ - if (!at91_leds_timer || !at91_leds_cpu) - return -ENODEV; - - leds_event = at91_leds_event; - - leds_event(led_start); - return 0; -} - -__initcall(leds_init); - - -void __init at91_init_leds(u8 cpu_led, u8 timer_led) -{ - /* Enable GPIO to access the LEDs */ - at91_set_gpio_output(cpu_led, 1); - at91_set_gpio_output(timer_led, 1); - - at91_leds_cpu = cpu_led; - at91_leds_timer = timer_led; -} - -#else -void __init at91_init_leds(u8 cpu_led, u8 timer_led) {} -#endif diff --git a/arch/arm/mach-clps711x/Makefile b/arch/arm/mach-clps711x/Makefile index aed9eb664499..6da6940b3656 100644 --- a/arch/arm/mach-clps711x/Makefile +++ b/arch/arm/mach-clps711x/Makefile @@ -15,5 +15,3 @@ obj-$(CONFIG_ARCH_CLEP7312) += clep7312.o obj-$(CONFIG_ARCH_EDB7211) += edb7211-arch.o edb7211-mm.o obj-$(CONFIG_ARCH_FORTUNET) += fortunet.o obj-$(CONFIG_ARCH_P720T) += p720t.o -leds-$(CONFIG_ARCH_P720T) += p720t-leds.o -obj-$(CONFIG_LEDS) += $(leds-y) diff --git a/arch/arm/mach-clps711x/p720t-leds.c b/arch/arm/mach-clps711x/p720t-leds.c deleted file mode 100644 index bbc449fbe14a..000000000000 --- a/arch/arm/mach-clps711x/p720t-leds.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * linux/arch/arm/mach-clps711x/leds.c - * - * Integrator LED control routines - * - * Copyright (C) 2000 Deep Blue Solutions Ltd - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/io.h> - -#include <mach/hardware.h> -#include <asm/leds.h> -#include <asm/mach-types.h> - -static void p720t_leds_event(led_event_t ledevt) -{ - unsigned long flags; - u32 pddr; - - local_irq_save(flags); - switch(ledevt) { - case led_idle_start: - break; - - case led_idle_end: - break; - - case led_timer: - pddr = clps_readb(PDDR); - clps_writeb(pddr ^ 1, PDDR); - break; - - default: - break; - } - - local_irq_restore(flags); -} - -static int __init leds_init(void) -{ - if (machine_is_p720t()) - leds_event = p720t_leds_event; - - return 0; -} - -arch_initcall(leds_init); diff --git a/arch/arm/mach-clps711x/p720t.c b/arch/arm/mach-clps711x/p720t.c index f266d90b9efc..b752b586fc2f 100644 --- a/arch/arm/mach-clps711x/p720t.c +++ b/arch/arm/mach-clps711x/p720t.c @@ -23,6 +23,8 @@ #include <linux/string.h> #include <linux/mm.h> #include <linux/io.h> +#include <linux/slab.h> +#include <linux/leds.h> #include <mach/hardware.h> #include <asm/pgtable.h> @@ -34,6 +36,8 @@ #include <asm/mach/map.h> #include <mach/syspld.h> +#include <asm/hardware/clps7111.h> + #include "common.h" /* @@ -107,6 +111,64 @@ static void __init p720t_init_early(void) } } +/* + * LED controled by CPLD + */ +#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) +static void p720t_led_set(struct led_classdev *cdev, + enum led_brightness b) +{ + u8 reg = clps_readb(PDDR); + + if (b != LED_OFF) + reg |= 0x1; + else + reg &= ~0x1; + + clps_writeb(reg, PDDR); +} + +static enum led_brightness p720t_led_get(struct led_classdev *cdev) +{ + u8 reg = clps_readb(PDDR); + + return (reg & 0x1) ? LED_FULL : LED_OFF; +} + +static int __init p720t_leds_init(void) +{ + + struct led_classdev *cdev; + int ret; + + if (!machine_is_p720t()) + return -ENODEV; + + cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); + if (!cdev) + return -ENOMEM; + + cdev->name = "p720t:0"; + cdev->brightness_set = p720t_led_set; + cdev->brightness_get = p720t_led_get; + cdev->default_trigger = "heartbeat"; + + ret = led_classdev_register(NULL, cdev); + if (ret < 0) { + kfree(cdev); + return ret; + } + + return 0; +} + +/* + * Since we may have triggers on any subsystem, defer registration + * until after subsystem_init. + */ +fs_initcall(p720t_leds_init); +#endif + MACHINE_START(P720T, "ARM-Prospector720T") /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */ .atag_offset = 0x100, diff --git a/arch/arm/mach-ebsa110/Makefile b/arch/arm/mach-ebsa110/Makefile index 6520ac835802..935e4af01a27 100644 --- a/arch/arm/mach-ebsa110/Makefile +++ b/arch/arm/mach-ebsa110/Makefile @@ -4,9 +4,7 @@ # Object file lists. -obj-y := core.o io.o +obj-y := core.o io.o leds.o obj-m := obj-n := obj- := - -obj-$(CONFIG_LEDS) += leds.o diff --git a/arch/arm/mach-ebsa110/leds.c b/arch/arm/mach-ebsa110/leds.c index 99e14e362500..0398258c20cd 100644 --- a/arch/arm/mach-ebsa110/leds.c +++ b/arch/arm/mach-ebsa110/leds.c @@ -1,52 +1,71 @@ /* - * linux/arch/arm/mach-ebsa110/leds.c + * Driver for the LED found on the EBSA110 machine + * Based on Versatile and RealView machine LED code * - * Copyright (C) 1998 Russell King - * - * 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. - * - * EBSA-110 LED control routines. We use the led as follows: - * - * - Red - toggles state every 50 timer interrupts + * License terms: GNU General Public License (GPL) version 2 + * Author: Bryan Wu <bryan.wu@canonical.com> */ -#include <linux/module.h> -#include <linux/spinlock.h> +#include <linux/kernel.h> #include <linux/init.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/leds.h> -#include <mach/hardware.h> -#include <asm/leds.h> #include <asm/mach-types.h> #include "core.h" -static spinlock_t leds_lock; - -static void ebsa110_leds_event(led_event_t ledevt) +#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) +static void ebsa110_led_set(struct led_classdev *cdev, + enum led_brightness b) { - unsigned long flags; + u8 reg = __raw_readb(SOFT_BASE); - spin_lock_irqsave(&leds_lock, flags); + if (b != LED_OFF) + reg |= 0x80; + else + reg &= ~0x80; - switch(ledevt) { - case led_timer: - *(volatile unsigned char *)SOFT_BASE ^= 128; - break; + __raw_writeb(reg, SOFT_BASE); +} - default: - break; - } +static enum led_brightness ebsa110_led_get(struct led_classdev *cdev) +{ + u8 reg = __raw_readb(SOFT_BASE); - spin_unlock_irqrestore(&leds_lock, flags); + return (reg & 0x80) ? LED_FULL : LED_OFF; } -static int __init leds_init(void) +static int __init ebsa110_leds_init(void) { - if (machine_is_ebsa110()) - leds_event = ebsa110_leds_event; + + struct led_classdev *cdev; + int ret; + + if (!machine_is_ebsa110()) + return -ENODEV; + + cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); + if (!cdev) + return -ENOMEM; + + cdev->name = "ebsa110:0"; + cdev->brightness_set = ebsa110_led_set; + cdev->brightness_get = ebsa110_led_get; + cdev->default_trigger = "heartbeat"; + + ret = led_classdev_register(NULL, cdev); + if (ret < 0) { + kfree(cdev); + return ret; + } return 0; } -__initcall(leds_init); +/* + * Since we may have triggers on any subsystem, defer registration + * until after subsystem_init. + */ +fs_initcall(ebsa110_leds_init); +#endif diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 6c3299ebbfc5..412884dafa6c 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -405,6 +405,8 @@ config MACH_EXYNOS4_DT select USE_OF select ARM_AMBA select HAVE_SAMSUNG_KEYPAD if INPUT_KEYBOARD + select PINCTRL + select PINCTRL_EXYNOS4 help Machine support for Samsung Exynos4 machine with device tree enabled. Select this if a fdt blob is available for the Exynos4 SoC based board. diff --git a/arch/arm/mach-exynos/clock-exynos5.c b/arch/arm/mach-exynos/clock-exynos5.c index 618d0aaaa599..f3171c3f3d94 100644 --- a/arch/arm/mach-exynos/clock-exynos5.c +++ b/arch/arm/mach-exynos/clock-exynos5.c @@ -547,6 +547,68 @@ static struct clksrc_clk exynos5_clk_aclk_66 = { .reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 0, .size = 3 }, }; +static struct clksrc_clk exynos5_clk_mout_aclk_300_gscl_mid = { + .clk = { + .name = "mout_aclk_300_gscl_mid", + }, + .sources = &exynos5_clkset_aclk, + .reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 24, .size = 1 }, +}; + +static struct clk *exynos5_clkset_aclk_300_mid1_list[] = { + [0] = &exynos5_clk_sclk_vpll.clk, + [1] = &exynos5_clk_mout_cpll.clk, +}; + +static struct clksrc_sources exynos5_clkset_aclk_300_gscl_mid1 = { + .sources = exynos5_clkset_aclk_300_mid1_list, + .nr_sources = ARRAY_SIZE(exynos5_clkset_aclk_300_mid1_list), +}; + +static struct clksrc_clk exynos5_clk_mout_aclk_300_gscl_mid1 = { + .clk = { + .name = "mout_aclk_300_gscl_mid1", + }, + .sources = &exynos5_clkset_aclk_300_gscl_mid1, + .reg_src = { .reg = EXYNOS5_CLKSRC_TOP1, .shift = 12, .size = 1 }, +}; + +static struct clk *exynos5_clkset_aclk_300_gscl_list[] = { + [0] = &exynos5_clk_mout_aclk_300_gscl_mid.clk, + [1] = &exynos5_clk_mout_aclk_300_gscl_mid1.clk, +}; + +static struct clksrc_sources exynos5_clkset_aclk_300_gscl = { + .sources = exynos5_clkset_aclk_300_gscl_list, + .nr_sources = ARRAY_SIZE(exynos5_clkset_aclk_300_gscl_list), +}; + +static struct clksrc_clk exynos5_clk_mout_aclk_300_gscl = { + .clk = { + .name = "mout_aclk_300_gscl", + }, + .sources = &exynos5_clkset_aclk_300_gscl, + .reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 25, .size = 1 }, +}; + +static struct clk *exynos5_clk_src_gscl_300_list[] = { + [0] = &clk_ext_xtal_mux, + [1] = &exynos5_clk_mout_aclk_300_gscl.clk, +}; + +static struct clksrc_sources exynos5_clk_src_gscl_300 = { + .sources = exynos5_clk_src_gscl_300_list, + .nr_sources = ARRAY_SIZE(exynos5_clk_src_gscl_300_list), +}; + +static struct clksrc_clk exynos5_clk_aclk_300_gscl = { + .clk = { + .name = "aclk_300_gscl", + }, + .sources = &exynos5_clk_src_gscl_300, + .reg_src = { .reg = EXYNOS5_CLKSRC_TOP3, .shift = 10, .size = 1 }, +}; + static struct clk exynos5_init_clocks_off[] = { { .name = "timers", @@ -755,6 +817,26 @@ static struct clk exynos5_init_clocks_off[] = { .enable = exynos5_clk_ip_peric_ctrl, .ctrlbit = (1 << 18), }, { + .name = "gscl", + .devname = "exynos-gsc.0", + .enable = exynos5_clk_ip_gscl_ctrl, + .ctrlbit = (1 << 0), + }, { + .name = "gscl", + .devname = "exynos-gsc.1", + .enable = exynos5_clk_ip_gscl_ctrl, + .ctrlbit = (1 << 1), + }, { + .name = "gscl", + .devname = "exynos-gsc.2", + .enable = exynos5_clk_ip_gscl_ctrl, + .ctrlbit = (1 << 2), + }, { + .name = "gscl", + .devname = "exynos-gsc.3", + .enable = exynos5_clk_ip_gscl_ctrl, + .ctrlbit = (1 << 3), + }, { .name = SYSMMU_CLOCK_NAME, .devname = SYSMMU_CLOCK_DEVNAME(mfc_l, 0), .enable = &exynos5_clk_ip_mfc_ctrl, @@ -1225,6 +1307,10 @@ static struct clksrc_clk *exynos5_sysclks[] = { &exynos5_clk_aclk_266, &exynos5_clk_aclk_200, &exynos5_clk_aclk_166, + &exynos5_clk_aclk_300_gscl, + &exynos5_clk_mout_aclk_300_gscl, + &exynos5_clk_mout_aclk_300_gscl_mid, + &exynos5_clk_mout_aclk_300_gscl_mid1, &exynos5_clk_aclk_66_pre, &exynos5_clk_aclk_66, &exynos5_clk_dout_mmc0, diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index 4eb39cdf75ea..715b690e5009 100644 --- a/arch/arm/mach-exynos/common.c +++ b/arch/arm/mach-exynos/common.c @@ -980,6 +980,32 @@ static int __init exynos_init_irq_eint(void) { int irq; +#ifdef CONFIG_PINCTRL_SAMSUNG + /* + * The Samsung pinctrl driver provides an integrated gpio/pinmux/pinconf + * functionality along with support for external gpio and wakeup + * interrupts. If the samsung pinctrl driver is enabled and includes + * the wakeup interrupt support, then the setting up external wakeup + * interrupts here can be skipped. This check here is temporary to + * allow exynos4 platforms that do not use Samsung pinctrl driver to + * co-exist with platforms that do. When all of the Samsung Exynos4 + * platforms switch over to using the pinctrl driver, the wakeup + * interrupt support code here can be completely removed. + */ + struct device_node *pctrl_np, *wkup_np; + const char *pctrl_compat = "samsung,pinctrl-exynos4210"; + const char *wkup_compat = "samsung,exynos4210-wakeup-eint"; + + for_each_compatible_node(pctrl_np, NULL, pctrl_compat) { + if (of_device_is_available(pctrl_np)) { + wkup_np = of_find_compatible_node(pctrl_np, NULL, + wkup_compat); + if (wkup_np) + return -ENODEV; + } + } +#endif + if (soc_is_exynos5250()) exynos_eint_base = ioremap(EXYNOS5_PA_GPIO1, SZ_4K); else diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h index 6d33f50c2e56..5aa77f996e59 100644 --- a/arch/arm/mach-exynos/include/mach/map.h +++ b/arch/arm/mach-exynos/include/mach/map.h @@ -121,6 +121,11 @@ #define EXYNOS4_PA_SYSMMU_MFC_L 0x13620000 #define EXYNOS4_PA_SYSMMU_MFC_R 0x13630000 +#define EXYNOS5_PA_GSC0 0x13E00000 +#define EXYNOS5_PA_GSC1 0x13E10000 +#define EXYNOS5_PA_GSC2 0x13E20000 +#define EXYNOS5_PA_GSC3 0x13E30000 + #define EXYNOS5_PA_SYSMMU_MDMA1 0x10A40000 #define EXYNOS5_PA_SYSMMU_SSS 0x10A50000 #define EXYNOS5_PA_SYSMMU_2D 0x10A60000 diff --git a/arch/arm/mach-exynos/mach-exynos5-dt.c b/arch/arm/mach-exynos/mach-exynos5-dt.c index ef770bc2318f..e707eb1b1eab 100644 --- a/arch/arm/mach-exynos/mach-exynos5-dt.c +++ b/arch/arm/mach-exynos/mach-exynos5-dt.c @@ -56,6 +56,14 @@ static const struct of_dev_auxdata exynos5250_auxdata_lookup[] __initconst = { OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_PDMA0, "dma-pl330.0", NULL), OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_PDMA1, "dma-pl330.1", NULL), OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_MDMA1, "dma-pl330.2", NULL), + OF_DEV_AUXDATA("samsung,exynos5-gsc", EXYNOS5_PA_GSC0, + "exynos-gsc.0", NULL), + OF_DEV_AUXDATA("samsung,exynos5-gsc", EXYNOS5_PA_GSC1, + "exynos-gsc.1", NULL), + OF_DEV_AUXDATA("samsung,exynos5-gsc", EXYNOS5_PA_GSC2, + "exynos-gsc.2", NULL), + OF_DEV_AUXDATA("samsung,exynos5-gsc", EXYNOS5_PA_GSC3, + "exynos-gsc.3", NULL), {}, }; diff --git a/arch/arm/mach-footbridge/Makefile b/arch/arm/mach-footbridge/Makefile index 3afb1b25946f..0b64dd430d61 100644 --- a/arch/arm/mach-footbridge/Makefile +++ b/arch/arm/mach-footbridge/Makefile @@ -14,15 +14,11 @@ pci-$(CONFIG_ARCH_EBSA285_HOST) += ebsa285-pci.o pci-$(CONFIG_ARCH_NETWINDER) += netwinder-pci.o pci-$(CONFIG_ARCH_PERSONAL_SERVER) += personal-pci.o -leds-$(CONFIG_ARCH_EBSA285) += ebsa285-leds.o -leds-$(CONFIG_ARCH_NETWINDER) += netwinder-leds.o - obj-$(CONFIG_ARCH_CATS) += cats-hw.o isa-timer.o obj-$(CONFIG_ARCH_EBSA285) += ebsa285.o dc21285-timer.o obj-$(CONFIG_ARCH_NETWINDER) += netwinder-hw.o isa-timer.o obj-$(CONFIG_ARCH_PERSONAL_SERVER) += personal.o dc21285-timer.o obj-$(CONFIG_PCI) +=$(pci-y) -obj-$(CONFIG_LEDS) +=$(leds-y) obj-$(CONFIG_ISA) += isa.o isa-rtc.o diff --git a/arch/arm/mach-footbridge/ebsa285-leds.c b/arch/arm/mach-footbridge/ebsa285-leds.c deleted file mode 100644 index 5bd266754b95..000000000000 --- a/arch/arm/mach-footbridge/ebsa285-leds.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * linux/arch/arm/mach-footbridge/ebsa285-leds.c - * - * Copyright (C) 1998-1999 Russell King - * - * 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. - * EBSA-285 control routines. - * - * The EBSA-285 uses the leds as follows: - * - Green - toggles state every 50 timer interrupts - * - Amber - On if system is not idle - * - Red - currently unused - * - * Changelog: - * 02-05-1999 RMK Various cleanups - */ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/spinlock.h> - -#include <mach/hardware.h> -#include <asm/leds.h> -#include <asm/mach-types.h> - -#define LED_STATE_ENABLED 1 -#define LED_STATE_CLAIMED 2 -static char led_state; -static char hw_led_state; - -static DEFINE_SPINLOCK(leds_lock); - -static void ebsa285_leds_event(led_event_t evt) -{ - unsigned long flags; - - spin_lock_irqsave(&leds_lock, flags); - - switch (evt) { - case led_start: - hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN; -#ifndef CONFIG_LEDS_CPU - hw_led_state |= XBUS_LED_AMBER; -#endif - led_state |= LED_STATE_ENABLED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN | XBUS_LED_AMBER; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN | XBUS_LED_AMBER; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state ^= XBUS_LED_GREEN; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= XBUS_LED_AMBER; - break; - - case led_idle_end: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~XBUS_LED_AMBER; - break; -#endif - - case led_halted: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~XBUS_LED_RED; - break; - - case led_green_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~XBUS_LED_GREEN; - break; - - case led_green_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= XBUS_LED_GREEN; - break; - - case led_amber_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~XBUS_LED_AMBER; - break; - - case led_amber_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= XBUS_LED_AMBER; - break; - - case led_red_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~XBUS_LED_RED; - break; - - case led_red_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= XBUS_LED_RED; - break; - - default: - break; - } - - if (led_state & LED_STATE_ENABLED) - *XBUS_LEDS = hw_led_state; - - spin_unlock_irqrestore(&leds_lock, flags); -} - -static int __init leds_init(void) -{ - if (machine_is_ebsa285()) - leds_event = ebsa285_leds_event; - - leds_event(led_start); - - return 0; -} - -__initcall(leds_init); diff --git a/arch/arm/mach-footbridge/ebsa285.c b/arch/arm/mach-footbridge/ebsa285.c index 27716a7e5fc1..b09551ef89ca 100644 --- a/arch/arm/mach-footbridge/ebsa285.c +++ b/arch/arm/mach-footbridge/ebsa285.c @@ -5,6 +5,8 @@ */ #include <linux/init.h> #include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/leds.h> #include <asm/hardware/dec21285.h> #include <asm/mach-types.h> @@ -13,6 +15,85 @@ #include "common.h" +/* LEDs */ +#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) +struct ebsa285_led { + struct led_classdev cdev; + u8 mask; +}; + +/* + * The triggers lines up below will only be used if the + * LED triggers are compiled in. + */ +static const struct { + const char *name; + const char *trigger; +} ebsa285_leds[] = { + { "ebsa285:amber", "heartbeat", }, + { "ebsa285:green", "cpu0", }, + { "ebsa285:red",}, +}; + +static void ebsa285_led_set(struct led_classdev *cdev, + enum led_brightness b) +{ + struct ebsa285_led *led = container_of(cdev, + struct ebsa285_led, cdev); + + if (b != LED_OFF) + *XBUS_LEDS |= led->mask; + else + *XBUS_LEDS &= ~led->mask; +} + +static enum led_brightness ebsa285_led_get(struct led_classdev *cdev) +{ + struct ebsa285_led *led = container_of(cdev, + struct ebsa285_led, cdev); + + return (*XBUS_LEDS & led->mask) ? LED_FULL : LED_OFF; +} + +static int __init ebsa285_leds_init(void) +{ + int i; + + if (machine_is_ebsa285()) + return -ENODEV; + + /* 3 LEDS All ON */ + *XBUS_LEDS |= XBUS_LED_AMBER | XBUS_LED_GREEN | XBUS_LED_RED; + + for (i = 0; i < ARRAY_SIZE(ebsa285_leds); i++) { + struct ebsa285_led *led; + + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (!led) + break; + + led->cdev.name = ebsa285_leds[i].name; + led->cdev.brightness_set = ebsa285_led_set; + led->cdev.brightness_get = ebsa285_led_get; + led->cdev.default_trigger = ebsa285_leds[i].trigger; + led->mask = BIT(i); + + if (led_classdev_register(NULL, &led->cdev) < 0) { + kfree(led); + break; + } + } + + return 0; +} + +/* + * Since we may have triggers on any subsystem, defer registration + * until after subsystem_init. + */ +fs_initcall(ebsa285_leds_init); +#endif + MACHINE_START(EBSA285, "EBSA285") /* Maintainer: Russell King */ .atag_offset = 0x100, diff --git a/arch/arm/mach-footbridge/netwinder-hw.c b/arch/arm/mach-footbridge/netwinder-hw.c index cac9f67e7da7..d2d14339c6c4 100644 --- a/arch/arm/mach-footbridge/netwinder-hw.c +++ b/arch/arm/mach-footbridge/netwinder-hw.c @@ -12,9 +12,10 @@ #include <linux/init.h> #include <linux/io.h> #include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/leds.h> #include <asm/hardware/dec21285.h> -#include <asm/leds.h> #include <asm/mach-types.h> #include <asm/setup.h> #include <asm/system_misc.h> @@ -27,13 +28,6 @@ #define GP1_IO_BASE 0x338 #define GP2_IO_BASE 0x33a - -#ifdef CONFIG_LEDS -#define DEFAULT_LEDS 0 -#else -#define DEFAULT_LEDS GPIO_GREEN_LED -#endif - /* * Winbond WB83977F accessibility stuff */ @@ -611,15 +605,9 @@ static void __init rwa010_init(void) static int __init nw_hw_init(void) { if (machine_is_netwinder()) { - unsigned long flags; - wb977_init(); cpld_init(); rwa010_init(); - - raw_spin_lock_irqsave(&nw_gpio_lock, flags); - nw_gpio_modify_op(GPIO_RED_LED|GPIO_GREEN_LED, DEFAULT_LEDS); - raw_spin_unlock_irqrestore(&nw_gpio_lock, flags); } return 0; } @@ -672,6 +660,102 @@ static void netwinder_restart(char mode, const char *cmd) } } +/* LEDs */ +#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) +struct netwinder_led { + struct led_classdev cdev; + u8 mask; +}; + +/* + * The triggers lines up below will only be used if the + * LED triggers are compiled in. + */ +static const struct { + const char *name; + const char *trigger; +} netwinder_leds[] = { + { "netwinder:green", "heartbeat", }, + { "netwinder:red", "cpu0", }, +}; + +/* + * The LED control in Netwinder is reversed: + * - setting bit means turn off LED + * - clearing bit means turn on LED + */ +static void netwinder_led_set(struct led_classdev *cdev, + enum led_brightness b) +{ + struct netwinder_led *led = container_of(cdev, + struct netwinder_led, cdev); + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&nw_gpio_lock, flags); + reg = nw_gpio_read(); + if (b != LED_OFF) + reg &= ~led->mask; + else + reg |= led->mask; + nw_gpio_modify_op(led->mask, reg); + spin_unlock_irqrestore(&nw_gpio_lock, flags); +} + +static enum led_brightness netwinder_led_get(struct led_classdev *cdev) +{ + struct netwinder_led *led = container_of(cdev, + struct netwinder_led, cdev); + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&nw_gpio_lock, flags); + reg = nw_gpio_read(); + spin_unlock_irqrestore(&nw_gpio_lock, flags); + + return (reg & led->mask) ? LED_OFF : LED_FULL; +} + +static int __init netwinder_leds_init(void) +{ + int i; + + if (!machine_is_netwinder()) + return -ENODEV; + + for (i = 0; i < ARRAY_SIZE(netwinder_leds); i++) { + struct netwinder_led *led; + + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (!led) + break; + + led->cdev.name = netwinder_leds[i].name; + led->cdev.brightness_set = netwinder_led_set; + led->cdev.brightness_get = netwinder_led_get; + led->cdev.default_trigger = netwinder_leds[i].trigger; + + if (i == 0) + led->mask = GPIO_GREEN_LED; + else + led->mask = GPIO_RED_LED; + + if (led_classdev_register(NULL, &led->cdev) < 0) { + kfree(led); + break; + } + } + + return 0; +} + +/* + * Since we may have triggers on any subsystem, defer registration + * until after subsystem_init. + */ +fs_initcall(netwinder_leds_init); +#endif + MACHINE_START(NETWINDER, "Rebel-NetWinder") /* Maintainer: Russell King/Rebel.com */ .atag_offset = 0x100, diff --git a/arch/arm/mach-footbridge/netwinder-leds.c b/arch/arm/mach-footbridge/netwinder-leds.c deleted file mode 100644 index 5a2bd89cbdca..000000000000 --- a/arch/arm/mach-footbridge/netwinder-leds.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * linux/arch/arm/mach-footbridge/netwinder-leds.c - * - * Copyright (C) 1998-1999 Russell King - * - * 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. - * - * NetWinder LED control routines. - * - * The Netwinder uses the leds as follows: - * - Green - toggles state every 50 timer interrupts - * - Red - On if the system is not idle - * - * Changelog: - * 02-05-1999 RMK Various cleanups - */ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/spinlock.h> - -#include <mach/hardware.h> -#include <asm/leds.h> -#include <asm/mach-types.h> - -#define LED_STATE_ENABLED 1 -#define LED_STATE_CLAIMED 2 -static char led_state; -static char hw_led_state; - -static DEFINE_RAW_SPINLOCK(leds_lock); - -static void netwinder_leds_event(led_event_t evt) -{ - unsigned long flags; - - raw_spin_lock_irqsave(&leds_lock, flags); - - switch (evt) { - case led_start: - led_state |= LED_STATE_ENABLED; - hw_led_state = GPIO_GREEN_LED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = 0; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = 0; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state ^= GPIO_GREEN_LED; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~GPIO_RED_LED; - break; - - case led_idle_end: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= GPIO_RED_LED; - break; -#endif - - case led_halted: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= GPIO_RED_LED; - break; - - case led_green_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= GPIO_GREEN_LED; - break; - - case led_green_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~GPIO_GREEN_LED; - break; - - case led_amber_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= GPIO_GREEN_LED | GPIO_RED_LED; - break; - - case led_amber_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~(GPIO_GREEN_LED | GPIO_RED_LED); - break; - - case led_red_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= GPIO_RED_LED; - break; - - case led_red_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~GPIO_RED_LED; - break; - - default: - break; - } - - raw_spin_unlock_irqrestore(&leds_lock, flags); - - if (led_state & LED_STATE_ENABLED) { - raw_spin_lock_irqsave(&nw_gpio_lock, flags); - nw_gpio_modify_op(GPIO_RED_LED | GPIO_GREEN_LED, hw_led_state); - raw_spin_unlock_irqrestore(&nw_gpio_lock, flags); - } -} - -static int __init leds_init(void) -{ - if (machine_is_netwinder()) - leds_event = netwinder_leds_event; - - leds_event(led_start); - - return 0; -} - -__initcall(leds_init); diff --git a/arch/arm/mach-integrator/Makefile b/arch/arm/mach-integrator/Makefile index ebeef966e1f5..5521d18bf19a 100644 --- a/arch/arm/mach-integrator/Makefile +++ b/arch/arm/mach-integrator/Makefile @@ -4,11 +4,10 @@ # Object file lists. -obj-y := core.o lm.o +obj-y := core.o lm.o leds.o obj-$(CONFIG_ARCH_INTEGRATOR_AP) += integrator_ap.o obj-$(CONFIG_ARCH_INTEGRATOR_CP) += integrator_cp.o -obj-$(CONFIG_LEDS) += leds.o obj-$(CONFIG_PCI) += pci_v3.o pci.o obj-$(CONFIG_CPU_FREQ_INTEGRATOR) += cpu.o obj-$(CONFIG_INTEGRATOR_IMPD1) += impd1.o diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c index a432d4325f89..dad3cb74ed31 100644 --- a/arch/arm/mach-integrator/core.c +++ b/arch/arm/mach-integrator/core.c @@ -28,7 +28,6 @@ #include <mach/cm.h> #include <mach/irqs.h> -#include <asm/leds.h> #include <asm/mach-types.h> #include <asm/mach/time.h> #include <asm/pgtable.h> @@ -128,8 +127,6 @@ static struct amba_pl010_data integrator_uart_data = { .set_mctrl = integrator_uart_set_mctrl, }; -#define CM_CTRL IO_ADDRESS(INTEGRATOR_HDR_CTRL) - static DEFINE_RAW_SPINLOCK(cm_lock); /** diff --git a/arch/arm/mach-integrator/include/mach/cm.h b/arch/arm/mach-integrator/include/mach/cm.h index 445d57adb043..1a78692e32a4 100644 --- a/arch/arm/mach-integrator/include/mach/cm.h +++ b/arch/arm/mach-integrator/include/mach/cm.h @@ -3,6 +3,8 @@ */ void cm_control(u32, u32); +#define CM_CTRL IO_ADDRESS(INTEGRATOR_HDR_CTRL) + #define CM_CTRL_LED (1 << 0) #define CM_CTRL_nMBDET (1 << 1) #define CM_CTRL_REMAP (1 << 2) diff --git a/arch/arm/mach-integrator/leds.c b/arch/arm/mach-integrator/leds.c index 466defa97842..7a7f6d3273bf 100644 --- a/arch/arm/mach-integrator/leds.c +++ b/arch/arm/mach-integrator/leds.c @@ -1,90 +1,125 @@ /* - * linux/arch/arm/mach-integrator/leds.c + * Driver for the 4 user LEDs found on the Integrator AP/CP baseboard + * Based on Versatile and RealView machine LED code * - * Integrator/AP and Integrator/CP LED control routines - * - * Copyright (C) 1999 ARM Limited - * Copyright (C) 2000 Deep Blue Solutions Ltd - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * License terms: GNU General Public License (GPL) version 2 + * Author: Bryan Wu <bryan.wu@canonical.com> */ #include <linux/kernel.h> #include <linux/init.h> -#include <linux/smp.h> -#include <linux/spinlock.h> #include <linux/io.h> +#include <linux/slab.h> +#include <linux/leds.h> +#include <mach/cm.h> #include <mach/hardware.h> #include <mach/platform.h> -#include <asm/leds.h> -#include <asm/mach-types.h> -#include <mach/cm.h> -static int saved_leds; +#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) + +#define ALPHA_REG __io_address(INTEGRATOR_DBG_BASE) +#define LEDREG (__io_address(INTEGRATOR_DBG_BASE) + INTEGRATOR_DBG_LEDS_OFFSET) -static void integrator_leds_event(led_event_t ledevt) +struct integrator_led { + struct led_classdev cdev; + u8 mask; +}; + +/* + * The triggers lines up below will only be used if the + * LED triggers are compiled in. + */ +static const struct { + const char *name; + const char *trigger; +} integrator_leds[] = { + { "integrator:green0", "heartbeat", }, + { "integrator:yellow", }, + { "integrator:red", }, + { "integrator:green1", }, + { "integrator:core_module", "cpu0", }, +}; + +static void integrator_led_set(struct led_classdev *cdev, + enum led_brightness b) { - unsigned long flags; - const unsigned int dbg_base = IO_ADDRESS(INTEGRATOR_DBG_BASE); - unsigned int update_alpha_leds; + struct integrator_led *led = container_of(cdev, + struct integrator_led, cdev); + u32 reg = __raw_readl(LEDREG); - // yup, change the LEDs - local_irq_save(flags); - update_alpha_leds = 0; + if (b != LED_OFF) + reg |= led->mask; + else + reg &= ~led->mask; - switch(ledevt) { - case led_idle_start: - cm_control(CM_CTRL_LED, 0); - break; + while (__raw_readl(ALPHA_REG) & 1) + cpu_relax(); - case led_idle_end: - cm_control(CM_CTRL_LED, CM_CTRL_LED); - break; + __raw_writel(reg, LEDREG); +} - case led_timer: - saved_leds ^= GREEN_LED; - update_alpha_leds = 1; - break; +static enum led_brightness integrator_led_get(struct led_classdev *cdev) +{ + struct integrator_led *led = container_of(cdev, + struct integrator_led, cdev); + u32 reg = __raw_readl(LEDREG); - case led_red_on: - saved_leds |= RED_LED; - update_alpha_leds = 1; - break; + return (reg & led->mask) ? LED_FULL : LED_OFF; +} - case led_red_off: - saved_leds &= ~RED_LED; - update_alpha_leds = 1; - break; +static void cm_led_set(struct led_classdev *cdev, + enum led_brightness b) +{ + if (b != LED_OFF) + cm_control(CM_CTRL_LED, CM_CTRL_LED); + else + cm_control(CM_CTRL_LED, 0); +} - default: - break; - } +static enum led_brightness cm_led_get(struct led_classdev *cdev) +{ + u32 reg = readl(CM_CTRL); - if (update_alpha_leds) { - while (__raw_readl(dbg_base + INTEGRATOR_DBG_ALPHA_OFFSET) & 1); - __raw_writel(saved_leds, dbg_base + INTEGRATOR_DBG_LEDS_OFFSET); - } - local_irq_restore(flags); + return (reg & CM_CTRL_LED) ? LED_FULL : LED_OFF; } -static int __init leds_init(void) +static int __init integrator_leds_init(void) { - if (machine_is_integrator() || machine_is_cintegrator()) - leds_event = integrator_leds_event; + int i; + + for (i = 0; i < ARRAY_SIZE(integrator_leds); i++) { + struct integrator_led *led; + + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (!led) + break; + + + led->cdev.name = integrator_leds[i].name; + + if (i == 4) { /* Setting for LED in core module */ + led->cdev.brightness_set = cm_led_set; + led->cdev.brightness_get = cm_led_get; + } else { + led->cdev.brightness_set = integrator_led_set; + led->cdev.brightness_get = integrator_led_get; + } + + led->cdev.default_trigger = integrator_leds[i].trigger; + led->mask = BIT(i); + + if (led_classdev_register(NULL, &led->cdev) < 0) { + kfree(led); + break; + } + } return 0; } -core_initcall(leds_init); +/* + * Since we may have triggers on any subsystem, defer registration + * until after subsystem_init. + */ +fs_initcall(integrator_leds_init); +#endif diff --git a/arch/arm/mach-ks8695/Makefile b/arch/arm/mach-ks8695/Makefile index 853efd9133c6..9324ef965c26 100644 --- a/arch/arm/mach-ks8695/Makefile +++ b/arch/arm/mach-ks8695/Makefile @@ -11,9 +11,6 @@ obj- := # PCI support is optional obj-$(CONFIG_PCI) += pci.o -# LEDs -obj-$(CONFIG_LEDS) += leds.o - # Board-specific support obj-$(CONFIG_MACH_KS8695) += board-micrel.o obj-$(CONFIG_MACH_DSM320) += board-dsm320.o diff --git a/arch/arm/mach-ks8695/devices.c b/arch/arm/mach-ks8695/devices.c index 73bd63812878..47399bc3c024 100644 --- a/arch/arm/mach-ks8695/devices.c +++ b/arch/arm/mach-ks8695/devices.c @@ -182,27 +182,6 @@ static void __init ks8695_add_device_watchdog(void) } -/* -------------------------------------------------------------------- - * LEDs - * -------------------------------------------------------------------- */ - -#if defined(CONFIG_LEDS) -short ks8695_leds_cpu = -1; -short ks8695_leds_timer = -1; - -void __init ks8695_init_leds(u8 cpu_led, u8 timer_led) -{ - /* Enable GPIO to access the LEDs */ - gpio_direction_output(cpu_led, 1); - gpio_direction_output(timer_led, 1); - - ks8695_leds_cpu = cpu_led; - ks8695_leds_timer = timer_led; -} -#else -void __init ks8695_init_leds(u8 cpu_led, u8 timer_led) {} -#endif - /* -------------------------------------------------------------------- */ /* diff --git a/arch/arm/mach-ks8695/include/mach/devices.h b/arch/arm/mach-ks8695/include/mach/devices.h index 85a3c9aa7d13..1e6594a0f297 100644 --- a/arch/arm/mach-ks8695/include/mach/devices.h +++ b/arch/arm/mach-ks8695/include/mach/devices.h @@ -18,11 +18,6 @@ extern void __init ks8695_add_device_wan(void); extern void __init ks8695_add_device_lan(void); extern void __init ks8695_add_device_hpna(void); - /* LEDs */ -extern short ks8695_leds_cpu; -extern short ks8695_leds_timer; -extern void __init ks8695_init_leds(u8 cpu_led, u8 timer_led); - /* PCI */ #define KS8695_MODE_PCI 0 #define KS8695_MODE_MINIPCI 1 diff --git a/arch/arm/mach-ks8695/leds.c b/arch/arm/mach-ks8695/leds.c deleted file mode 100644 index 4bd707547293..000000000000 --- a/arch/arm/mach-ks8695/leds.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * LED driver for KS8695-based boards. - * - * Copyright (C) Andrew Victor - * - * 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 <linux/gpio.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> - -#include <asm/leds.h> -#include <mach/devices.h> - - -static inline void ks8695_led_on(unsigned int led) -{ - gpio_set_value(led, 0); -} - -static inline void ks8695_led_off(unsigned int led) -{ - gpio_set_value(led, 1); -} - -static inline void ks8695_led_toggle(unsigned int led) -{ - unsigned long is_off = gpio_get_value(led); - if (is_off) - ks8695_led_on(led); - else - ks8695_led_off(led); -} - - -/* - * Handle LED events. - */ -static void ks8695_leds_event(led_event_t evt) -{ - unsigned long flags; - - local_irq_save(flags); - - switch(evt) { - case led_start: /* System startup */ - ks8695_led_on(ks8695_leds_cpu); - break; - - case led_stop: /* System stop / suspend */ - ks8695_led_off(ks8695_leds_cpu); - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: /* Every 50 timer ticks */ - ks8695_led_toggle(ks8695_leds_timer); - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: /* Entering idle state */ - ks8695_led_off(ks8695_leds_cpu); - break; - - case led_idle_end: /* Exit idle state */ - ks8695_led_on(ks8695_leds_cpu); - break; -#endif - - default: - break; - } - - local_irq_restore(flags); -} - - -static int __init leds_init(void) -{ - if ((ks8695_leds_timer == -1) || (ks8695_leds_cpu == -1)) - return -ENODEV; - - leds_event = ks8695_leds_event; - - leds_event(led_start); - return 0; -} - -__initcall(leds_init); diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile index 398e9e53e189..cd169c386161 100644 --- a/arch/arm/mach-omap1/Makefile +++ b/arch/arm/mach-omap1/Makefile @@ -61,14 +61,6 @@ obj-$(CONFIG_ARCH_OMAP850) += gpio7xx.o obj-$(CONFIG_ARCH_OMAP15XX) += gpio15xx.o obj-$(CONFIG_ARCH_OMAP16XX) += gpio16xx.o -# LEDs support -led-$(CONFIG_MACH_OMAP_H2) += leds-h2p2-debug.o -led-$(CONFIG_MACH_OMAP_H3) += leds-h2p2-debug.o -led-$(CONFIG_MACH_OMAP_INNOVATOR) += leds-innovator.o -led-$(CONFIG_MACH_OMAP_PERSEUS2) += leds-h2p2-debug.o -led-$(CONFIG_MACH_OMAP_OSK) += leds-osk.o -obj-$(CONFIG_LEDS) += $(led-y) - ifneq ($(CONFIG_FB_OMAP),) obj-y += lcd_dma.o endif diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c index af283a2bc7c7..376f7f29ef77 100644 --- a/arch/arm/mach-omap1/board-h2.c +++ b/arch/arm/mach-omap1/board-h2.c @@ -32,6 +32,7 @@ #include <linux/smc91x.h> #include <linux/omapfb.h> #include <linux/platform_data/gpio-omap.h> +#include <linux/leds.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> @@ -307,12 +308,39 @@ static struct platform_device h2_irda_device = { .resource = h2_irda_resources, }; +static struct gpio_led h2_gpio_led_pins[] = { + { + .name = "h2:red", + .default_trigger = "heartbeat", + .gpio = 3, + }, + { + .name = "h2:green", + .default_trigger = "cpu0", + .gpio = OMAP_MPUIO(4), + }, +}; + +static struct gpio_led_platform_data h2_gpio_led_data = { + .leds = h2_gpio_led_pins, + .num_leds = ARRAY_SIZE(h2_gpio_led_pins), +}; + +static struct platform_device h2_gpio_leds = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &h2_gpio_led_data, + }, +}; + static struct platform_device *h2_devices[] __initdata = { &h2_nor_device, &h2_nand_device, &h2_smc91x_device, &h2_irda_device, &h2_kp_device, + &h2_gpio_leds, }; static void __init h2_init_smc91x(void) @@ -407,6 +435,10 @@ static void __init h2_init(void) omap_cfg_reg(E19_1610_KBR4); omap_cfg_reg(N19_1610_KBR5); + /* GPIO based LEDs */ + omap_cfg_reg(P18_1610_GPIO3); + omap_cfg_reg(MPUIO4); + h2_smc91x_resources[1].start = gpio_to_irq(0); h2_smc91x_resources[1].end = gpio_to_irq(0); platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices)); diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c index 06d11b1ee9c6..ededdb7ef28c 100644 --- a/arch/arm/mach-omap1/board-h3.c +++ b/arch/arm/mach-omap1/board-h3.c @@ -32,6 +32,7 @@ #include <linux/smc91x.h> #include <linux/omapfb.h> #include <linux/platform_data/gpio-omap.h> +#include <linux/leds.h> #include <asm/setup.h> #include <asm/page.h> @@ -325,6 +326,32 @@ static struct spi_board_info h3_spi_board_info[] __initdata = { }, }; +static struct gpio_led h3_gpio_led_pins[] = { + { + .name = "h3:red", + .default_trigger = "heartbeat", + .gpio = 3, + }, + { + .name = "h3:green", + .default_trigger = "cpu0", + .gpio = OMAP_MPUIO(4), + }, +}; + +static struct gpio_led_platform_data h3_gpio_led_data = { + .leds = h3_gpio_led_pins, + .num_leds = ARRAY_SIZE(h3_gpio_led_pins), +}; + +static struct platform_device h3_gpio_leds = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &h3_gpio_led_data, + }, +}; + static struct platform_device *devices[] __initdata = { &nor_device, &nand_device, @@ -332,6 +359,7 @@ static struct platform_device *devices[] __initdata = { &intlat_device, &h3_kp_device, &h3_lcd_device, + &h3_gpio_leds, }; static struct omap_usb_config h3_usb_config __initdata = { @@ -399,6 +427,10 @@ static void __init h3_init(void) omap_cfg_reg(E19_1610_KBR4); omap_cfg_reg(N19_1610_KBR5); + /* GPIO based LEDs */ + omap_cfg_reg(P18_1610_GPIO3); + omap_cfg_reg(MPUIO4); + smc91x_resources[1].start = gpio_to_irq(40); smc91x_resources[1].end = gpio_to_irq(40); platform_add_devices(devices, ARRAY_SIZE(devices)); diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c index 2f1f9b967576..5973945a8741 100644 --- a/arch/arm/mach-omap1/board-osk.c +++ b/arch/arm/mach-omap1/board-osk.c @@ -382,10 +382,37 @@ static struct platform_device osk5912_lcd_device = { .id = -1, }; +static struct gpio_led mistral_gpio_led_pins[] = { + { + .name = "mistral:red", + .default_trigger = "heartbeat", + .gpio = 3, + }, + { + .name = "mistral:green", + .default_trigger = "cpu0", + .gpio = OMAP_MPUIO(4), + }, +}; + +static struct gpio_led_platform_data mistral_gpio_led_data = { + .leds = mistral_gpio_led_pins, + .num_leds = ARRAY_SIZE(mistral_gpio_led_pins), +}; + +static struct platform_device mistral_gpio_leds = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &mistral_gpio_led_data, + }, +}; + static struct platform_device *mistral_devices[] __initdata = { &osk5912_kp_device, &mistral_bl_device, &osk5912_lcd_device, + &mistral_gpio_leds, }; static int mistral_get_pendown_state(void) @@ -510,6 +537,12 @@ static void __init osk_mistral_init(void) if (gpio_request(2, "lcd_pwr") == 0) gpio_direction_output(2, 1); + /* + * GPIO based LEDs + */ + omap_cfg_reg(P18_1610_GPIO3); + omap_cfg_reg(MPUIO4); + i2c_register_board_info(1, mistral_i2c_board_info, ARRAY_SIZE(mistral_i2c_board_info)); diff --git a/arch/arm/mach-omap1/leds-h2p2-debug.c b/arch/arm/mach-omap1/leds-h2p2-debug.c deleted file mode 100644 index 6f958aec9459..000000000000 --- a/arch/arm/mach-omap1/leds-h2p2-debug.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * linux/arch/arm/mach-omap1/leds-h2p2-debug.c - * - * Copyright 2003 by Texas Instruments Incorporated - * - * There are 16 LEDs on the debug board (all green); four may be used - * for logical 'green', 'amber', 'red', and 'blue' (after "claiming"). - * - * The "surfer" expansion board and H2 sample board also have two-color - * green+red LEDs (in parallel), used here for timer and idle indicators. - */ -#include <linux/gpio.h> -#include <linux/init.h> -#include <linux/kernel_stat.h> -#include <linux/sched.h> -#include <linux/io.h> -#include <linux/platform_data/gpio-omap.h> - -#include <mach/hardware.h> -#include <asm/leds.h> -#include <asm/mach-types.h> - -#include <plat/fpga.h> - -#include "leds.h" - - -#define GPIO_LED_RED 3 -#define GPIO_LED_GREEN OMAP_MPUIO(4) - - -#define LED_STATE_ENABLED 0x01 -#define LED_STATE_CLAIMED 0x02 -#define LED_TIMER_ON 0x04 - -#define GPIO_IDLE GPIO_LED_GREEN -#define GPIO_TIMER GPIO_LED_RED - - -void h2p2_dbg_leds_event(led_event_t evt) -{ - unsigned long flags; - - static struct h2p2_dbg_fpga __iomem *fpga; - static u16 led_state, hw_led_state; - - local_irq_save(flags); - - if (!(led_state & LED_STATE_ENABLED) && evt != led_start) - goto done; - - switch (evt) { - case led_start: - if (!fpga) - fpga = ioremap(H2P2_DBG_FPGA_START, - H2P2_DBG_FPGA_SIZE); - if (fpga) { - led_state |= LED_STATE_ENABLED; - __raw_writew(~0, &fpga->leds); - } - break; - - case led_stop: - case led_halted: - /* all leds off during suspend or shutdown */ - - if (! machine_is_omap_perseus2()) { - gpio_set_value(GPIO_TIMER, 0); - gpio_set_value(GPIO_IDLE, 0); - } - - led_state &= ~LED_STATE_ENABLED; - if (fpga) { - __raw_writew(~0, &fpga->leds); - if (evt == led_halted) { - iounmap(fpga); - fpga = NULL; - } - } - - goto done; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = 0; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - led_state ^= LED_TIMER_ON; - - if (machine_is_omap_perseus2()) - hw_led_state ^= H2P2_DBG_FPGA_P2_LED_TIMER; - else { - gpio_set_value(GPIO_TIMER, led_state & LED_TIMER_ON); - goto done; - } - - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - if (machine_is_omap_perseus2()) - hw_led_state |= H2P2_DBG_FPGA_P2_LED_IDLE; - else { - gpio_set_value(GPIO_IDLE, 1); - goto done; - } - - break; - - case led_idle_end: - if (machine_is_omap_perseus2()) - hw_led_state &= ~H2P2_DBG_FPGA_P2_LED_IDLE; - else { - gpio_set_value(GPIO_IDLE, 0); - goto done; - } - - break; -#endif - - case led_green_on: - hw_led_state |= H2P2_DBG_FPGA_LED_GREEN; - break; - case led_green_off: - hw_led_state &= ~H2P2_DBG_FPGA_LED_GREEN; - break; - - case led_amber_on: - hw_led_state |= H2P2_DBG_FPGA_LED_AMBER; - break; - case led_amber_off: - hw_led_state &= ~H2P2_DBG_FPGA_LED_AMBER; - break; - - case led_red_on: - hw_led_state |= H2P2_DBG_FPGA_LED_RED; - break; - case led_red_off: - hw_led_state &= ~H2P2_DBG_FPGA_LED_RED; - break; - - case led_blue_on: - hw_led_state |= H2P2_DBG_FPGA_LED_BLUE; - break; - case led_blue_off: - hw_led_state &= ~H2P2_DBG_FPGA_LED_BLUE; - break; - - default: - break; - } - - - /* - * Actually burn the LEDs - */ - if (led_state & LED_STATE_ENABLED && fpga) - __raw_writew(~hw_led_state, &fpga->leds); - -done: - local_irq_restore(flags); -} diff --git a/arch/arm/mach-omap1/leds-innovator.c b/arch/arm/mach-omap1/leds-innovator.c deleted file mode 100644 index 3a066ee8d02c..000000000000 --- a/arch/arm/mach-omap1/leds-innovator.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * linux/arch/arm/mach-omap1/leds-innovator.c - */ -#include <linux/init.h> - -#include <mach/hardware.h> -#include <asm/leds.h> - -#include "leds.h" - - -#define LED_STATE_ENABLED 1 -#define LED_STATE_CLAIMED 2 - -static unsigned int led_state; -static unsigned int hw_led_state; - -void innovator_leds_event(led_event_t evt) -{ - unsigned long flags; - - local_irq_save(flags); - - switch (evt) { - case led_start: - hw_led_state = 0; - led_state = LED_STATE_ENABLED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - hw_led_state = 0; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = 0; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = 0; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state ^= 0; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= 0; - break; - - case led_idle_end: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~0; - break; -#endif - - case led_halted: - break; - - case led_green_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~0; - break; - - case led_green_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= 0; - break; - - case led_amber_on: - break; - - case led_amber_off: - break; - - case led_red_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~0; - break; - - case led_red_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= 0; - break; - - default: - break; - } - - local_irq_restore(flags); -} diff --git a/arch/arm/mach-omap1/leds-osk.c b/arch/arm/mach-omap1/leds-osk.c deleted file mode 100644 index 936ed426b84f..000000000000 --- a/arch/arm/mach-omap1/leds-osk.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * linux/arch/arm/mach-omap1/leds-osk.c - * - * LED driver for OSK with optional Mistral QVGA board - */ -#include <linux/gpio.h> -#include <linux/init.h> - -#include <mach/hardware.h> -#include <asm/leds.h> - -#include "leds.h" - - -#define LED_STATE_ENABLED (1 << 0) -#define LED_STATE_CLAIMED (1 << 1) -static u8 led_state; - -#define TIMER_LED (1 << 3) /* Mistral board */ -#define IDLE_LED (1 << 4) /* Mistral board */ -static u8 hw_led_state; - - -#ifdef CONFIG_OMAP_OSK_MISTRAL - -/* For now, all system indicators require the Mistral board, since that - * LED can be manipulated without a task context. This LED is either red, - * or green, but not both; it can't give the full "disco led" effect. - */ - -#define GPIO_LED_RED 3 -#define GPIO_LED_GREEN OMAP_MPUIO(4) - -static void mistral_setled(void) -{ - int red = 0; - int green = 0; - - if (hw_led_state & TIMER_LED) - red = 1; - else if (hw_led_state & IDLE_LED) - green = 1; - /* else both sides are disabled */ - - gpio_set_value(GPIO_LED_GREEN, green); - gpio_set_value(GPIO_LED_RED, red); -} - -#endif - -void osk_leds_event(led_event_t evt) -{ - unsigned long flags; - u16 leds; - - local_irq_save(flags); - - if (!(led_state & LED_STATE_ENABLED) && evt != led_start) - goto done; - - leds = hw_led_state; - switch (evt) { - case led_start: - led_state |= LED_STATE_ENABLED; - hw_led_state = 0; - leds = ~0; - break; - - case led_halted: - case led_stop: - led_state &= ~LED_STATE_ENABLED; - hw_led_state = 0; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = 0; - leds = ~0; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = 0; - break; - -#ifdef CONFIG_OMAP_OSK_MISTRAL - - case led_timer: - hw_led_state ^= TIMER_LED; - mistral_setled(); - break; - - case led_idle_start: /* idle == off */ - hw_led_state &= ~IDLE_LED; - mistral_setled(); - break; - - case led_idle_end: - hw_led_state |= IDLE_LED; - mistral_setled(); - break; - -#endif /* CONFIG_OMAP_OSK_MISTRAL */ - - default: - break; - } - - leds ^= hw_led_state; - -done: - local_irq_restore(flags); -} diff --git a/arch/arm/mach-omap1/leds.c b/arch/arm/mach-omap1/leds.c deleted file mode 100644 index 4071479f7106..000000000000 --- a/arch/arm/mach-omap1/leds.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * linux/arch/arm/mach-omap1/leds.c - * - * OMAP LEDs dispatcher - */ -#include <linux/gpio.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/platform_data/gpio-omap.h> - -#include <asm/leds.h> -#include <asm/mach-types.h> - -#include <mach/mux.h> - -#include "leds.h" - -static int __init -omap_leds_init(void) -{ - if (!cpu_class_is_omap1()) - return -ENODEV; - - if (machine_is_omap_innovator()) - leds_event = innovator_leds_event; - - else if (machine_is_omap_h2() - || machine_is_omap_h3() - || machine_is_omap_perseus2()) - leds_event = h2p2_dbg_leds_event; - - else if (machine_is_omap_osk()) - leds_event = osk_leds_event; - - else - return -1; - - if (machine_is_omap_h2() - || machine_is_omap_h3() -#ifdef CONFIG_OMAP_OSK_MISTRAL - || machine_is_omap_osk() -#endif - ) { - - /* LED1/LED2 pins can be used as GPIO (as done here), or by - * the LPG (works even in deep sleep!), to drive a bicolor - * LED on the H2 sample board, and another on the H2/P2 - * "surfer" expansion board. - * - * The same pins drive a LED on the OSK Mistral board, but - * that's a different kind of LED (just one color at a time). - */ - omap_cfg_reg(P18_1610_GPIO3); - if (gpio_request(3, "LED red") == 0) - gpio_direction_output(3, 1); - else - printk(KERN_WARNING "LED: can't get GPIO3/red?\n"); - - omap_cfg_reg(MPUIO4); - if (gpio_request(OMAP_MPUIO(4), "LED green") == 0) - gpio_direction_output(OMAP_MPUIO(4), 1); - else - printk(KERN_WARNING "LED: can't get MPUIO4/green?\n"); - } - - leds_event(led_start); - return 0; -} - -__initcall(omap_leds_init); diff --git a/arch/arm/mach-omap1/leds.h b/arch/arm/mach-omap1/leds.h deleted file mode 100644 index a1e9fedc376c..000000000000 --- a/arch/arm/mach-omap1/leds.h +++ /dev/null @@ -1,3 +0,0 @@ -extern void innovator_leds_event(led_event_t evt); -extern void h2p2_dbg_leds_event(led_event_t evt); -extern void osk_leds_event(led_event_t evt); diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c index 4062480bfec7..4d4816fd6fc9 100644 --- a/arch/arm/mach-omap1/time.c +++ b/arch/arm/mach-omap1/time.c @@ -44,7 +44,6 @@ #include <linux/clockchips.h> #include <linux/io.h> -#include <asm/leds.h> #include <asm/irq.h> #include <asm/sched_clock.h> diff --git a/arch/arm/mach-omap1/timer32k.c b/arch/arm/mach-omap1/timer32k.c index eae49c3980c9..74529549130c 100644 --- a/arch/arm/mach-omap1/timer32k.c +++ b/arch/arm/mach-omap1/timer32k.c @@ -46,7 +46,6 @@ #include <linux/clockchips.h> #include <linux/io.h> -#include <asm/leds.h> #include <asm/irq.h> #include <asm/mach/irq.h> #include <asm/mach/time.h> diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index edc30b8b77ed..a6219eaf1f68 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -48,6 +48,7 @@ config ARCH_OMAP3 select ARM_CPU_SUSPEND if PM select MULTI_IRQ_HANDLER select SOC_HAS_OMAP2_SDRC + select OMAP_INTERCONNECT config ARCH_OMAP4 bool "TI OMAP4" @@ -67,6 +68,7 @@ config ARCH_OMAP4 select USB_ARCH_HAS_EHCI if USB_SUPPORT select ARM_CPU_SUSPEND if PM select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP + select OMAP_INTERCONNECT config SOC_OMAP5 bool "TI OMAP5" diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 845202358ddc..7d6abda3b74e 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -180,11 +180,6 @@ obj-$(CONFIG_ARCH_OMAP4) += omap_hwmod_44xx_data.o # EMU peripherals obj-$(CONFIG_OMAP3_EMU) += emu.o -# L3 interconnect -obj-$(CONFIG_ARCH_OMAP3) += omap_l3_smx.o -obj-$(CONFIG_ARCH_OMAP4) += omap_l3_noc.o -obj-$(CONFIG_SOC_OMAP5) += omap_l3_noc.o - obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o mailbox_mach-objs := mailbox.o diff --git a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c index 78a6a11d8216..9b1c95310291 100644 --- a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c +++ b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c @@ -18,7 +18,6 @@ #include <linux/ethtool.h> #include <net/dsa.h> #include <asm/mach-types.h> -#include <asm/leds.h> #include <asm/mach/arch.h> #include <asm/mach/pci.h> #include <mach/orion5x.h> diff --git a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c index 2f5dc54cd4cd..51ba2b81a10b 100644 --- a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c +++ b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c @@ -19,7 +19,6 @@ #include <linux/i2c.h> #include <net/dsa.h> #include <asm/mach-types.h> -#include <asm/leds.h> #include <asm/mach/arch.h> #include <asm/mach/pci.h> #include <mach/orion5x.h> diff --git a/arch/arm/mach-orion5x/rd88f5182-setup.c b/arch/arm/mach-orion5x/rd88f5182-setup.c index 399130fac0b6..0a56b9444f1b 100644 --- a/arch/arm/mach-orion5x/rd88f5182-setup.c +++ b/arch/arm/mach-orion5x/rd88f5182-setup.c @@ -19,8 +19,8 @@ #include <linux/mv643xx_eth.h> #include <linux/ata_platform.h> #include <linux/i2c.h> +#include <linux/leds.h> #include <asm/mach-types.h> -#include <asm/leds.h> #include <asm/mach/arch.h> #include <asm/mach/pci.h> #include <mach/orion5x.h> @@ -53,12 +53,6 @@ #define RD88F5182_PCI_SLOT0_IRQ_A_PIN 7 #define RD88F5182_PCI_SLOT0_IRQ_B_PIN 6 -/* - * GPIO Debug LED - */ - -#define RD88F5182_GPIO_DBG_LED 0 - /***************************************************************************** * 16M NOR Flash on Device bus CS1 ****************************************************************************/ @@ -83,55 +77,32 @@ static struct platform_device rd88f5182_nor_flash = { .resource = &rd88f5182_nor_flash_resource, }; -#ifdef CONFIG_LEDS - /***************************************************************************** - * Use GPIO debug led as CPU active indication + * Use GPIO LED as CPU active indication ****************************************************************************/ -static void rd88f5182_dbgled_event(led_event_t evt) -{ - int val; - - if (evt == led_idle_end) - val = 1; - else if (evt == led_idle_start) - val = 0; - else - return; - - gpio_set_value(RD88F5182_GPIO_DBG_LED, val); -} - -static int __init rd88f5182_dbgled_init(void) -{ - int pin; - - if (machine_is_rd88f5182()) { - pin = RD88F5182_GPIO_DBG_LED; +#define RD88F5182_GPIO_LED 0 - if (gpio_request(pin, "DBGLED") == 0) { - if (gpio_direction_output(pin, 0) != 0) { - printk(KERN_ERR "rd88f5182_dbgled_init failed " - "to set output pin %d\n", pin); - gpio_free(pin); - return 0; - } - } else { - printk(KERN_ERR "rd88f5182_dbgled_init failed " - "to request gpio %d\n", pin); - return 0; - } - - leds_event = rd88f5182_dbgled_event; - } - - return 0; -} +static struct gpio_led rd88f5182_gpio_led_pins[] = { + { + .name = "rd88f5182:cpu", + .default_trigger = "cpu0", + .gpio = RD88F5182_GPIO_LED, + }, +}; -__initcall(rd88f5182_dbgled_init); +static struct gpio_led_platform_data rd88f5182_gpio_led_data = { + .leds = rd88f5182_gpio_led_pins, + .num_leds = ARRAY_SIZE(rd88f5182_gpio_led_pins), +}; -#endif +static struct platform_device rd88f5182_gpio_leds = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &rd88f5182_gpio_led_data, + }, +}; /***************************************************************************** * PCI @@ -298,6 +269,7 @@ static void __init rd88f5182_init(void) orion5x_setup_dev1_win(RD88F5182_NOR_BASE, RD88F5182_NOR_SIZE); platform_device_register(&rd88f5182_nor_flash); + platform_device_register(&rd88f5182_gpio_leds); i2c_register_board_info(0, &rd88f5182_i2c_rtc, 1); } diff --git a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c index 92df49c1b62a..ed50910b08a4 100644 --- a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c +++ b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c @@ -20,7 +20,6 @@ #include <linux/ethtool.h> #include <net/dsa.h> #include <asm/mach-types.h> -#include <asm/leds.h> #include <asm/mach/arch.h> #include <asm/mach/pci.h> #include <mach/orion5x.h> diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index 2bedc9ed076c..ee88d6eae648 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile @@ -98,12 +98,4 @@ obj-$(CONFIG_MACH_RAUMFELD_CONNECTOR) += raumfeld.o obj-$(CONFIG_MACH_RAUMFELD_SPEAKER) += raumfeld.o obj-$(CONFIG_MACH_ZIPIT2) += z2.o -# Support for blinky lights -led-y := leds.o -led-$(CONFIG_ARCH_LUBBOCK) += leds-lubbock.o -led-$(CONFIG_MACH_MAINSTONE) += leds-mainstone.o -led-$(CONFIG_ARCH_PXA_IDP) += leds-idp.o - -obj-$(CONFIG_LEDS) += $(led-y) - obj-$(CONFIG_TOSA_BT) += tosa-bt.o diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c index 6ff466bd43e8..ae1e9977603e 100644 --- a/arch/arm/mach-pxa/idp.c +++ b/arch/arm/mach-pxa/idp.c @@ -191,6 +191,87 @@ static void __init idp_map_io(void) iotable_init(idp_io_desc, ARRAY_SIZE(idp_io_desc)); } +/* LEDs */ +#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) +struct idp_led { + struct led_classdev cdev; + u8 mask; +}; + +/* + * The triggers lines up below will only be used if the + * LED triggers are compiled in. + */ +static const struct { + const char *name; + const char *trigger; +} idp_leds[] = { + { "idp:green", "heartbeat", }, + { "idp:red", "cpu0", }, +}; + +static void idp_led_set(struct led_classdev *cdev, + enum led_brightness b) +{ + struct idp_led *led = container_of(cdev, + struct idp_led, cdev); + u32 reg = IDP_CPLD_LED_CONTROL; + + if (b != LED_OFF) + reg &= ~led->mask; + else + reg |= led->mask; + + IDP_CPLD_LED_CONTROL = reg; +} + +static enum led_brightness idp_led_get(struct led_classdev *cdev) +{ + struct idp_led *led = container_of(cdev, + struct idp_led, cdev); + + return (IDP_CPLD_LED_CONTROL & led->mask) ? LED_OFF : LED_FULL; +} + +static int __init idp_leds_init(void) +{ + int i; + + if (!machine_is_pxa_idp()) + return -ENODEV; + + for (i = 0; i < ARRAY_SIZE(idp_leds); i++) { + struct idp_led *led; + + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (!led) + break; + + led->cdev.name = idp_leds[i].name; + led->cdev.brightness_set = idp_led_set; + led->cdev.brightness_get = idp_led_get; + led->cdev.default_trigger = idp_leds[i].trigger; + + if (i == 0) + led->mask = IDP_HB_LED; + else + led->mask = IDP_BUSY_LED; + + if (led_classdev_register(NULL, &led->cdev) < 0) { + kfree(led); + break; + } + } + + return 0; +} + +/* + * Since we may have triggers on any subsystem, defer registration + * until after subsystem_init. + */ +fs_initcall(idp_leds_init); +#endif MACHINE_START(PXA_IDP, "Vibren PXA255 IDP") /* Maintainer: Vibren Technologies */ diff --git a/arch/arm/mach-pxa/leds-idp.c b/arch/arm/mach-pxa/leds-idp.c deleted file mode 100644 index 06b060025d11..000000000000 --- a/arch/arm/mach-pxa/leds-idp.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * linux/arch/arm/mach-pxa/leds-idp.c - * - * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu> - * - * Copyright (c) 2001 Jeff Sutherland <jeffs@accelent.com> - * - * Original (leds-footbridge.c) by Russell King - * - * Macros for actual LED manipulation should be in machine specific - * files in this 'mach' directory. - */ - - -#include <linux/init.h> - -#include <mach/hardware.h> -#include <asm/leds.h> - -#include <mach/pxa25x.h> -#include <mach/idp.h> - -#include "leds.h" - -#define LED_STATE_ENABLED 1 -#define LED_STATE_CLAIMED 2 - -static unsigned int led_state; -static unsigned int hw_led_state; - -void idp_leds_event(led_event_t evt) -{ - unsigned long flags; - - local_irq_save(flags); - - switch (evt) { - case led_start: - hw_led_state = IDP_HB_LED | IDP_BUSY_LED; - led_state = LED_STATE_ENABLED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = IDP_HB_LED | IDP_BUSY_LED; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = IDP_HB_LED | IDP_BUSY_LED; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state ^= IDP_HB_LED; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~IDP_BUSY_LED; - break; - - case led_idle_end: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= IDP_BUSY_LED; - break; -#endif - - case led_halted: - break; - - case led_green_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= IDP_HB_LED; - break; - - case led_green_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~IDP_HB_LED; - break; - - case led_amber_on: - break; - - case led_amber_off: - break; - - case led_red_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= IDP_BUSY_LED; - break; - - case led_red_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~IDP_BUSY_LED; - break; - - default: - break; - } - - if (led_state & LED_STATE_ENABLED) - IDP_CPLD_LED_CONTROL = ( (IDP_CPLD_LED_CONTROL | IDP_LEDS_MASK) & ~hw_led_state); - else - IDP_CPLD_LED_CONTROL |= IDP_LEDS_MASK; - - local_irq_restore(flags); -} diff --git a/arch/arm/mach-pxa/leds-lubbock.c b/arch/arm/mach-pxa/leds-lubbock.c deleted file mode 100644 index 0bd85c884a7c..000000000000 --- a/arch/arm/mach-pxa/leds-lubbock.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * linux/arch/arm/mach-pxa/leds-lubbock.c - * - * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu> - * - * Copyright (c) 2001 Jeff Sutherland <jeffs@accelent.com> - * - * Original (leds-footbridge.c) by Russell King - * - * Major surgery on April 2004 by Nicolas Pitre for less global - * namespace collision. Mostly adapted the Mainstone version. - */ - -#include <linux/init.h> - -#include <mach/hardware.h> -#include <asm/leds.h> -#include <mach/pxa25x.h> -#include <mach/lubbock.h> - -#include "leds.h" - -/* - * 8 discrete leds available for general use: - * - * Note: bits [15-8] are used to enable/blank the 8 7 segment hex displays - * so be sure to not monkey with them here. - */ - -#define D28 (1 << 0) -#define D27 (1 << 1) -#define D26 (1 << 2) -#define D25 (1 << 3) -#define D24 (1 << 4) -#define D23 (1 << 5) -#define D22 (1 << 6) -#define D21 (1 << 7) - -#define LED_STATE_ENABLED 1 -#define LED_STATE_CLAIMED 2 - -static unsigned int led_state; -static unsigned int hw_led_state; - -void lubbock_leds_event(led_event_t evt) -{ - unsigned long flags; - - local_irq_save(flags); - - switch (evt) { - case led_start: - hw_led_state = 0; - led_state = LED_STATE_ENABLED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = 0; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = 0; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - hw_led_state ^= D26; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - hw_led_state &= ~D27; - break; - - case led_idle_end: - hw_led_state |= D27; - break; -#endif - - case led_halted: - break; - - case led_green_on: - hw_led_state |= D21; - break; - - case led_green_off: - hw_led_state &= ~D21; - break; - - case led_amber_on: - hw_led_state |= D22; - break; - - case led_amber_off: - hw_led_state &= ~D22; - break; - - case led_red_on: - hw_led_state |= D23; - break; - - case led_red_off: - hw_led_state &= ~D23; - break; - - default: - break; - } - - if (led_state & LED_STATE_ENABLED) - LUB_DISC_BLNK_LED = (LUB_DISC_BLNK_LED | 0xff) & ~hw_led_state; - else - LUB_DISC_BLNK_LED |= 0xff; - - local_irq_restore(flags); -} diff --git a/arch/arm/mach-pxa/leds-mainstone.c b/arch/arm/mach-pxa/leds-mainstone.c deleted file mode 100644 index 4058ab340fe6..000000000000 --- a/arch/arm/mach-pxa/leds-mainstone.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * linux/arch/arm/mach-pxa/leds-mainstone.c - * - * Author: Nicolas Pitre - * Created: Nov 05, 2002 - * Copyright: MontaVista Software Inc. - * - * 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 <linux/init.h> - -#include <mach/hardware.h> -#include <asm/leds.h> - -#include <mach/pxa27x.h> -#include <mach/mainstone.h> - -#include "leds.h" - - -/* 8 discrete leds available for general use: */ -#define D28 (1 << 0) -#define D27 (1 << 1) -#define D26 (1 << 2) -#define D25 (1 << 3) -#define D24 (1 << 4) -#define D23 (1 << 5) -#define D22 (1 << 6) -#define D21 (1 << 7) - -#define LED_STATE_ENABLED 1 -#define LED_STATE_CLAIMED 2 - -static unsigned int led_state; -static unsigned int hw_led_state; - -void mainstone_leds_event(led_event_t evt) -{ - unsigned long flags; - - local_irq_save(flags); - - switch (evt) { - case led_start: - hw_led_state = 0; - led_state = LED_STATE_ENABLED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = 0; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = 0; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - hw_led_state ^= D26; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - hw_led_state &= ~D27; - break; - - case led_idle_end: - hw_led_state |= D27; - break; -#endif - - case led_halted: - break; - - case led_green_on: - hw_led_state |= D21; - break; - - case led_green_off: - hw_led_state &= ~D21; - break; - - case led_amber_on: - hw_led_state |= D22; - break; - - case led_amber_off: - hw_led_state &= ~D22; - break; - - case led_red_on: - hw_led_state |= D23; - break; - - case led_red_off: - hw_led_state &= ~D23; - break; - - default: - break; - } - - if (led_state & LED_STATE_ENABLED) - MST_LEDCTRL = (MST_LEDCTRL | 0xff) & ~hw_led_state; - else - MST_LEDCTRL |= 0xff; - - local_irq_restore(flags); -} diff --git a/arch/arm/mach-pxa/leds.c b/arch/arm/mach-pxa/leds.c deleted file mode 100644 index bbe4d5f6afaa..000000000000 --- a/arch/arm/mach-pxa/leds.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * linux/arch/arm/mach-pxa/leds.c - * - * xscale LEDs dispatcher - * - * Copyright (C) 2001 Nicolas Pitre - * - * Copyright (c) 2001 Jeff Sutherland, Accelent Systems Inc. - */ -#include <linux/compiler.h> -#include <linux/init.h> - -#include <asm/leds.h> -#include <asm/mach-types.h> - -#include "leds.h" - -static int __init -pxa_leds_init(void) -{ - if (machine_is_lubbock()) - leds_event = lubbock_leds_event; - if (machine_is_mainstone()) - leds_event = mainstone_leds_event; - if (machine_is_pxa_idp()) - leds_event = idp_leds_event; - - leds_event(led_start); - return 0; -} - -core_initcall(pxa_leds_init); diff --git a/arch/arm/mach-pxa/leds.h b/arch/arm/mach-pxa/leds.h deleted file mode 100644 index 7f0dfe01345a..000000000000 --- a/arch/arm/mach-pxa/leds.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * arch/arm/mach-pxa/leds.h - * - * Copyright (c) 2001 Jeff Sutherland, Accelent Systems Inc. - * - * blinky lights for various PXA-based systems: - * - */ - -extern void idp_leds_event(led_event_t evt); -extern void lubbock_leds_event(led_event_t evt); -extern void mainstone_leds_event(led_event_t evt); -extern void trizeps4_leds_event(led_event_t evt); diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index 0ca0db787903..3c48035afd6b 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -15,6 +15,7 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> +#include <linux/io.h> #include <linux/platform_device.h> #include <linux/syscore_ops.h> #include <linux/major.h> @@ -23,6 +24,8 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> #include <linux/smc91x.h> +#include <linux/slab.h> +#include <linux/leds.h> #include <linux/spi/spi.h> #include <linux/spi/ads7846.h> @@ -549,6 +552,98 @@ static void __init lubbock_map_io(void) PCFR |= PCFR_OPDE; } +/* + * Driver for the 8 discrete LEDs available for general use: + * Note: bits [15-8] are used to enable/blank the 8 7 segment hex displays + * so be sure to not monkey with them here. + */ + +#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) +struct lubbock_led { + struct led_classdev cdev; + u8 mask; +}; + +/* + * The triggers lines up below will only be used if the + * LED triggers are compiled in. + */ +static const struct { + const char *name; + const char *trigger; +} lubbock_leds[] = { + { "lubbock:D28", "default-on", }, + { "lubbock:D27", "cpu0", }, + { "lubbock:D26", "heartbeat" }, + { "lubbock:D25", }, + { "lubbock:D24", }, + { "lubbock:D23", }, + { "lubbock:D22", }, + { "lubbock:D21", }, +}; + +static void lubbock_led_set(struct led_classdev *cdev, + enum led_brightness b) +{ + struct lubbock_led *led = container_of(cdev, + struct lubbock_led, cdev); + u32 reg = LUB_DISC_BLNK_LED; + + if (b != LED_OFF) + reg |= led->mask; + else + reg &= ~led->mask; + + LUB_DISC_BLNK_LED = reg; +} + +static enum led_brightness lubbock_led_get(struct led_classdev *cdev) +{ + struct lubbock_led *led = container_of(cdev, + struct lubbock_led, cdev); + u32 reg = LUB_DISC_BLNK_LED; + + return (reg & led->mask) ? LED_FULL : LED_OFF; +} + +static int __init lubbock_leds_init(void) +{ + int i; + + if (!machine_is_lubbock()) + return -ENODEV; + + /* All ON */ + LUB_DISC_BLNK_LED |= 0xff; + for (i = 0; i < ARRAY_SIZE(lubbock_leds); i++) { + struct lubbock_led *led; + + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (!led) + break; + + led->cdev.name = lubbock_leds[i].name; + led->cdev.brightness_set = lubbock_led_set; + led->cdev.brightness_get = lubbock_led_get; + led->cdev.default_trigger = lubbock_leds[i].trigger; + led->mask = BIT(i); + + if (led_classdev_register(NULL, &led->cdev) < 0) { + kfree(led); + break; + } + } + + return 0; +} + +/* + * Since we may have triggers on any subsystem, defer registration + * until after subsystem_init. + */ +fs_initcall(lubbock_leds_init); +#endif + MACHINE_START(LUBBOCK, "Intel DBPXA250 Development Platform (aka Lubbock)") /* Maintainer: MontaVista Software Inc. */ .map_io = lubbock_map_io, diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c index 1aebaf719462..bdc6c335830a 100644 --- a/arch/arm/mach-pxa/mainstone.c +++ b/arch/arm/mach-pxa/mainstone.c @@ -28,6 +28,8 @@ #include <linux/pwm_backlight.h> #include <linux/smc91x.h> #include <linux/i2c/pxa-i2c.h> +#include <linux/slab.h> +#include <linux/leds.h> #include <asm/types.h> #include <asm/setup.h> @@ -613,6 +615,98 @@ static void __init mainstone_map_io(void) PCFR = 0x66; } +/* + * Driver for the 8 discrete LEDs available for general use: + * Note: bits [15-8] are used to enable/blank the 8 7 segment hex displays + * so be sure to not monkey with them here. + */ + +#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) +struct mainstone_led { + struct led_classdev cdev; + u8 mask; +}; + +/* + * The triggers lines up below will only be used if the + * LED triggers are compiled in. + */ +static const struct { + const char *name; + const char *trigger; +} mainstone_leds[] = { + { "mainstone:D28", "default-on", }, + { "mainstone:D27", "cpu0", }, + { "mainstone:D26", "heartbeat" }, + { "mainstone:D25", }, + { "mainstone:D24", }, + { "mainstone:D23", }, + { "mainstone:D22", }, + { "mainstone:D21", }, +}; + +static void mainstone_led_set(struct led_classdev *cdev, + enum led_brightness b) +{ + struct mainstone_led *led = container_of(cdev, + struct mainstone_led, cdev); + u32 reg = MST_LEDCTRL; + + if (b != LED_OFF) + reg |= led->mask; + else + reg &= ~led->mask; + + MST_LEDCTRL = reg; +} + +static enum led_brightness mainstone_led_get(struct led_classdev *cdev) +{ + struct mainstone_led *led = container_of(cdev, + struct mainstone_led, cdev); + u32 reg = MST_LEDCTRL; + + return (reg & led->mask) ? LED_FULL : LED_OFF; +} + +static int __init mainstone_leds_init(void) +{ + int i; + + if (!machine_is_mainstone()) + return -ENODEV; + + /* All ON */ + MST_LEDCTRL |= 0xff; + for (i = 0; i < ARRAY_SIZE(mainstone_leds); i++) { + struct mainstone_led *led; + + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (!led) + break; + + led->cdev.name = mainstone_leds[i].name; + led->cdev.brightness_set = mainstone_led_set; + led->cdev.brightness_get = mainstone_led_get; + led->cdev.default_trigger = mainstone_leds[i].trigger; + led->mask = BIT(i); + + if (led_classdev_register(NULL, &led->cdev) < 0) { + kfree(led); + break; + } + } + + return 0; +} + +/* + * Since we may have triggers on any subsystem, defer registration + * until after subsystem_init. + */ +fs_initcall(mainstone_leds_init); +#endif + MACHINE_START(MAINSTONE, "Intel HCDDBBVA0 Development Platform (aka Mainstone)") /* Maintainer: MontaVista Software Inc. */ .atag_offset = 0x100, /* BLOB boot parameter setting */ diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c index ff007d15e0ec..682467480588 100644 --- a/arch/arm/mach-realview/core.c +++ b/arch/arm/mach-realview/core.c @@ -34,7 +34,6 @@ #include <mach/hardware.h> #include <asm/irq.h> -#include <asm/leds.h> #include <asm/mach-types.h> #include <asm/hardware/arm_timer.h> #include <asm/hardware/icst.h> @@ -330,44 +329,6 @@ struct clcd_board clcd_plat_data = { .remove = versatile_clcd_remove_dma, }; -#ifdef CONFIG_LEDS -#define VA_LEDS_BASE (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LED_OFFSET) - -void realview_leds_event(led_event_t ledevt) -{ - unsigned long flags; - u32 val; - u32 led = 1 << smp_processor_id(); - - local_irq_save(flags); - val = readl(VA_LEDS_BASE); - - switch (ledevt) { - case led_idle_start: - val = val & ~led; - break; - - case led_idle_end: - val = val | led; - break; - - case led_timer: - val = val ^ REALVIEW_SYS_LED7; - break; - - case led_halted: - val = 0; - break; - - default: - break; - } - - writel(val, VA_LEDS_BASE); - local_irq_restore(flags); -} -#endif /* CONFIG_LEDS */ - /* * Where is the timer (VA)? */ diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h index f8f2c0ac4c01..f2141ae5a7de 100644 --- a/arch/arm/mach-realview/core.h +++ b/arch/arm/mach-realview/core.h @@ -26,7 +26,6 @@ #include <linux/io.h> #include <asm/setup.h> -#include <asm/leds.h> #define APB_DEVICE(name, busid, base, plat) \ static AMBA_APB_DEVICE(name, busid, 0, REALVIEW_##base##_BASE, base##_IRQ, plat) @@ -47,7 +46,6 @@ extern void __iomem *timer1_va_base; extern void __iomem *timer2_va_base; extern void __iomem *timer3_va_base; -extern void realview_leds_event(led_event_t ledevt); extern void realview_timer_init(unsigned int timer_irq); extern int realview_flash_register(struct resource *res, u32 num); extern int realview_eth_register(const char *name, struct resource *res); diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c index ce7747692c8b..d3b3cd216d64 100644 --- a/arch/arm/mach-realview/realview_eb.c +++ b/arch/arm/mach-realview/realview_eb.c @@ -31,7 +31,6 @@ #include <mach/hardware.h> #include <asm/irq.h> -#include <asm/leds.h> #include <asm/mach-types.h> #include <asm/pgtable.h> #include <asm/hardware/gic.h> @@ -463,10 +462,6 @@ static void __init realview_eb_init(void) struct amba_device *d = amba_devs[i]; amba_device_register(d, &iomem_resource); } - -#ifdef CONFIG_LEDS - leds_event = realview_leds_event; -#endif } MACHINE_START(REALVIEW_EB, "ARM-RealView EB") diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c index e21711d72ee2..07d6672ddae7 100644 --- a/arch/arm/mach-realview/realview_pb1176.c +++ b/arch/arm/mach-realview/realview_pb1176.c @@ -33,7 +33,6 @@ #include <mach/hardware.h> #include <asm/irq.h> -#include <asm/leds.h> #include <asm/mach-types.h> #include <asm/pgtable.h> #include <asm/hardware/gic.h> @@ -376,10 +375,6 @@ static void __init realview_pb1176_init(void) struct amba_device *d = amba_devs[i]; amba_device_register(d, &iomem_resource); } - -#ifdef CONFIG_LEDS - leds_event = realview_leds_event; -#endif } MACHINE_START(REALVIEW_PB1176, "ARM-RealView PB1176") diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c index b442fb276d57..ec4fcd9a7e9c 100644 --- a/arch/arm/mach-realview/realview_pb11mp.c +++ b/arch/arm/mach-realview/realview_pb11mp.c @@ -31,7 +31,6 @@ #include <mach/hardware.h> #include <asm/irq.h> -#include <asm/leds.h> #include <asm/mach-types.h> #include <asm/pgtable.h> #include <asm/hardware/gic.h> @@ -358,10 +357,6 @@ static void __init realview_pb11mp_init(void) struct amba_device *d = amba_devs[i]; amba_device_register(d, &iomem_resource); } - -#ifdef CONFIG_LEDS - leds_event = realview_leds_event; -#endif } MACHINE_START(REALVIEW_PB11MP, "ARM-RealView PB11MPCore") diff --git a/arch/arm/mach-realview/realview_pba8.c b/arch/arm/mach-realview/realview_pba8.c index 1435cd863965..9992431b8a15 100644 --- a/arch/arm/mach-realview/realview_pba8.c +++ b/arch/arm/mach-realview/realview_pba8.c @@ -30,7 +30,6 @@ #include <linux/platform_data/clk-realview.h> #include <asm/irq.h> -#include <asm/leds.h> #include <asm/mach-types.h> #include <asm/pgtable.h> #include <asm/hardware/gic.h> @@ -300,10 +299,6 @@ static void __init realview_pba8_init(void) struct amba_device *d = amba_devs[i]; amba_device_register(d, &iomem_resource); } - -#ifdef CONFIG_LEDS - leds_event = realview_leds_event; -#endif } MACHINE_START(REALVIEW_PBA8, "ARM-RealView PB-A8") diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c index 5d2c8bebb069..17954a327e1b 100644 --- a/arch/arm/mach-realview/realview_pbx.c +++ b/arch/arm/mach-realview/realview_pbx.c @@ -29,7 +29,6 @@ #include <linux/platform_data/clk-realview.h> #include <asm/irq.h> -#include <asm/leds.h> #include <asm/mach-types.h> #include <asm/smp_twd.h> #include <asm/pgtable.h> @@ -395,10 +394,6 @@ static void __init realview_pbx_init(void) struct amba_device *d = amba_devs[i]; amba_device_register(d, &iomem_resource); } - -#ifdef CONFIG_LEDS - leds_event = realview_leds_event; -#endif } MACHINE_START(REALVIEW_PBX, "ARM-RealView PBX") diff --git a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile index 60b97ec01676..1aed9e70465d 100644 --- a/arch/arm/mach-sa1100/Makefile +++ b/arch/arm/mach-sa1100/Makefile @@ -7,21 +7,17 @@ obj-y := clock.o generic.o irq.o time.o #nmi-oopser.o obj-m := obj-n := obj- := -led-y := leds.o obj-$(CONFIG_CPU_FREQ_SA1100) += cpu-sa1100.o obj-$(CONFIG_CPU_FREQ_SA1110) += cpu-sa1110.o # Specific board support obj-$(CONFIG_SA1100_ASSABET) += assabet.o -led-$(CONFIG_SA1100_ASSABET) += leds-assabet.o obj-$(CONFIG_ASSABET_NEPONSET) += neponset.o obj-$(CONFIG_SA1100_BADGE4) += badge4.o -led-$(CONFIG_SA1100_BADGE4) += leds-badge4.o obj-$(CONFIG_SA1100_CERF) += cerf.o -led-$(CONFIG_SA1100_CERF) += leds-cerf.o obj-$(CONFIG_SA1100_COLLIE) += collie.o @@ -29,13 +25,11 @@ obj-$(CONFIG_SA1100_H3100) += h3100.o h3xxx.o obj-$(CONFIG_SA1100_H3600) += h3600.o h3xxx.o obj-$(CONFIG_SA1100_HACKKIT) += hackkit.o -led-$(CONFIG_SA1100_HACKKIT) += leds-hackkit.o obj-$(CONFIG_SA1100_JORNADA720) += jornada720.o obj-$(CONFIG_SA1100_JORNADA720_SSP) += jornada720_ssp.o obj-$(CONFIG_SA1100_LART) += lart.o -led-$(CONFIG_SA1100_LART) += leds-lart.o obj-$(CONFIG_SA1100_NANOENGINE) += nanoengine.o obj-$(CONFIG_PCI_NANOENGINE) += pci-nanoengine.o @@ -46,9 +40,6 @@ obj-$(CONFIG_SA1100_SHANNON) += shannon.o obj-$(CONFIG_SA1100_SIMPAD) += simpad.o -# LEDs support -obj-$(CONFIG_LEDS) += $(led-y) - # Miscellaneous functions obj-$(CONFIG_PM) += pm.o sleep.o obj-$(CONFIG_SA1100_SSP) += ssp.o diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c index d673211f121c..1710ed1a0ac0 100644 --- a/arch/arm/mach-sa1100/assabet.c +++ b/arch/arm/mach-sa1100/assabet.c @@ -20,6 +20,8 @@ #include <linux/mtd/partitions.h> #include <linux/delay.h> #include <linux/mm.h> +#include <linux/leds.h> +#include <linux/slab.h> #include <video/sa1100fb.h> @@ -529,6 +531,89 @@ static void __init assabet_map_io(void) sa1100_register_uart(2, 3); } +/* LEDs */ +#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) +struct assabet_led { + struct led_classdev cdev; + u32 mask; +}; + +/* + * The triggers lines up below will only be used if the + * LED triggers are compiled in. + */ +static const struct { + const char *name; + const char *trigger; +} assabet_leds[] = { + { "assabet:red", "cpu0",}, + { "assabet:green", "heartbeat", }, +}; + +/* + * The LED control in Assabet is reversed: + * - setting bit means turn off LED + * - clearing bit means turn on LED + */ +static void assabet_led_set(struct led_classdev *cdev, + enum led_brightness b) +{ + struct assabet_led *led = container_of(cdev, + struct assabet_led, cdev); + + if (b != LED_OFF) + ASSABET_BCR_clear(led->mask); + else + ASSABET_BCR_set(led->mask); +} + +static enum led_brightness assabet_led_get(struct led_classdev *cdev) +{ + struct assabet_led *led = container_of(cdev, + struct assabet_led, cdev); + + return (ASSABET_BCR & led->mask) ? LED_OFF : LED_FULL; +} + +static int __init assabet_leds_init(void) +{ + int i; + + if (!machine_is_assabet()) + return -ENODEV; + + for (i = 0; i < ARRAY_SIZE(assabet_leds); i++) { + struct assabet_led *led; + + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (!led) + break; + + led->cdev.name = assabet_leds[i].name; + led->cdev.brightness_set = assabet_led_set; + led->cdev.brightness_get = assabet_led_get; + led->cdev.default_trigger = assabet_leds[i].trigger; + + if (!i) + led->mask = ASSABET_BCR_LED_RED; + else + led->mask = ASSABET_BCR_LED_GREEN; + + if (led_classdev_register(NULL, &led->cdev) < 0) { + kfree(led); + break; + } + } + + return 0; +} + +/* + * Since we may have triggers on any subsystem, defer registration + * until after subsystem_init. + */ +fs_initcall(assabet_leds_init); +#endif MACHINE_START(ASSABET, "Intel-Assabet") .atag_offset = 0x100, diff --git a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c index b30fb99b587c..038df4894b0f 100644 --- a/arch/arm/mach-sa1100/badge4.c +++ b/arch/arm/mach-sa1100/badge4.c @@ -22,6 +22,8 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> #include <linux/errno.h> +#include <linux/gpio.h> +#include <linux/leds.h> #include <mach/hardware.h> #include <asm/mach-types.h> @@ -76,8 +78,36 @@ static struct platform_device sa1111_device = { .resource = sa1111_resources, }; +/* LEDs */ +struct gpio_led badge4_gpio_leds[] = { + { + .name = "badge4:red", + .default_trigger = "heartbeat", + .gpio = 7, + }, + { + .name = "badge4:green", + .default_trigger = "cpu0", + .gpio = 9, + }, +}; + +static struct gpio_led_platform_data badge4_gpio_led_info = { + .leds = badge4_gpio_leds, + .num_leds = ARRAY_SIZE(badge4_gpio_leds), +}; + +static struct platform_device badge4_leds = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &badge4_gpio_led_info, + } +}; + static struct platform_device *devices[] __initdata = { &sa1111_device, + &badge4_leds, }; static int __init badge4_sa1111_init(void) diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c index 09d7f4b4b354..5240f104a3cd 100644 --- a/arch/arm/mach-sa1100/cerf.c +++ b/arch/arm/mach-sa1100/cerf.c @@ -17,6 +17,8 @@ #include <linux/irq.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> +#include <linux/gpio.h> +#include <linux/leds.h> #include <mach/hardware.h> #include <asm/setup.h> @@ -43,8 +45,48 @@ static struct platform_device cerfuart2_device = { .resource = cerfuart2_resources, }; +/* LEDs */ +struct gpio_led cerf_gpio_leds[] = { + { + .name = "cerf:d0", + .default_trigger = "heartbeat", + .gpio = 0, + }, + { + .name = "cerf:d1", + .default_trigger = "cpu0", + .gpio = 1, + }, + { + .name = "cerf:d2", + .default_trigger = "default-on", + .gpio = 2, + }, + { + .name = "cerf:d3", + .default_trigger = "default-on", + .gpio = 3, + }, + +}; + +static struct gpio_led_platform_data cerf_gpio_led_info = { + .leds = cerf_gpio_leds, + .num_leds = ARRAY_SIZE(cerf_gpio_leds), +}; + +static struct platform_device cerf_leds = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &cerf_gpio_led_info, + } +}; + + static struct platform_device *cerf_devices[] __initdata = { &cerfuart2_device, + &cerf_leds, }; #ifdef CONFIG_SA1100_CERF_FLASH_32MB diff --git a/arch/arm/mach-sa1100/hackkit.c b/arch/arm/mach-sa1100/hackkit.c index 7f86bd911826..fc106aab7c7e 100644 --- a/arch/arm/mach-sa1100/hackkit.c +++ b/arch/arm/mach-sa1100/hackkit.c @@ -21,6 +21,10 @@ #include <linux/serial_core.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> +#include <linux/tty.h> +#include <linux/gpio.h> +#include <linux/leds.h> +#include <linux/platform_device.h> #include <asm/mach-types.h> #include <asm/setup.h> @@ -183,9 +187,37 @@ static struct flash_platform_data hackkit_flash_data = { static struct resource hackkit_flash_resource = DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M); +/* LEDs */ +struct gpio_led hackkit_gpio_leds[] = { + { + .name = "hackkit:red", + .default_trigger = "cpu0", + .gpio = 22, + }, + { + .name = "hackkit:green", + .default_trigger = "heartbeat", + .gpio = 23, + }, +}; + +static struct gpio_led_platform_data hackkit_gpio_led_info = { + .leds = hackkit_gpio_leds, + .num_leds = ARRAY_SIZE(hackkit_gpio_leds), +}; + +static struct platform_device hackkit_leds = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &hackkit_gpio_led_info, + } +}; + static void __init hackkit_init(void) { sa11x0_register_mtd(&hackkit_flash_data, &hackkit_flash_resource, 1); + platform_device_register(&hackkit_leds); } /********************************************************************** diff --git a/arch/arm/mach-sa1100/lart.c b/arch/arm/mach-sa1100/lart.c index b775a0abec0a..b2ce04bf4c9b 100644 --- a/arch/arm/mach-sa1100/lart.c +++ b/arch/arm/mach-sa1100/lart.c @@ -5,6 +5,9 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/tty.h> +#include <linux/gpio.h> +#include <linux/leds.h> +#include <linux/platform_device.h> #include <video/sa1100fb.h> @@ -126,6 +129,27 @@ static struct map_desc lart_io_desc[] __initdata = { } }; +/* LEDs */ +struct gpio_led lart_gpio_leds[] = { + { + .name = "lart:red", + .default_trigger = "cpu0", + .gpio = 23, + }, +}; + +static struct gpio_led_platform_data lart_gpio_led_info = { + .leds = lart_gpio_leds, + .num_leds = ARRAY_SIZE(lart_gpio_leds), +}; + +static struct platform_device lart_leds = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &lart_gpio_led_info, + } +}; static void __init lart_map_io(void) { sa1100_map_io(); @@ -139,6 +163,8 @@ static void __init lart_map_io(void) GPDR |= GPIO_UART_TXD; GPDR &= ~GPIO_UART_RXD; PPAR |= PPAR_UPR; + + platform_device_register(&lart_leds); } MACHINE_START(LART, "LART") diff --git a/arch/arm/mach-sa1100/leds-assabet.c b/arch/arm/mach-sa1100/leds-assabet.c deleted file mode 100644 index 3699176bca94..000000000000 --- a/arch/arm/mach-sa1100/leds-assabet.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * linux/arch/arm/mach-sa1100/leds-assabet.c - * - * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu> - * - * Original (leds-footbridge.c) by Russell King - * - * Assabet uses the LEDs as follows: - * - Green - toggles state every 50 timer interrupts - * - Red - on if system is not idle - */ -#include <linux/init.h> - -#include <mach/hardware.h> -#include <asm/leds.h> -#include <mach/assabet.h> - -#include "leds.h" - - -#define LED_STATE_ENABLED 1 -#define LED_STATE_CLAIMED 2 - -static unsigned int led_state; -static unsigned int hw_led_state; - -#define ASSABET_BCR_LED_MASK (ASSABET_BCR_LED_GREEN | ASSABET_BCR_LED_RED) - -void assabet_leds_event(led_event_t evt) -{ - unsigned long flags; - - local_irq_save(flags); - - switch (evt) { - case led_start: - hw_led_state = ASSABET_BCR_LED_RED | ASSABET_BCR_LED_GREEN; - led_state = LED_STATE_ENABLED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - hw_led_state = ASSABET_BCR_LED_RED | ASSABET_BCR_LED_GREEN; - ASSABET_BCR_frob(ASSABET_BCR_LED_MASK, hw_led_state); - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = ASSABET_BCR_LED_RED | ASSABET_BCR_LED_GREEN; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = ASSABET_BCR_LED_RED | ASSABET_BCR_LED_GREEN; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state ^= ASSABET_BCR_LED_GREEN; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= ASSABET_BCR_LED_RED; - break; - - case led_idle_end: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~ASSABET_BCR_LED_RED; - break; -#endif - - case led_halted: - break; - - case led_green_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~ASSABET_BCR_LED_GREEN; - break; - - case led_green_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= ASSABET_BCR_LED_GREEN; - break; - - case led_amber_on: - break; - - case led_amber_off: - break; - - case led_red_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~ASSABET_BCR_LED_RED; - break; - - case led_red_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= ASSABET_BCR_LED_RED; - break; - - default: - break; - } - - if (led_state & LED_STATE_ENABLED) - ASSABET_BCR_frob(ASSABET_BCR_LED_MASK, hw_led_state); - - local_irq_restore(flags); -} diff --git a/arch/arm/mach-sa1100/leds-badge4.c b/arch/arm/mach-sa1100/leds-badge4.c deleted file mode 100644 index f99fac3eedb6..000000000000 --- a/arch/arm/mach-sa1100/leds-badge4.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * linux/arch/arm/mach-sa1100/leds-badge4.c - * - * Author: Christopher Hoover <ch@hpl.hp.com> - * Copyright (C) 2002 Hewlett-Packard Company - * - * 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 <linux/init.h> - -#include <mach/hardware.h> -#include <asm/leds.h> - -#include "leds.h" - -#define LED_STATE_ENABLED 1 -#define LED_STATE_CLAIMED 2 - -static unsigned int led_state; -static unsigned int hw_led_state; - -#define LED_RED GPIO_GPIO(7) -#define LED_GREEN GPIO_GPIO(9) -#define LED_MASK (LED_RED|LED_GREEN) - -#define LED_IDLE LED_GREEN -#define LED_TIMER LED_RED - -void badge4_leds_event(led_event_t evt) -{ - unsigned long flags; - - local_irq_save(flags); - - switch (evt) { - case led_start: - GPDR |= LED_MASK; - hw_led_state = LED_MASK; - led_state = LED_STATE_ENABLED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = LED_MASK; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = LED_MASK; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state ^= LED_TIMER; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - /* LED off when system is idle */ - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~LED_IDLE; - break; - - case led_idle_end: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= LED_IDLE; - break; -#endif - - case led_red_on: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~LED_RED; - break; - - case led_red_off: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= LED_RED; - break; - - case led_green_on: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~LED_GREEN; - break; - - case led_green_off: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= LED_GREEN; - break; - - default: - break; - } - - if (led_state & LED_STATE_ENABLED) { - GPSR = hw_led_state; - GPCR = hw_led_state ^ LED_MASK; - } - - local_irq_restore(flags); -} diff --git a/arch/arm/mach-sa1100/leds-cerf.c b/arch/arm/mach-sa1100/leds-cerf.c deleted file mode 100644 index 30fc3b2bf555..000000000000 --- a/arch/arm/mach-sa1100/leds-cerf.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * linux/arch/arm/mach-sa1100/leds-cerf.c - * - * Author: ??? - */ -#include <linux/init.h> -#include <linux/io.h> - -#include <mach/hardware.h> -#include <asm/leds.h> - -#include "leds.h" - - -#define LED_STATE_ENABLED 1 -#define LED_STATE_CLAIMED 2 - -static unsigned int led_state; -static unsigned int hw_led_state; - -#define LED_D0 GPIO_GPIO(0) -#define LED_D1 GPIO_GPIO(1) -#define LED_D2 GPIO_GPIO(2) -#define LED_D3 GPIO_GPIO(3) -#define LED_MASK (LED_D0|LED_D1|LED_D2|LED_D3) - -void cerf_leds_event(led_event_t evt) -{ - unsigned long flags; - - local_irq_save(flags); - - switch (evt) { - case led_start: - hw_led_state = LED_MASK; - led_state = LED_STATE_ENABLED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = LED_MASK; - break; - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = LED_MASK; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state ^= LED_D0; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~LED_D1; - break; - - case led_idle_end: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= LED_D1; - break; -#endif - case led_green_on: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~LED_D2; - break; - - case led_green_off: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= LED_D2; - break; - - case led_amber_on: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~LED_D3; - break; - - case led_amber_off: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= LED_D3; - break; - - case led_red_on: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~LED_D1; - break; - - case led_red_off: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= LED_D1; - break; - - default: - break; - } - - if (led_state & LED_STATE_ENABLED) { - GPSR = hw_led_state; - GPCR = hw_led_state ^ LED_MASK; - } - - local_irq_restore(flags); -} diff --git a/arch/arm/mach-sa1100/leds-hackkit.c b/arch/arm/mach-sa1100/leds-hackkit.c deleted file mode 100644 index f8e47235babe..000000000000 --- a/arch/arm/mach-sa1100/leds-hackkit.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * linux/arch/arm/mach-sa1100/leds-hackkit.c - * - * based on leds-lart.c - * - * (C) Erik Mouw (J.A.K.Mouw@its.tudelft.nl), April 21, 2000 - * (C) Stefan Eletzhofer <stefan.eletzhofer@eletztrick.de>, 2002 - * - * The HackKit has two leds (GPIO 22/23). The red led (gpio 22) is used - * as cpu led, the green one is used as timer led. - */ -#include <linux/init.h> -#include <linux/io.h> - -#include <mach/hardware.h> -#include <asm/leds.h> - -#include "leds.h" - - -#define LED_STATE_ENABLED 1 -#define LED_STATE_CLAIMED 2 - -static unsigned int led_state; -static unsigned int hw_led_state; - -#define LED_GREEN GPIO_GPIO23 -#define LED_RED GPIO_GPIO22 -#define LED_MASK (LED_RED | LED_GREEN) - -void hackkit_leds_event(led_event_t evt) -{ - unsigned long flags; - - local_irq_save(flags); - - switch(evt) { - case led_start: - /* pin 22/23 are outputs */ - GPDR |= LED_MASK; - hw_led_state = LED_MASK; - led_state = LED_STATE_ENABLED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = LED_MASK; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = LED_MASK; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state ^= LED_GREEN; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - /* The LART people like the LED to be off when the - system is idle... */ - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~LED_RED; - break; - - case led_idle_end: - /* ... and on if the system is not idle */ - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= LED_RED; - break; -#endif - - case led_red_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~LED_RED; - break; - - case led_red_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= LED_RED; - break; - - case led_green_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~LED_GREEN; - break; - - case led_green_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= LED_GREEN; - break; - - default: - break; - } - - /* Now set the GPIO state, or nothing will happen at all */ - if (led_state & LED_STATE_ENABLED) { - GPSR = hw_led_state; - GPCR = hw_led_state ^ LED_MASK; - } - - local_irq_restore(flags); -} diff --git a/arch/arm/mach-sa1100/leds-lart.c b/arch/arm/mach-sa1100/leds-lart.c deleted file mode 100644 index 50a5b143b460..000000000000 --- a/arch/arm/mach-sa1100/leds-lart.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * linux/arch/arm/mach-sa1100/leds-lart.c - * - * (C) Erik Mouw (J.A.K.Mouw@its.tudelft.nl), April 21, 2000 - * - * LART uses the LED as follows: - * - GPIO23 is the LED, on if system is not idle - * You can use both CONFIG_LEDS_CPU and CONFIG_LEDS_TIMER at the same - * time, but in that case the timer events will still dictate the - * pace of the LED. - */ -#include <linux/init.h> -#include <linux/io.h> - -#include <mach/hardware.h> -#include <asm/leds.h> - -#include "leds.h" - - -#define LED_STATE_ENABLED 1 -#define LED_STATE_CLAIMED 2 - -static unsigned int led_state; -static unsigned int hw_led_state; - -#define LED_23 GPIO_GPIO23 -#define LED_MASK (LED_23) - -void lart_leds_event(led_event_t evt) -{ - unsigned long flags; - - local_irq_save(flags); - - switch(evt) { - case led_start: - /* pin 23 is output pin */ - GPDR |= LED_23; - hw_led_state = LED_MASK; - led_state = LED_STATE_ENABLED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = LED_MASK; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = LED_MASK; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state ^= LED_23; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - /* The LART people like the LED to be off when the - system is idle... */ - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~LED_23; - break; - - case led_idle_end: - /* ... and on if the system is not idle */ - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= LED_23; - break; -#endif - - case led_red_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~LED_23; - break; - - case led_red_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= LED_23; - break; - - default: - break; - } - - /* Now set the GPIO state, or nothing will happen at all */ - if (led_state & LED_STATE_ENABLED) { - GPSR = hw_led_state; - GPCR = hw_led_state ^ LED_MASK; - } - - local_irq_restore(flags); -} diff --git a/arch/arm/mach-sa1100/leds.c b/arch/arm/mach-sa1100/leds.c deleted file mode 100644 index 5fe71a0f1053..000000000000 --- a/arch/arm/mach-sa1100/leds.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * linux/arch/arm/mach-sa1100/leds.c - * - * SA1100 LEDs dispatcher - * - * Copyright (C) 2001 Nicolas Pitre - */ -#include <linux/compiler.h> -#include <linux/init.h> - -#include <asm/leds.h> -#include <asm/mach-types.h> - -#include "leds.h" - -static int __init -sa1100_leds_init(void) -{ - if (machine_is_assabet()) - leds_event = assabet_leds_event; - if (machine_is_consus()) - leds_event = consus_leds_event; - if (machine_is_badge4()) - leds_event = badge4_leds_event; - if (machine_is_brutus()) - leds_event = brutus_leds_event; - if (machine_is_cerf()) - leds_event = cerf_leds_event; - if (machine_is_flexanet()) - leds_event = flexanet_leds_event; - if (machine_is_graphicsclient()) - leds_event = graphicsclient_leds_event; - if (machine_is_hackkit()) - leds_event = hackkit_leds_event; - if (machine_is_lart()) - leds_event = lart_leds_event; - if (machine_is_pfs168()) - leds_event = pfs168_leds_event; - if (machine_is_graphicsmaster()) - leds_event = graphicsmaster_leds_event; - if (machine_is_adsbitsy()) - leds_event = adsbitsy_leds_event; - if (machine_is_pt_system3()) - leds_event = system3_leds_event; - - leds_event(led_start); - return 0; -} - -core_initcall(sa1100_leds_init); diff --git a/arch/arm/mach-sa1100/leds.h b/arch/arm/mach-sa1100/leds.h deleted file mode 100644 index 776b6020f550..000000000000 --- a/arch/arm/mach-sa1100/leds.h +++ /dev/null @@ -1,13 +0,0 @@ -extern void assabet_leds_event(led_event_t evt); -extern void badge4_leds_event(led_event_t evt); -extern void consus_leds_event(led_event_t evt); -extern void brutus_leds_event(led_event_t evt); -extern void cerf_leds_event(led_event_t evt); -extern void flexanet_leds_event(led_event_t evt); -extern void graphicsclient_leds_event(led_event_t evt); -extern void hackkit_leds_event(led_event_t evt); -extern void lart_leds_event(led_event_t evt); -extern void pfs168_leds_event(led_event_t evt); -extern void graphicsmaster_leds_event(led_event_t evt); -extern void adsbitsy_leds_event(led_event_t evt); -extern void system3_leds_event(led_event_t evt); diff --git a/arch/arm/mach-shark/Makefile b/arch/arm/mach-shark/Makefile index 45be9b04e7ba..29657183c452 100644 --- a/arch/arm/mach-shark/Makefile +++ b/arch/arm/mach-shark/Makefile @@ -4,9 +4,7 @@ # Object file lists. -obj-y := core.o dma.o irq.o pci.o +obj-y := core.o dma.o irq.o pci.o leds.o obj-m := obj-n := obj- := - -obj-$(CONFIG_LEDS) += leds.o diff --git a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c index d35b94ef73b7..9ad2e9737fb5 100644 --- a/arch/arm/mach-shark/core.c +++ b/arch/arm/mach-shark/core.c @@ -13,7 +13,6 @@ #include <asm/setup.h> #include <asm/mach-types.h> -#include <asm/leds.h> #include <asm/param.h> #include <asm/system_misc.h> diff --git a/arch/arm/mach-shark/leds.c b/arch/arm/mach-shark/leds.c index 25609076921f..081c778a10ac 100644 --- a/arch/arm/mach-shark/leds.c +++ b/arch/arm/mach-shark/leds.c @@ -1,165 +1,117 @@ /* - * arch/arm/mach-shark/leds.c - * by Alexander Schulz - * - * derived from: - * arch/arm/kernel/leds-footbridge.c - * Copyright (C) 1998-1999 Russell King - * * DIGITAL Shark LED control routines. * - * The leds use is as follows: - * - Green front - toggles state every 50 timer interrupts - * - Amber front - Unused, this is a dual color led (Amber/Green) - * - Amber back - On if system is not idle + * Driver for the 3 user LEDs found on the Shark + * Based on Versatile and RealView machine LED code * - * Changelog: + * License terms: GNU General Public License (GPL) version 2 + * Author: Bryan Wu <bryan.wu@canonical.com> */ #include <linux/kernel.h> -#include <linux/module.h> #include <linux/init.h> -#include <linux/spinlock.h> -#include <linux/ioport.h> #include <linux/io.h> +#include <linux/ioport.h> +#include <linux/slab.h> +#include <linux/leds.h> -#include <asm/leds.h> +#include <asm/mach-types.h> -#define LED_STATE_ENABLED 1 -#define LED_STATE_CLAIMED 2 +#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) +struct shark_led { + struct led_classdev cdev; + u8 mask; +}; -#define SEQUOIA_LED_GREEN (1<<6) -#define SEQUOIA_LED_AMBER (1<<5) -#define SEQUOIA_LED_BACK (1<<7) +/* + * The triggers lines up below will only be used if the + * LED triggers are compiled in. + */ +static const struct { + const char *name; + const char *trigger; +} shark_leds[] = { + { "shark:amber0", "default-on", }, /* Bit 5 */ + { "shark:green", "heartbeat", }, /* Bit 6 */ + { "shark:amber1", "cpu0" }, /* Bit 7 */ +}; + +static u16 led_reg_read(void) +{ + outw(0x09, 0x24); + return inw(0x26); +} -static char led_state; -static short hw_led_state; -static short saved_state; +static void led_reg_write(u16 value) +{ + outw(0x09, 0x24); + outw(value, 0x26); +} -static DEFINE_RAW_SPINLOCK(leds_lock); +static void shark_led_set(struct led_classdev *cdev, + enum led_brightness b) +{ + struct shark_led *led = container_of(cdev, + struct shark_led, cdev); + u16 reg = led_reg_read(); -short sequoia_read(int addr) { - outw(addr,0x24); - return inw(0x26); -} + if (b != LED_OFF) + reg |= led->mask; + else + reg &= ~led->mask; -void sequoia_write(short value,short addr) { - outw(addr,0x24); - outw(value,0x26); + led_reg_write(reg); } -static void sequoia_leds_event(led_event_t evt) +static enum led_brightness shark_led_get(struct led_classdev *cdev) { - unsigned long flags; - - raw_spin_lock_irqsave(&leds_lock, flags); + struct shark_led *led = container_of(cdev, + struct shark_led, cdev); + u16 reg = led_reg_read(); - hw_led_state = sequoia_read(0x09); + return (reg & led->mask) ? LED_FULL : LED_OFF; +} - switch (evt) { - case led_start: - hw_led_state |= SEQUOIA_LED_GREEN; - hw_led_state |= SEQUOIA_LED_AMBER; -#ifdef CONFIG_LEDS_CPU - hw_led_state |= SEQUOIA_LED_BACK; -#else - hw_led_state &= ~SEQUOIA_LED_BACK; -#endif - led_state |= LED_STATE_ENABLED; - break; - - case led_stop: - hw_led_state &= ~SEQUOIA_LED_BACK; - hw_led_state |= SEQUOIA_LED_GREEN; - hw_led_state |= SEQUOIA_LED_AMBER; - led_state &= ~LED_STATE_ENABLED; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - saved_state = hw_led_state; - hw_led_state &= ~SEQUOIA_LED_BACK; - hw_led_state |= SEQUOIA_LED_GREEN; - hw_led_state |= SEQUOIA_LED_AMBER; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = saved_state; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state ^= SEQUOIA_LED_GREEN; - break; -#endif +static int __init shark_leds_init(void) +{ + int i; + u16 reg; -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~SEQUOIA_LED_BACK; - break; + if (!machine_is_shark()) + return -ENODEV; - case led_idle_end: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= SEQUOIA_LED_BACK; - break; -#endif + for (i = 0; i < ARRAY_SIZE(shark_leds); i++) { + struct shark_led *led; - case led_green_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~SEQUOIA_LED_GREEN; - break; - - case led_green_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= SEQUOIA_LED_GREEN; - break; - - case led_amber_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~SEQUOIA_LED_AMBER; - break; - - case led_amber_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= SEQUOIA_LED_AMBER; - break; - - case led_red_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= SEQUOIA_LED_BACK; - break; - - case led_red_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~SEQUOIA_LED_BACK; - break; - - default: - break; - } + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (!led) + break; - if (led_state & LED_STATE_ENABLED) - sequoia_write(hw_led_state,0x09); + led->cdev.name = shark_leds[i].name; + led->cdev.brightness_set = shark_led_set; + led->cdev.brightness_get = shark_led_get; + led->cdev.default_trigger = shark_leds[i].trigger; - raw_spin_unlock_irqrestore(&leds_lock, flags); -} + /* Count in 5 bits offset */ + led->mask = BIT(i + 5); -static int __init leds_init(void) -{ - extern void (*leds_event)(led_event_t); - short temp; - - leds_event = sequoia_leds_event; + if (led_classdev_register(NULL, &led->cdev) < 0) { + kfree(led); + break; + } + } /* Make LEDs independent of power-state */ - request_region(0x24,4,"sequoia"); - temp = sequoia_read(0x09); - temp |= 1<<10; - sequoia_write(temp,0x09); - leds_event(led_start); + request_region(0x24, 4, "led_reg"); + reg = led_reg_read(); + reg |= 1 << 10; + led_reg_write(reg); + return 0; } -__initcall(leds_init); +/* + * Since we may have triggers on any subsystem, defer registration + * until after subsystem_init. + */ +fs_initcall(shark_leds_init); +#endif diff --git a/arch/arm/mach-tegra/tegra20_clocks_data.c b/arch/arm/mach-tegra/tegra20_clocks_data.c index c8a7b951f759..cc9b5fd8c3d3 100644 --- a/arch/arm/mach-tegra/tegra20_clocks_data.c +++ b/arch/arm/mach-tegra/tegra20_clocks_data.c @@ -917,14 +917,10 @@ PERIPH_CLK(la, "la", NULL, 76, 0x1f8, 26000000, mux_pllp_pllc_pllm_clkm, MUX PERIPH_CLK(owr, "tegra_w1", NULL, 71, 0x1cc, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); PERIPH_CLK(nor, "nor", NULL, 42, 0x1d0, 92000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* requires min voltage */ PERIPH_CLK(mipi, "mipi", NULL, 50, 0x174, 60000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */ -PERIPH_CLK(i2c1, "tegra-i2c.0", NULL, 12, 0x124, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16); -PERIPH_CLK(i2c2, "tegra-i2c.1", NULL, 54, 0x198, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16); -PERIPH_CLK(i2c3, "tegra-i2c.2", NULL, 67, 0x1b8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16); -PERIPH_CLK(dvc, "tegra-i2c.3", NULL, 47, 0x128, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16); -PERIPH_CLK(i2c1_i2c, "tegra-i2c.0", "i2c", 0, 0, 72000000, mux_pllp_out3, 0); -PERIPH_CLK(i2c2_i2c, "tegra-i2c.1", "i2c", 0, 0, 72000000, mux_pllp_out3, 0); -PERIPH_CLK(i2c3_i2c, "tegra-i2c.2", "i2c", 0, 0, 72000000, mux_pllp_out3, 0); -PERIPH_CLK(dvc_i2c, "tegra-i2c.3", "i2c", 0, 0, 72000000, mux_pllp_out3, 0); +PERIPH_CLK(i2c1, "tegra-i2c.0", "div-clk", 12, 0x124, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16); +PERIPH_CLK(i2c2, "tegra-i2c.1", "div-clk", 54, 0x198, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16); +PERIPH_CLK(i2c3, "tegra-i2c.2", "div-clk", 67, 0x1b8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16); +PERIPH_CLK(dvc, "tegra-i2c.3", "div-clk", 47, 0x128, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16); PERIPH_CLK(uarta, "tegra-uart.0", NULL, 6, 0x178, 600000000, mux_pllp_pllc_pllm_clkm, MUX); PERIPH_CLK(uartb, "tegra-uart.1", NULL, 7, 0x17c, 600000000, mux_pllp_pllc_pllm_clkm, MUX); PERIPH_CLK(uartc, "tegra-uart.2", NULL, 55, 0x1a0, 600000000, mux_pllp_pllc_pllm_clkm, MUX); @@ -989,10 +985,6 @@ static struct clk *tegra_list_clks[] = { &tegra_i2c2, &tegra_i2c3, &tegra_dvc, - &tegra_i2c1_i2c, - &tegra_i2c2_i2c, - &tegra_i2c3_i2c, - &tegra_dvc_i2c, &tegra_uarta, &tegra_uartb, &tegra_uartc, @@ -1056,6 +1048,10 @@ static struct clk_duplicate tegra_clk_duplicates[] = { CLK_DUPLICATE("vde", "tegra-aes", "vde"), CLK_DUPLICATE("cclk", NULL, "cpu"), CLK_DUPLICATE("twd", "smp_twd", NULL), + CLK_DUPLICATE("pll_p_out3", "tegra-i2c.0", "fast-clk"), + CLK_DUPLICATE("pll_p_out3", "tegra-i2c.1", "fast-clk"), + CLK_DUPLICATE("pll_p_out3", "tegra-i2c.2", "fast-clk"), + CLK_DUPLICATE("pll_p_out3", "tegra-i2c.3", "fast-clk"), }; #define CLK(dev, con, ck) \ diff --git a/arch/arm/mach-tegra/tegra30_clocks_data.c b/arch/arm/mach-tegra/tegra30_clocks_data.c index c10449603df0..d92cb556ae35 100644 --- a/arch/arm/mach-tegra/tegra30_clocks_data.c +++ b/arch/arm/mach-tegra/tegra30_clocks_data.c @@ -1071,11 +1071,11 @@ PERIPH_CLK(la, "la", NULL, 76, 0x1f8, 26000000, mux_pllp_pllc_pllm_clkm, MUX PERIPH_CLK(owr, "tegra_w1", NULL, 71, 0x1cc, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB); PERIPH_CLK(nor, "nor", NULL, 42, 0x1d0, 127000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* requires min voltage */ PERIPH_CLK(mipi, "mipi", NULL, 50, 0x174, 60000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB); /* scales with voltage */ -PERIPH_CLK(i2c1, "tegra-i2c.0", NULL, 12, 0x124, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB); -PERIPH_CLK(i2c2, "tegra-i2c.1", NULL, 54, 0x198, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB); -PERIPH_CLK(i2c3, "tegra-i2c.2", NULL, 67, 0x1b8, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB); -PERIPH_CLK(i2c4, "tegra-i2c.3", NULL, 103, 0x3c4, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB); -PERIPH_CLK(i2c5, "tegra-i2c.4", NULL, 47, 0x128, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB); +PERIPH_CLK(i2c1, "tegra-i2c.0", "div-clk", 12, 0x124, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB); +PERIPH_CLK(i2c2, "tegra-i2c.1", "div-clk", 54, 0x198, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB); +PERIPH_CLK(i2c3, "tegra-i2c.2", "div-clk", 67, 0x1b8, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB); +PERIPH_CLK(i2c4, "tegra-i2c.3", "div-clk", 103, 0x3c4, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB); +PERIPH_CLK(i2c5, "tegra-i2c.4", "div-clk", 47, 0x128, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB); PERIPH_CLK(uarta, "tegra-uart.0", NULL, 6, 0x178, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB); PERIPH_CLK(uartb, "tegra-uart.1", NULL, 7, 0x17c, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB); PERIPH_CLK(uartc, "tegra-uart.2", NULL, 55, 0x1a0, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB); @@ -1287,6 +1287,11 @@ struct clk_duplicate tegra_clk_duplicates[] = { CLK_DUPLICATE("dam1", NULL, "dam1"), CLK_DUPLICATE("dam2", NULL, "dam2"), CLK_DUPLICATE("spdif_in", NULL, "spdif_in"), + CLK_DUPLICATE("pll_p_out3", "tegra-i2c.0", "fast-clk"), + CLK_DUPLICATE("pll_p_out3", "tegra-i2c.1", "fast-clk"), + CLK_DUPLICATE("pll_p_out3", "tegra-i2c.2", "fast-clk"), + CLK_DUPLICATE("pll_p_out3", "tegra-i2c.3", "fast-clk"), + CLK_DUPLICATE("pll_p_out3", "tegra-i2c.4", "fast-clk"), }; struct clk *tegra_ptr_clks[] = { diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index ca7902c6ed18..5b5c1eeb5b5c 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -37,7 +37,6 @@ #include <linux/mtd/physmap.h> #include <asm/irq.h> -#include <asm/leds.h> #include <asm/hardware/arm_timer.h> #include <asm/hardware/icst.h> #include <asm/hardware/vic.h> @@ -758,10 +757,6 @@ void __init versatile_init(void) struct amba_device *d = amba_devs[i]; amba_device_register(d, &iomem_resource); } - -#ifdef CONFIG_LEDS - leds_event = versatile_leds_event; -#endif } /* diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index d15a4a6d6146..ca83a7659aef 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -42,9 +42,8 @@ config OMAP_DEBUG_DEVICES For debug cards on TI reference boards. config OMAP_DEBUG_LEDS - bool + def_bool y if NEW_LEDS depends on OMAP_DEBUG_DEVICES - default y if LEDS_CLASS config POWER_AVS_OMAP bool "AVS(Adaptive Voltage Scaling) support for OMAP IP versions 1&2" diff --git a/arch/arm/plat-omap/debug-leds.c b/arch/arm/plat-omap/debug-leds.c index 195aaae65872..ea29bbe8e5cf 100644 --- a/arch/arm/plat-omap/debug-leds.c +++ b/arch/arm/plat-omap/debug-leds.c @@ -1,280 +1,119 @@ /* * linux/arch/arm/plat-omap/debug-leds.c * + * Copyright 2011 by Bryan Wu <bryan.wu@canonical.com> * Copyright 2003 by Texas Instruments Incorporated * * 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 <linux/gpio.h> + +#include <linux/kernel.h> #include <linux/init.h> #include <linux/platform_device.h> #include <linux/leds.h> #include <linux/io.h> #include <linux/platform_data/gpio-omap.h> +#include <linux/slab.h> #include <mach/hardware.h> -#include <asm/leds.h> #include <asm/mach-types.h> #include <plat/fpga.h> - /* Many OMAP development platforms reuse the same "debug board"; these * platforms include H2, H3, H4, and Perseus2. There are 16 LEDs on the * debug board (all green), accessed through FPGA registers. - * - * The "surfer" expansion board and H2 sample board also have two-color - * green+red LEDs (in parallel), used here for timer and idle indicators - * in preference to the ones on the debug board, for a "Disco LED" effect. - * - * This driver exports either the original ARM LED API, the new generic - * one, or both. - */ - -static spinlock_t lock; -static struct h2p2_dbg_fpga __iomem *fpga; -static u16 led_state, hw_led_state; - - -#ifdef CONFIG_OMAP_DEBUG_LEDS -#define new_led_api() 1 -#else -#define new_led_api() 0 -#endif - - -/*-------------------------------------------------------------------------*/ - -/* original ARM debug LED API: - * - timer and idle leds (some boards use non-FPGA leds here); - * - up to 4 generic leds, easily accessed in-kernel (any context) */ -#define GPIO_LED_RED 3 -#define GPIO_LED_GREEN OMAP_MPUIO(4) - -#define LED_STATE_ENABLED 0x01 -#define LED_STATE_CLAIMED 0x02 -#define LED_TIMER_ON 0x04 - -#define GPIO_IDLE GPIO_LED_GREEN -#define GPIO_TIMER GPIO_LED_RED - -static void h2p2_dbg_leds_event(led_event_t evt) -{ - unsigned long flags; - - spin_lock_irqsave(&lock, flags); - - if (!(led_state & LED_STATE_ENABLED) && evt != led_start) - goto done; - - switch (evt) { - case led_start: - if (fpga) - led_state |= LED_STATE_ENABLED; - break; - - case led_stop: - case led_halted: - /* all leds off during suspend or shutdown */ - - if (!(machine_is_omap_perseus2() || machine_is_omap_h4())) { - gpio_set_value(GPIO_TIMER, 0); - gpio_set_value(GPIO_IDLE, 0); - } - - __raw_writew(~0, &fpga->leds); - led_state &= ~LED_STATE_ENABLED; - goto done; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = 0; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - led_state ^= LED_TIMER_ON; - - if (machine_is_omap_perseus2() || machine_is_omap_h4()) - hw_led_state ^= H2P2_DBG_FPGA_P2_LED_TIMER; - else { - gpio_set_value(GPIO_TIMER, - led_state & LED_TIMER_ON); - goto done; - } - - break; -#endif - -#ifdef CONFIG_LEDS_CPU - /* LED lit iff busy */ - case led_idle_start: - if (machine_is_omap_perseus2() || machine_is_omap_h4()) - hw_led_state &= ~H2P2_DBG_FPGA_P2_LED_IDLE; - else { - gpio_set_value(GPIO_IDLE, 1); - goto done; - } - - break; +static struct h2p2_dbg_fpga __iomem *fpga; - case led_idle_end: - if (machine_is_omap_perseus2() || machine_is_omap_h4()) - hw_led_state |= H2P2_DBG_FPGA_P2_LED_IDLE; - else { - gpio_set_value(GPIO_IDLE, 0); - goto done; - } - - break; -#endif - - case led_green_on: - hw_led_state |= H2P2_DBG_FPGA_LED_GREEN; - break; - case led_green_off: - hw_led_state &= ~H2P2_DBG_FPGA_LED_GREEN; - break; - - case led_amber_on: - hw_led_state |= H2P2_DBG_FPGA_LED_AMBER; - break; - case led_amber_off: - hw_led_state &= ~H2P2_DBG_FPGA_LED_AMBER; - break; - - case led_red_on: - hw_led_state |= H2P2_DBG_FPGA_LED_RED; - break; - case led_red_off: - hw_led_state &= ~H2P2_DBG_FPGA_LED_RED; - break; - - case led_blue_on: - hw_led_state |= H2P2_DBG_FPGA_LED_BLUE; - break; - case led_blue_off: - hw_led_state &= ~H2P2_DBG_FPGA_LED_BLUE; - break; - - default: - break; - } - - - /* - * Actually burn the LEDs - */ - if (led_state & LED_STATE_ENABLED) - __raw_writew(~hw_led_state, &fpga->leds); - -done: - spin_unlock_irqrestore(&lock, flags); -} - -/*-------------------------------------------------------------------------*/ - -/* "new" LED API - * - with syfs access and generic triggering - * - not readily accessible to in-kernel drivers - */ +static u16 fpga_led_state; struct dbg_led { struct led_classdev cdev; u16 mask; }; -static struct dbg_led dbg_leds[] = { - /* REVISIT at least H2 uses different timer & cpu leds... */ -#ifndef CONFIG_LEDS_TIMER - { .mask = 1 << 0, .cdev.name = "d4:green", - .cdev.default_trigger = "heartbeat", }, -#endif -#ifndef CONFIG_LEDS_CPU - { .mask = 1 << 1, .cdev.name = "d5:green", }, /* !idle */ -#endif - { .mask = 1 << 2, .cdev.name = "d6:green", }, - { .mask = 1 << 3, .cdev.name = "d7:green", }, - - { .mask = 1 << 4, .cdev.name = "d8:green", }, - { .mask = 1 << 5, .cdev.name = "d9:green", }, - { .mask = 1 << 6, .cdev.name = "d10:green", }, - { .mask = 1 << 7, .cdev.name = "d11:green", }, - - { .mask = 1 << 8, .cdev.name = "d12:green", }, - { .mask = 1 << 9, .cdev.name = "d13:green", }, - { .mask = 1 << 10, .cdev.name = "d14:green", }, - { .mask = 1 << 11, .cdev.name = "d15:green", }, - -#ifndef CONFIG_LEDS - { .mask = 1 << 12, .cdev.name = "d16:green", }, - { .mask = 1 << 13, .cdev.name = "d17:green", }, - { .mask = 1 << 14, .cdev.name = "d18:green", }, - { .mask = 1 << 15, .cdev.name = "d19:green", }, -#endif +static const struct { + const char *name; + const char *trigger; +} dbg_leds[] = { + { "dbg:d4", "heartbeat", }, + { "dbg:d5", "cpu0", }, + { "dbg:d6", "default-on", }, + { "dbg:d7", }, + { "dbg:d8", }, + { "dbg:d9", }, + { "dbg:d10", }, + { "dbg:d11", }, + { "dbg:d12", }, + { "dbg:d13", }, + { "dbg:d14", }, + { "dbg:d15", }, + { "dbg:d16", }, + { "dbg:d17", }, + { "dbg:d18", }, + { "dbg:d19", }, }; -static void -fpga_led_set(struct led_classdev *cdev, enum led_brightness value) +/* + * The triggers lines up below will only be used if the + * LED triggers are compiled in. + */ +static void dbg_led_set(struct led_classdev *cdev, + enum led_brightness b) { - struct dbg_led *led = container_of(cdev, struct dbg_led, cdev); - unsigned long flags; + struct dbg_led *led = container_of(cdev, struct dbg_led, cdev); + u16 reg; - spin_lock_irqsave(&lock, flags); - if (value == LED_OFF) - hw_led_state &= ~led->mask; + reg = __raw_readw(&fpga->leds); + if (b != LED_OFF) + reg |= led->mask; else - hw_led_state |= led->mask; - __raw_writew(~hw_led_state, &fpga->leds); - spin_unlock_irqrestore(&lock, flags); + reg &= ~led->mask; + __raw_writew(reg, &fpga->leds); } -static void __init newled_init(struct device *dev) +static enum led_brightness dbg_led_get(struct led_classdev *cdev) { - unsigned i; - struct dbg_led *led; - int status; + struct dbg_led *led = container_of(cdev, struct dbg_led, cdev); + u16 reg; - for (i = 0, led = dbg_leds; i < ARRAY_SIZE(dbg_leds); i++, led++) { - led->cdev.brightness_set = fpga_led_set; - status = led_classdev_register(dev, &led->cdev); - if (status < 0) - break; - } - return; + reg = __raw_readw(&fpga->leds); + return (reg & led->mask) ? LED_FULL : LED_OFF; } - -/*-------------------------------------------------------------------------*/ - -static int /* __init */ fpga_probe(struct platform_device *pdev) +static int fpga_probe(struct platform_device *pdev) { struct resource *iomem; - - spin_lock_init(&lock); + int i; iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!iomem) return -ENODEV; fpga = ioremap(iomem->start, H2P2_DBG_FPGA_SIZE); - __raw_writew(~0, &fpga->leds); + __raw_writew(0xff, &fpga->leds); + + for (i = 0; i < ARRAY_SIZE(dbg_leds); i++) { + struct dbg_led *led; + + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (!led) + break; -#ifdef CONFIG_LEDS - leds_event = h2p2_dbg_leds_event; - leds_event(led_start); -#endif + led->cdev.name = dbg_leds[i].name; + led->cdev.brightness_set = dbg_led_set; + led->cdev.brightness_get = dbg_led_get; + led->cdev.default_trigger = dbg_leds[i].trigger; + led->mask = BIT(i); - if (new_led_api()) { - newled_init(&pdev->dev); + if (led_classdev_register(NULL, &led->cdev) < 0) { + kfree(led); + break; + } } return 0; @@ -282,13 +121,15 @@ static int /* __init */ fpga_probe(struct platform_device *pdev) static int fpga_suspend_noirq(struct device *dev) { - __raw_writew(~0, &fpga->leds); + fpga_led_state = __raw_readw(&fpga->leds); + __raw_writew(0xff, &fpga->leds); + return 0; } static int fpga_resume_noirq(struct device *dev) { - __raw_writew(~hw_led_state, &fpga->leds); + __raw_writew(~fpga_led_state, &fpga->leds); return 0; } diff --git a/arch/arm/plat-samsung/time.c b/arch/arm/plat-samsung/time.c index 4dcb11c3d894..60552e22f22e 100644 --- a/arch/arm/plat-samsung/time.c +++ b/arch/arm/plat-samsung/time.c @@ -28,7 +28,6 @@ #include <linux/io.h> #include <linux/platform_device.h> -#include <asm/leds.h> #include <asm/mach-types.h> #include <asm/irq.h> diff --git a/arch/arm/plat-versatile/Kconfig b/arch/arm/plat-versatile/Kconfig index 8d5c10a5084d..2a4ae8a6a081 100644 --- a/arch/arm/plat-versatile/Kconfig +++ b/arch/arm/plat-versatile/Kconfig @@ -16,8 +16,10 @@ config PLAT_VERSATILE_FPGA_IRQ_NR depends on PLAT_VERSATILE_FPGA_IRQ config PLAT_VERSATILE_LEDS - def_bool y if LEDS_CLASS + def_bool y if NEW_LEDS depends on ARCH_REALVIEW || ARCH_VERSATILE + select LEDS_CLASS + select LEDS_TRIGGER config PLAT_VERSATILE_SCHED_CLOCK def_bool y diff --git a/arch/arm/plat-versatile/leds.c b/arch/arm/plat-versatile/leds.c index 3169fa555ea6..d2490d00b46c 100644 --- a/arch/arm/plat-versatile/leds.c +++ b/arch/arm/plat-versatile/leds.c @@ -37,10 +37,10 @@ static const struct { } versatile_leds[] = { { "versatile:0", "heartbeat", }, { "versatile:1", "mmc0", }, - { "versatile:2", }, - { "versatile:3", }, - { "versatile:4", }, - { "versatile:5", }, + { "versatile:2", "cpu0" }, + { "versatile:3", "cpu1" }, + { "versatile:4", "cpu2" }, + { "versatile:5", "cpu3" }, { "versatile:6", }, { "versatile:7", }, }; diff --git a/drivers/Kconfig b/drivers/Kconfig index 36d3daa19a74..dbdefa3fe775 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -2,6 +2,8 @@ menu "Device Drivers" source "drivers/base/Kconfig" +source "drivers/bus/Kconfig" + source "drivers/connector/Kconfig" source "drivers/mtd/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 8c30e73cd94c..acb48fa4531c 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -6,6 +6,7 @@ # obj-y += irqchip/ +obj-y += bus/ # GPIO must come after pinctrl as gpios may need to mux pins etc obj-y += pinctrl/ diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig new file mode 100644 index 000000000000..bbec35d21fe5 --- /dev/null +++ b/drivers/bus/Kconfig @@ -0,0 +1,21 @@ +# +# Bus Devices +# + +menu "Bus devices" + +config OMAP_OCP2SCP + tristate "OMAP OCP2SCP DRIVER" + help + Driver to enable ocp2scp module which transforms ocp interface + protocol to scp protocol. In OMAP4, USB PHY is connected via + OCP2SCP and in OMAP5, both USB PHY and SATA PHY is connected via + OCP2SCP. + +config OMAP_INTERCONNECT + tristate "OMAP INTERCONNECT DRIVER" + depends on ARCH_OMAP2PLUS + + help + Driver to enable OMAP interconnect error handling driver. +endmenu diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile new file mode 100644 index 000000000000..45d997c85453 --- /dev/null +++ b/drivers/bus/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the bus drivers. +# + +obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o + +# Interconnect bus driver for OMAP SoCs. +obj-$(CONFIG_OMAP_INTERCONNECT) += omap_l3_smx.o omap_l3_noc.o diff --git a/drivers/bus/omap-ocp2scp.c b/drivers/bus/omap-ocp2scp.c new file mode 100644 index 000000000000..ff63560b8467 --- /dev/null +++ b/drivers/bus/omap-ocp2scp.c @@ -0,0 +1,88 @@ +/* + * omap-ocp2scp.c - transform ocp interface protocol to scp protocol + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com + * 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. + * + * Author: Kishon Vijay Abraham I <kishon@ti.com> + * + * 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 <linux/module.h> +#include <linux/platform_device.h> +#include <linux/err.h> +#include <linux/pm_runtime.h> +#include <linux/of.h> +#include <linux/of_platform.h> + +static int ocp2scp_remove_devices(struct device *dev, void *c) +{ + struct platform_device *pdev = to_platform_device(dev); + + platform_device_unregister(pdev); + + return 0; +} + +static int __devinit omap_ocp2scp_probe(struct platform_device *pdev) +{ + int ret; + struct device_node *np = pdev->dev.of_node; + + if (np) { + ret = of_platform_populate(np, NULL, NULL, &pdev->dev); + if (ret) { + dev_err(&pdev->dev, "failed to add resources for ocp2scp child\n"); + goto err0; + } + } + pm_runtime_enable(&pdev->dev); + + return 0; + +err0: + device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices); + + return ret; +} + +static int __devexit omap_ocp2scp_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id omap_ocp2scp_id_table[] = { + { .compatible = "ti,omap-ocp2scp" }, + {} +}; +MODULE_DEVICE_TABLE(of, omap_ocp2scp_id_table); +#endif + +static struct platform_driver omap_ocp2scp_driver = { + .probe = omap_ocp2scp_probe, + .remove = __devexit_p(omap_ocp2scp_remove), + .driver = { + .name = "omap-ocp2scp", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(omap_ocp2scp_id_table), + }, +}; + +module_platform_driver(omap_ocp2scp_driver); + +MODULE_ALIAS("platform: omap-ocp2scp"); +MODULE_AUTHOR("Texas Instruments Inc."); +MODULE_DESCRIPTION("OMAP OCP2SCP driver"); +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-omap2/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index f447e02102bb..44b2b3e57882 100644 --- a/arch/arm/mach-omap2/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -191,7 +191,7 @@ static int __devinit omap4_l3_probe(struct platform_device *pdev) IRQF_DISABLED, "l3-dbg-irq", l3); if (ret) { pr_crit("L3: request_irq failed to register for 0x%x\n", - 9 + OMAP44XX_IRQ_GIC_START); + l3->debug_irq); goto err3; } @@ -201,7 +201,7 @@ static int __devinit omap4_l3_probe(struct platform_device *pdev) IRQF_DISABLED, "l3-app-irq", l3); if (ret) { pr_crit("L3: request_irq failed to register for 0x%x\n", - 10 + OMAP44XX_IRQ_GIC_START); + l3->app_irq); goto err4; } diff --git a/arch/arm/mach-omap2/omap_l3_noc.h b/drivers/bus/omap_l3_noc.h index a6ce34dc4814..a6ce34dc4814 100644 --- a/arch/arm/mach-omap2/omap_l3_noc.h +++ b/drivers/bus/omap_l3_noc.h diff --git a/arch/arm/mach-omap2/omap_l3_smx.c b/drivers/bus/omap_l3_smx.c index acc216491b8a..acc216491b8a 100644 --- a/arch/arm/mach-omap2/omap_l3_smx.c +++ b/drivers/bus/omap_l3_smx.c diff --git a/arch/arm/mach-omap2/omap_l3_smx.h b/drivers/bus/omap_l3_smx.h index 4f3cebca4179..4f3cebca4179 100644 --- a/arch/arm/mach-omap2/omap_l3_smx.h +++ b/drivers/bus/omap_l3_smx.h diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c index d45c3345b4af..a0e2f7d70355 100644 --- a/drivers/char/nwflash.c +++ b/drivers/char/nwflash.c @@ -30,7 +30,6 @@ #include <asm/hardware/dec21285.h> #include <asm/io.h> -#include <asm/leds.h> #include <asm/mach-types.h> #include <asm/uaccess.h> @@ -179,9 +178,6 @@ static ssize_t flash_write(struct file *file, const char __user *buf, written = 0; - leds_event(led_claim); - leds_event(led_green_on); - nBlock = (int) p >> 16; //block # of 64K bytes /* @@ -258,11 +254,6 @@ static ssize_t flash_write(struct file *file, const char __user *buf, printk(KERN_DEBUG "flash_write: written 0x%X bytes OK.\n", written); } - /* - * restore reg on exit - */ - leds_event(led_release); - mutex_unlock(&nwflash_mutex); return written; @@ -334,11 +325,6 @@ static int erase_block(int nBlock) int temp, temp1; /* - * orange LED == erase - */ - leds_event(led_amber_on); - - /* * reset footbridge to the correct offset 0 (...0..3) */ *CSR_ROMWRITEREG = 0; @@ -446,12 +432,6 @@ static int write_block(unsigned long p, const char __user *buf, int count) unsigned long timeout; unsigned long timeout1; - /* - * red LED == write - */ - leds_event(led_amber_off); - leds_event(led_red_on); - pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p)); /* @@ -558,17 +538,9 @@ static int write_block(unsigned long p, const char __user *buf, int count) pWritePtr - FLASH_BASE); /* - * no LED == waiting - */ - leds_event(led_amber_off); - /* * wait couple ms */ msleep(10); - /* - * red LED == write - */ - leds_event(led_red_on); goto WriteRetry; } else { @@ -583,12 +555,6 @@ static int write_block(unsigned long p, const char __user *buf, int count) } } - /* - * green LED == read/verify - */ - leds_event(led_amber_off); - leds_event(led_green_on); - msleep(10); pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p)); diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index 8af4b06e80f7..a006f0db15af 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -2797,6 +2797,27 @@ static __init void exynos4_gpiolib_init(void) int group = 0; void __iomem *gpx_base; +#ifdef CONFIG_PINCTRL_SAMSUNG + /* + * This gpio driver includes support for device tree support and + * there are platforms using it. In order to maintain + * compatibility with those platforms, and to allow non-dt + * Exynos4210 platforms to use this gpiolib support, a check + * is added to find out if there is a active pin-controller + * driver support available. If it is available, this gpiolib + * support is ignored and the gpiolib support available in + * pin-controller driver is used. This is a temporary check and + * will go away when all of the Exynos4210 platforms have + * switched to using device tree and the pin-ctrl driver. + */ + struct device_node *pctrl_np; + const char *pctrl_compat = "samsung,pinctrl-exynos4210"; + pctrl_np = of_find_compatible_node(NULL, NULL, pctrl_compat); + if (pctrl_np) + if (of_device_is_available(pctrl_np)) + return; +#endif + /* gpio part1 */ gpio_base1 = ioremap(EXYNOS4_PA_GPIO1, SZ_4K); if (gpio_base1 == NULL) { diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 9a08c57bc936..f981ac4e6783 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -27,6 +27,7 @@ #include <linux/slab.h> #include <linux/i2c-tegra.h> #include <linux/of_i2c.h> +#include <linux/of_device.h> #include <linux/module.h> #include <asm/unaligned.h> @@ -114,11 +115,21 @@ enum msg_end_type { }; /** + * struct tegra_i2c_hw_feature : Different HW support on Tegra + * @has_continue_xfer_support: Continue transfer supports. + */ + +struct tegra_i2c_hw_feature { + bool has_continue_xfer_support; +}; + +/** * struct tegra_i2c_dev - per device i2c context * @dev: device reference for power management + * @hw: Tegra i2c hw feature. * @adapter: core i2c layer adapter information - * @clk: clock reference for i2c controller - * @i2c_clk: clock reference for i2c bus + * @div_clk: clock reference for div clock of i2c controller. + * @fast_clk: clock reference for fast clock of i2c controller. * @base: ioremapped registers cookie * @cont_id: i2c controller id, used for for packet header * @irq: irq number of transfer complete interrupt @@ -133,9 +144,10 @@ enum msg_end_type { */ struct tegra_i2c_dev { struct device *dev; + const struct tegra_i2c_hw_feature *hw; struct i2c_adapter adapter; - struct clk *clk; - struct clk *i2c_clk; + struct clk *div_clk; + struct clk *fast_clk; void __iomem *base; int cont_id; int irq; @@ -351,16 +363,40 @@ static void tegra_dvc_init(struct tegra_i2c_dev *i2c_dev) dvc_writel(i2c_dev, val, DVC_CTRL_REG1); } +static inline int tegra_i2c_clock_enable(struct tegra_i2c_dev *i2c_dev) +{ + int ret; + ret = clk_prepare_enable(i2c_dev->fast_clk); + if (ret < 0) { + dev_err(i2c_dev->dev, + "Enabling fast clk failed, err %d\n", ret); + return ret; + } + ret = clk_prepare_enable(i2c_dev->div_clk); + if (ret < 0) { + dev_err(i2c_dev->dev, + "Enabling div clk failed, err %d\n", ret); + clk_disable_unprepare(i2c_dev->fast_clk); + } + return ret; +} + +static inline void tegra_i2c_clock_disable(struct tegra_i2c_dev *i2c_dev) +{ + clk_disable_unprepare(i2c_dev->div_clk); + clk_disable_unprepare(i2c_dev->fast_clk); +} + static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) { u32 val; int err = 0; - clk_prepare_enable(i2c_dev->clk); + tegra_i2c_clock_enable(i2c_dev); - tegra_periph_reset_assert(i2c_dev->clk); + tegra_periph_reset_assert(i2c_dev->div_clk); udelay(2); - tegra_periph_reset_deassert(i2c_dev->clk); + tegra_periph_reset_deassert(i2c_dev->div_clk); if (i2c_dev->is_dvc) tegra_dvc_init(i2c_dev); @@ -369,7 +405,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT); i2c_writel(i2c_dev, val, I2C_CNFG); i2c_writel(i2c_dev, 0, I2C_INT_MASK); - clk_set_rate(i2c_dev->clk, i2c_dev->bus_clk_rate * 8); + clk_set_rate(i2c_dev->div_clk, i2c_dev->bus_clk_rate * 8); if (!i2c_dev->is_dvc) { u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG); @@ -387,7 +423,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) if (tegra_i2c_flush_fifos(i2c_dev)) err = -ETIMEDOUT; - clk_disable_unprepare(i2c_dev->clk); + tegra_i2c_clock_disable(i2c_dev); if (i2c_dev->irq_disabled) { i2c_dev->irq_disabled = 0; @@ -563,7 +599,7 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], if (i2c_dev->is_suspended) return -EBUSY; - clk_prepare_enable(i2c_dev->clk); + tegra_i2c_clock_enable(i2c_dev); for (i = 0; i < num; i++) { enum msg_end_type end_type = MSG_END_STOP; if (i < (num - 1)) { @@ -576,14 +612,19 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], if (ret) break; } - clk_disable_unprepare(i2c_dev->clk); + tegra_i2c_clock_disable(i2c_dev); return ret ?: i; } static u32 tegra_i2c_func(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | - I2C_FUNC_PROTOCOL_MANGLING | I2C_FUNC_NOSTART; + struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap); + u32 ret = I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | + I2C_FUNC_PROTOCOL_MANGLING; + + if (i2c_dev->hw->has_continue_xfer_support) + ret |= I2C_FUNC_NOSTART; + return ret; } static const struct i2c_algorithm tegra_i2c_algo = { @@ -591,13 +632,32 @@ static const struct i2c_algorithm tegra_i2c_algo = { .functionality = tegra_i2c_func, }; +static const struct tegra_i2c_hw_feature tegra20_i2c_hw = { + .has_continue_xfer_support = false, +}; + +static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { + .has_continue_xfer_support = true, +}; + +#if defined(CONFIG_OF) +/* Match table for of_platform binding */ +static const struct of_device_id tegra_i2c_of_match[] __devinitconst = { + { .compatible = "nvidia,tegra30-i2c", .data = &tegra30_i2c_hw, }, + { .compatible = "nvidia,tegra20-i2c", .data = &tegra20_i2c_hw, }, + { .compatible = "nvidia,tegra20-i2c-dvc", .data = &tegra20_i2c_hw, }, + {}, +}; +MODULE_DEVICE_TABLE(of, tegra_i2c_of_match); +#endif + static int __devinit tegra_i2c_probe(struct platform_device *pdev) { struct tegra_i2c_dev *i2c_dev; struct tegra_i2c_platform_data *pdata = pdev->dev.platform_data; struct resource *res; - struct clk *clk; - struct clk *i2c_clk; + struct clk *div_clk; + struct clk *fast_clk; const unsigned int *prop; void __iomem *base; int irq; @@ -622,16 +682,16 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev) } irq = res->start; - clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(clk)) { + div_clk = devm_clk_get(&pdev->dev, "div-clk"); + if (IS_ERR(div_clk)) { dev_err(&pdev->dev, "missing controller clock"); - return PTR_ERR(clk); + return PTR_ERR(div_clk); } - i2c_clk = devm_clk_get(&pdev->dev, "i2c"); - if (IS_ERR(i2c_clk)) { + fast_clk = devm_clk_get(&pdev->dev, "fast-clk"); + if (IS_ERR(fast_clk)) { dev_err(&pdev->dev, "missing bus clock"); - return PTR_ERR(i2c_clk); + return PTR_ERR(fast_clk); } i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); @@ -641,8 +701,8 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev) } i2c_dev->base = base; - i2c_dev->clk = clk; - i2c_dev->i2c_clk = i2c_clk; + i2c_dev->div_clk = div_clk; + i2c_dev->fast_clk = fast_clk; i2c_dev->adapter.algo = &tegra_i2c_algo; i2c_dev->irq = irq; i2c_dev->cont_id = pdev->id; @@ -659,11 +719,18 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev) i2c_dev->bus_clk_rate = be32_to_cpup(prop); } - if (pdev->dev.of_node) + i2c_dev->hw = &tegra20_i2c_hw; + + if (pdev->dev.of_node) { + const struct of_device_id *match; + match = of_match_device(of_match_ptr(tegra_i2c_of_match), + &pdev->dev); + i2c_dev->hw = match->data; i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node, "nvidia,tegra20-i2c-dvc"); - else if (pdev->id == 3) + } else if (pdev->id == 3) { i2c_dev->is_dvc = 1; + } init_completion(&i2c_dev->msg_complete); platform_set_drvdata(pdev, i2c_dev); @@ -681,8 +748,6 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev) return ret; } - clk_prepare_enable(i2c_dev->i2c_clk); - i2c_set_adapdata(&i2c_dev->adapter, i2c_dev); i2c_dev->adapter.owner = THIS_MODULE; i2c_dev->adapter.class = I2C_CLASS_HWMON; @@ -696,7 +761,6 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev) ret = i2c_add_numbered_adapter(&i2c_dev->adapter); if (ret) { dev_err(&pdev->dev, "Failed to add I2C adapter\n"); - clk_disable_unprepare(i2c_dev->i2c_clk); return ret; } @@ -751,16 +815,6 @@ static SIMPLE_DEV_PM_OPS(tegra_i2c_pm, tegra_i2c_suspend, tegra_i2c_resume); #define TEGRA_I2C_PM NULL #endif -#if defined(CONFIG_OF) -/* Match table for of_platform binding */ -static const struct of_device_id tegra_i2c_of_match[] __devinitconst = { - { .compatible = "nvidia,tegra20-i2c", }, - { .compatible = "nvidia,tegra20-i2c-dvc", }, - {}, -}; -MODULE_DEVICE_TABLE(of, tegra_i2c_of_match); -#endif - static struct platform_driver tegra_i2c_driver = { .probe = tegra_i2c_probe, .remove = __devexit_p(tegra_i2c_remove), diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index c96bbaadeebd..16578d3b52bb 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -506,6 +506,16 @@ config LEDS_TRIGGER_BACKLIGHT If unsure, say N. +config LEDS_TRIGGER_CPU + bool "LED CPU Trigger" + depends on LEDS_TRIGGERS + help + This allows LEDs to be controlled by active CPUs. This shows + the active CPUs across an array of LEDs so you can see which + CPUs are active on the system at any given moment. + + If unsure, say N. + config LEDS_TRIGGER_GPIO tristate "LED GPIO Trigger" depends on LEDS_TRIGGERS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index a4429a9217bc..a9b627c4f8ba 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -61,5 +61,6 @@ obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o obj-$(CONFIG_LEDS_TRIGGER_GPIO) += ledtrig-gpio.o +obj-$(CONFIG_LEDS_TRIGGER_CPU) += ledtrig-cpu.o obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT) += ledtrig-transient.o diff --git a/drivers/leds/ledtrig-cpu.c b/drivers/leds/ledtrig-cpu.c new file mode 100644 index 000000000000..b312056da14d --- /dev/null +++ b/drivers/leds/ledtrig-cpu.c @@ -0,0 +1,163 @@ +/* + * ledtrig-cpu.c - LED trigger based on CPU activity + * + * This LED trigger will be registered for each possible CPU and named as + * cpu0, cpu1, cpu2, cpu3, etc. + * + * It can be bound to any LED just like other triggers using either a + * board file or via sysfs interface. + * + * An API named ledtrig_cpu is exported for any user, who want to add CPU + * activity indication in their code + * + * Copyright 2011 Linus Walleij <linus.walleij@linaro.org> + * Copyright 2011 - 2012 Bryan Wu <bryan.wu@canonical.com> + * + * 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 <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/percpu.h> +#include <linux/syscore_ops.h> +#include <linux/rwsem.h> +#include "leds.h" + +#define MAX_NAME_LEN 8 + +struct led_trigger_cpu { + char name[MAX_NAME_LEN]; + struct led_trigger *_trig; + struct mutex lock; + int lock_is_inited; +}; + +static DEFINE_PER_CPU(struct led_trigger_cpu, cpu_trig); + +/** + * ledtrig_cpu - emit a CPU event as a trigger + * @evt: CPU event to be emitted + * + * Emit a CPU event on a CPU core, which will trigger a + * binded LED to turn on or turn off. + */ +void ledtrig_cpu(enum cpu_led_event ledevt) +{ + struct led_trigger_cpu *trig = &__get_cpu_var(cpu_trig); + + /* mutex lock should be initialized before calling mutex_call() */ + if (!trig->lock_is_inited) + return; + + mutex_lock(&trig->lock); + + /* Locate the correct CPU LED */ + switch (ledevt) { + case CPU_LED_IDLE_END: + case CPU_LED_START: + /* Will turn the LED on, max brightness */ + led_trigger_event(trig->_trig, LED_FULL); + break; + + case CPU_LED_IDLE_START: + case CPU_LED_STOP: + case CPU_LED_HALTED: + /* Will turn the LED off */ + led_trigger_event(trig->_trig, LED_OFF); + break; + + default: + /* Will leave the LED as it is */ + break; + } + + mutex_unlock(&trig->lock); +} +EXPORT_SYMBOL(ledtrig_cpu); + +static int ledtrig_cpu_syscore_suspend(void) +{ + ledtrig_cpu(CPU_LED_STOP); + return 0; +} + +static void ledtrig_cpu_syscore_resume(void) +{ + ledtrig_cpu(CPU_LED_START); +} + +static void ledtrig_cpu_syscore_shutdown(void) +{ + ledtrig_cpu(CPU_LED_HALTED); +} + +static struct syscore_ops ledtrig_cpu_syscore_ops = { + .shutdown = ledtrig_cpu_syscore_shutdown, + .suspend = ledtrig_cpu_syscore_suspend, + .resume = ledtrig_cpu_syscore_resume, +}; + +static int __init ledtrig_cpu_init(void) +{ + int cpu; + + /* Supports up to 9999 cpu cores */ + BUILD_BUG_ON(CONFIG_NR_CPUS > 9999); + + /* + * Registering CPU led trigger for each CPU core here + * ignores CPU hotplug, but after this CPU hotplug works + * fine with this trigger. + */ + for_each_possible_cpu(cpu) { + struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu); + + mutex_init(&trig->lock); + + snprintf(trig->name, MAX_NAME_LEN, "cpu%d", cpu); + + mutex_lock(&trig->lock); + led_trigger_register_simple(trig->name, &trig->_trig); + trig->lock_is_inited = 1; + mutex_unlock(&trig->lock); + } + + register_syscore_ops(&ledtrig_cpu_syscore_ops); + + pr_info("ledtrig-cpu: registered to indicate activity on CPUs\n"); + + return 0; +} +module_init(ledtrig_cpu_init); + +static void __exit ledtrig_cpu_exit(void) +{ + int cpu; + + for_each_possible_cpu(cpu) { + struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu); + + mutex_lock(&trig->lock); + + led_trigger_unregister_simple(trig->_trig); + trig->_trig = NULL; + memset(trig->name, 0, MAX_NAME_LEN); + trig->lock_is_inited = 0; + + mutex_unlock(&trig->lock); + mutex_destroy(&trig->lock); + } + + unregister_syscore_ops(&ledtrig_cpu_syscore_ops); +} +module_exit(ledtrig_cpu_exit); + +MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); +MODULE_AUTHOR("Bryan Wu <bryan.wu@canonical.com>"); +MODULE_DESCRIPTION("CPU LED trigger"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 8ca417614c57..598cd0a3adee 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -406,46 +406,6 @@ config MTD_NAND_ATMEL help Enables support for NAND Flash / Smart Media Card interface on Atmel AT91 and AVR32 processors. -choice - prompt "ECC management for NAND Flash / SmartMedia on AT91 / AVR32" - depends on MTD_NAND_ATMEL - -config MTD_NAND_ATMEL_ECC_HW - bool "Hardware ECC" - depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9260 || AVR32 - help - Use hardware ECC instead of software ECC when the chip - supports it. - - The hardware ECC controller is capable of single bit error - correction and 2-bit random detection per page. - - NB : hardware and software ECC schemes are incompatible. - If you switch from one to another, you'll have to erase your - mtd partition. - - If unsure, say Y - -config MTD_NAND_ATMEL_ECC_SOFT - bool "Software ECC" - help - Use software ECC. - - NB : hardware and software ECC schemes are incompatible. - If you switch from one to another, you'll have to erase your - mtd partition. - -config MTD_NAND_ATMEL_ECC_NONE - bool "No ECC (testing only, DANGEROUS)" - depends on DEBUG_KERNEL - help - No ECC will be used. - It's not a good idea and it should be reserved for testing - purpose only. - - If unsure, say N - -endchoice config MTD_NAND_PXA3xx tristate "Support for NAND flash devices on PXA3xx" diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 54e3588bef62..34e94c7f68ca 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -145,6 +145,15 @@ config PINCTRL_COH901 COH 901 335 and COH 901 571/3. They contain 3, 5 or 7 ports of 8 GPIO pins each. +config PINCTRL_SAMSUNG + bool "Samsung pinctrl driver" + select PINMUX + select PINCONF + +config PINCTRL_EXYNOS4 + bool "Pinctrl driver data for Exynos4 SoC" + select PINCTRL_SAMSUNG + source "drivers/pinctrl/spear/Kconfig" endmenu diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index f40b1f81ff2c..6a88113e11d9 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -29,5 +29,7 @@ obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o +obj-$(CONFIG_PINCTRL_SAMSUNG) += pinctrl-samsung.o +obj-$(CONFIG_PINCTRL_EXYNOS4) += pinctrl-exynos.o obj-$(CONFIG_PLAT_SPEAR) += spear/ diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c new file mode 100644 index 000000000000..21362f48d370 --- /dev/null +++ b/drivers/pinctrl/pinctrl-exynos.c @@ -0,0 +1,579 @@ +/* + * Exynos specific support for Samsung pinctrl/gpiolib driver with eint support. + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * Copyright (c) 2012 Linaro Ltd + * http://www.linaro.org + * + * Author: Thomas Abraham <thomas.ab@samsung.com> + * + * 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 file contains the Samsung Exynos specific information required by the + * the Samsung pinctrl/gpiolib driver. It also includes the implementation of + * external gpio and wakeup interrupt support. + */ + +#include <linux/module.h> +#include <linux/device.h> +#include <linux/interrupt.h> +#include <linux/irqdomain.h> +#include <linux/irq.h> +#include <linux/of_irq.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/err.h> + +#include <asm/mach/irq.h> + +#include "pinctrl-samsung.h" +#include "pinctrl-exynos.h" + +/* list of external wakeup controllers supported */ +static const struct of_device_id exynos_wkup_irq_ids[] = { + { .compatible = "samsung,exynos4210-wakeup-eint", }, +}; + +static void exynos_gpio_irq_unmask(struct irq_data *irqd) +{ + struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; + struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); + unsigned long reg_mask = d->ctrl->geint_mask + edata->eint_offset; + unsigned long mask; + + mask = readl(d->virt_base + reg_mask); + mask &= ~(1 << edata->pin); + writel(mask, d->virt_base + reg_mask); +} + +static void exynos_gpio_irq_mask(struct irq_data *irqd) +{ + struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; + struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); + unsigned long reg_mask = d->ctrl->geint_mask + edata->eint_offset; + unsigned long mask; + + mask = readl(d->virt_base + reg_mask); + mask |= 1 << edata->pin; + writel(mask, d->virt_base + reg_mask); +} + +static void exynos_gpio_irq_ack(struct irq_data *irqd) +{ + struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; + struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); + unsigned long reg_pend = d->ctrl->geint_pend + edata->eint_offset; + + writel(1 << edata->pin, d->virt_base + reg_pend); +} + +static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) +{ + struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; + struct samsung_pin_ctrl *ctrl = d->ctrl; + struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); + struct samsung_pin_bank *bank = edata->bank; + unsigned int shift = EXYNOS_EINT_CON_LEN * edata->pin; + unsigned int con, trig_type; + unsigned long reg_con = ctrl->geint_con + edata->eint_offset; + unsigned int mask; + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + trig_type = EXYNOS_EINT_EDGE_RISING; + break; + case IRQ_TYPE_EDGE_FALLING: + trig_type = EXYNOS_EINT_EDGE_FALLING; + break; + case IRQ_TYPE_EDGE_BOTH: + trig_type = EXYNOS_EINT_EDGE_BOTH; + break; + case IRQ_TYPE_LEVEL_HIGH: + trig_type = EXYNOS_EINT_LEVEL_HIGH; + break; + case IRQ_TYPE_LEVEL_LOW: + trig_type = EXYNOS_EINT_LEVEL_LOW; + break; + default: + pr_err("unsupported external interrupt type\n"); + return -EINVAL; + } + + if (type & IRQ_TYPE_EDGE_BOTH) + __irq_set_handler_locked(irqd->irq, handle_edge_irq); + else + __irq_set_handler_locked(irqd->irq, handle_level_irq); + + con = readl(d->virt_base + reg_con); + con &= ~(EXYNOS_EINT_CON_MASK << shift); + con |= trig_type << shift; + writel(con, d->virt_base + reg_con); + + reg_con = bank->pctl_offset; + shift = edata->pin * bank->func_width; + mask = (1 << bank->func_width) - 1; + + con = readl(d->virt_base + reg_con); + con &= ~(mask << shift); + con |= EXYNOS_EINT_FUNC << shift; + writel(con, d->virt_base + reg_con); + + return 0; +} + +/* + * irq_chip for gpio interrupts. + */ +static struct irq_chip exynos_gpio_irq_chip = { + .name = "exynos_gpio_irq_chip", + .irq_unmask = exynos_gpio_irq_unmask, + .irq_mask = exynos_gpio_irq_mask, + .irq_ack = exynos_gpio_irq_ack, + .irq_set_type = exynos_gpio_irq_set_type, +}; + +/* + * given a controller-local external gpio interrupt number, prepare the handler + * data for it. + */ +static struct exynos_geint_data *exynos_get_eint_data(irq_hw_number_t hw, + struct samsung_pinctrl_drv_data *d) +{ + struct samsung_pin_bank *bank = d->ctrl->pin_banks; + struct exynos_geint_data *eint_data; + unsigned int nr_banks = d->ctrl->nr_banks, idx; + unsigned int irq_base = 0, eint_offset = 0; + + if (hw >= d->ctrl->nr_gint) { + dev_err(d->dev, "unsupported ext-gpio interrupt\n"); + return NULL; + } + + for (idx = 0; idx < nr_banks; idx++, bank++) { + if (bank->eint_type != EINT_TYPE_GPIO) + continue; + if ((hw >= irq_base) && (hw < (irq_base + bank->nr_pins))) + break; + irq_base += bank->nr_pins; + eint_offset += 4; + } + + if (idx == nr_banks) { + dev_err(d->dev, "pin bank not found for ext-gpio interrupt\n"); + return NULL; + } + + eint_data = devm_kzalloc(d->dev, sizeof(*eint_data), GFP_KERNEL); + if (!eint_data) { + dev_err(d->dev, "no memory for eint-gpio data\n"); + return NULL; + } + + eint_data->bank = bank; + eint_data->pin = hw - irq_base; + eint_data->eint_offset = eint_offset; + return eint_data; +} + +static int exynos_gpio_irq_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) +{ + struct samsung_pinctrl_drv_data *d = h->host_data; + struct exynos_geint_data *eint_data; + + eint_data = exynos_get_eint_data(hw, d); + if (!eint_data) + return -EINVAL; + + irq_set_handler_data(virq, eint_data); + irq_set_chip_data(virq, h->host_data); + irq_set_chip_and_handler(virq, &exynos_gpio_irq_chip, + handle_level_irq); + set_irq_flags(virq, IRQF_VALID); + return 0; +} + +static void exynos_gpio_irq_unmap(struct irq_domain *h, unsigned int virq) +{ + struct samsung_pinctrl_drv_data *d = h->host_data; + struct exynos_geint_data *eint_data; + + eint_data = irq_get_handler_data(virq); + devm_kfree(d->dev, eint_data); +} + +/* + * irq domain callbacks for external gpio interrupt controller. + */ +static const struct irq_domain_ops exynos_gpio_irqd_ops = { + .map = exynos_gpio_irq_map, + .unmap = exynos_gpio_irq_unmap, + .xlate = irq_domain_xlate_twocell, +}; + +static irqreturn_t exynos_eint_gpio_irq(int irq, void *data) +{ + struct samsung_pinctrl_drv_data *d = data; + struct samsung_pin_ctrl *ctrl = d->ctrl; + struct samsung_pin_bank *bank = ctrl->pin_banks; + unsigned int svc, group, pin, virq; + + svc = readl(d->virt_base + ctrl->svc); + group = EXYNOS_SVC_GROUP(svc); + pin = svc & EXYNOS_SVC_NUM_MASK; + + if (!group) + return IRQ_HANDLED; + bank += (group - 1); + + virq = irq_linear_revmap(d->gpio_irqd, bank->irq_base + pin); + if (!virq) + return IRQ_NONE; + generic_handle_irq(virq); + return IRQ_HANDLED; +} + +/* + * exynos_eint_gpio_init() - setup handling of external gpio interrupts. + * @d: driver data of samsung pinctrl driver. + */ +static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d) +{ + struct device *dev = d->dev; + unsigned int ret; + + if (!d->irq) { + dev_err(dev, "irq number not available\n"); + return -EINVAL; + } + + ret = devm_request_irq(dev, d->irq, exynos_eint_gpio_irq, + 0, dev_name(dev), d); + if (ret) { + dev_err(dev, "irq request failed\n"); + return -ENXIO; + } + + d->gpio_irqd = irq_domain_add_linear(dev->of_node, d->ctrl->nr_gint, + &exynos_gpio_irqd_ops, d); + if (!d->gpio_irqd) { + dev_err(dev, "gpio irq domain allocation failed\n"); + return -ENXIO; + } + + return 0; +} + +static void exynos_wkup_irq_unmask(struct irq_data *irqd) +{ + struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); + unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK; + unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1); + unsigned long reg_mask = d->ctrl->weint_mask + (bank << 2); + unsigned long mask; + + mask = readl(d->virt_base + reg_mask); + mask &= ~(1 << pin); + writel(mask, d->virt_base + reg_mask); +} + +static void exynos_wkup_irq_mask(struct irq_data *irqd) +{ + struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); + unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK; + unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1); + unsigned long reg_mask = d->ctrl->weint_mask + (bank << 2); + unsigned long mask; + + mask = readl(d->virt_base + reg_mask); + mask |= 1 << pin; + writel(mask, d->virt_base + reg_mask); +} + +static void exynos_wkup_irq_ack(struct irq_data *irqd) +{ + struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); + unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK; + unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1); + unsigned long pend = d->ctrl->weint_pend + (bank << 2); + + writel(1 << pin, d->virt_base + pend); +} + +static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type) +{ + struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); + unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK; + unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1); + unsigned long reg_con = d->ctrl->weint_con + (bank << 2); + unsigned long shift = EXYNOS_EINT_CON_LEN * pin; + unsigned long con, trig_type; + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + trig_type = EXYNOS_EINT_EDGE_RISING; + break; + case IRQ_TYPE_EDGE_FALLING: + trig_type = EXYNOS_EINT_EDGE_FALLING; + break; + case IRQ_TYPE_EDGE_BOTH: + trig_type = EXYNOS_EINT_EDGE_BOTH; + break; + case IRQ_TYPE_LEVEL_HIGH: + trig_type = EXYNOS_EINT_LEVEL_HIGH; + break; + case IRQ_TYPE_LEVEL_LOW: + trig_type = EXYNOS_EINT_LEVEL_LOW; + break; + default: + pr_err("unsupported external interrupt type\n"); + return -EINVAL; + } + + if (type & IRQ_TYPE_EDGE_BOTH) + __irq_set_handler_locked(irqd->irq, handle_edge_irq); + else + __irq_set_handler_locked(irqd->irq, handle_level_irq); + + con = readl(d->virt_base + reg_con); + con &= ~(EXYNOS_EINT_CON_MASK << shift); + con |= trig_type << shift; + writel(con, d->virt_base + reg_con); + return 0; +} + +/* + * irq_chip for wakeup interrupts + */ +static struct irq_chip exynos_wkup_irq_chip = { + .name = "exynos_wkup_irq_chip", + .irq_unmask = exynos_wkup_irq_unmask, + .irq_mask = exynos_wkup_irq_mask, + .irq_ack = exynos_wkup_irq_ack, + .irq_set_type = exynos_wkup_irq_set_type, +}; + +/* interrupt handler for wakeup interrupts 0..15 */ +static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc) +{ + struct exynos_weint_data *eintd = irq_get_handler_data(irq); + struct irq_chip *chip = irq_get_chip(irq); + int eint_irq; + + chained_irq_enter(chip, desc); + chip->irq_mask(&desc->irq_data); + + if (chip->irq_ack) + chip->irq_ack(&desc->irq_data); + + eint_irq = irq_linear_revmap(eintd->domain, eintd->irq); + generic_handle_irq(eint_irq); + chip->irq_unmask(&desc->irq_data); + chained_irq_exit(chip, desc); +} + +static inline void exynos_irq_demux_eint(int irq_base, unsigned long pend, + struct irq_domain *domain) +{ + unsigned int irq; + + while (pend) { + irq = fls(pend) - 1; + generic_handle_irq(irq_find_mapping(domain, irq_base + irq)); + pend &= ~(1 << irq); + } +} + +/* interrupt handler for wakeup interrupt 16 */ +static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc) +{ + struct irq_chip *chip = irq_get_chip(irq); + struct exynos_weint_data *eintd = irq_get_handler_data(irq); + struct samsung_pinctrl_drv_data *d = eintd->domain->host_data; + unsigned long pend; + unsigned long mask; + + chained_irq_enter(chip, desc); + pend = readl(d->virt_base + d->ctrl->weint_pend + 0x8); + mask = readl(d->virt_base + d->ctrl->weint_mask + 0x8); + exynos_irq_demux_eint(16, pend & ~mask, eintd->domain); + pend = readl(d->virt_base + d->ctrl->weint_pend + 0xC); + mask = readl(d->virt_base + d->ctrl->weint_mask + 0xC); + exynos_irq_demux_eint(24, pend & ~mask, eintd->domain); + chained_irq_exit(chip, desc); +} + +static int exynos_wkup_irq_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) +{ + irq_set_chip_and_handler(virq, &exynos_wkup_irq_chip, handle_level_irq); + irq_set_chip_data(virq, h->host_data); + set_irq_flags(virq, IRQF_VALID); + return 0; +} + +/* + * irq domain callbacks for external wakeup interrupt controller. + */ +static const struct irq_domain_ops exynos_wkup_irqd_ops = { + .map = exynos_wkup_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + +/* + * exynos_eint_wkup_init() - setup handling of external wakeup interrupts. + * @d: driver data of samsung pinctrl driver. + */ +static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) +{ + struct device *dev = d->dev; + struct device_node *wkup_np = NULL; + struct device_node *np; + struct exynos_weint_data *weint_data; + int idx, irq; + + for_each_child_of_node(dev->of_node, np) { + if (of_match_node(exynos_wkup_irq_ids, np)) { + wkup_np = np; + break; + } + } + if (!wkup_np) + return -ENODEV; + + d->wkup_irqd = irq_domain_add_linear(wkup_np, d->ctrl->nr_wint, + &exynos_wkup_irqd_ops, d); + if (!d->wkup_irqd) { + dev_err(dev, "wakeup irq domain allocation failed\n"); + return -ENXIO; + } + + weint_data = devm_kzalloc(dev, sizeof(*weint_data) * 17, GFP_KERNEL); + if (!weint_data) { + dev_err(dev, "could not allocate memory for weint_data\n"); + return -ENOMEM; + } + + irq = irq_of_parse_and_map(wkup_np, 16); + if (irq) { + weint_data[16].domain = d->wkup_irqd; + irq_set_chained_handler(irq, exynos_irq_demux_eint16_31); + irq_set_handler_data(irq, &weint_data[16]); + } else { + dev_err(dev, "irq number for EINT16-32 not found\n"); + } + + for (idx = 0; idx < 16; idx++) { + weint_data[idx].domain = d->wkup_irqd; + weint_data[idx].irq = idx; + + irq = irq_of_parse_and_map(wkup_np, idx); + if (irq) { + irq_set_handler_data(irq, &weint_data[idx]); + irq_set_chained_handler(irq, exynos_irq_eint0_15); + } else { + dev_err(dev, "irq number for eint-%x not found\n", idx); + } + } + return 0; +} + +/* pin banks of exynos4210 pin-controller 0 */ +static struct samsung_pin_bank exynos4210_pin_banks0[] = { + EXYNOS_PIN_BANK_EINTG(0x000, EXYNOS4210_GPIO_A0, "gpa0"), + EXYNOS_PIN_BANK_EINTG(0x020, EXYNOS4210_GPIO_A1, "gpa1"), + EXYNOS_PIN_BANK_EINTG(0x040, EXYNOS4210_GPIO_B, "gpb"), + EXYNOS_PIN_BANK_EINTG(0x060, EXYNOS4210_GPIO_C0, "gpc0"), + EXYNOS_PIN_BANK_EINTG(0x080, EXYNOS4210_GPIO_C1, "gpc1"), + EXYNOS_PIN_BANK_EINTG(0x0A0, EXYNOS4210_GPIO_D0, "gpd0"), + EXYNOS_PIN_BANK_EINTG(0x0C0, EXYNOS4210_GPIO_D1, "gpd1"), + EXYNOS_PIN_BANK_EINTG(0x0E0, EXYNOS4210_GPIO_E0, "gpe0"), + EXYNOS_PIN_BANK_EINTG(0x100, EXYNOS4210_GPIO_E1, "gpe1"), + EXYNOS_PIN_BANK_EINTG(0x120, EXYNOS4210_GPIO_E2, "gpe2"), + EXYNOS_PIN_BANK_EINTG(0x140, EXYNOS4210_GPIO_E3, "gpe3"), + EXYNOS_PIN_BANK_EINTG(0x160, EXYNOS4210_GPIO_E4, "gpe4"), + EXYNOS_PIN_BANK_EINTG(0x180, EXYNOS4210_GPIO_F0, "gpf0"), + EXYNOS_PIN_BANK_EINTG(0x1A0, EXYNOS4210_GPIO_F1, "gpf1"), + EXYNOS_PIN_BANK_EINTG(0x1C0, EXYNOS4210_GPIO_F2, "gpf2"), + EXYNOS_PIN_BANK_EINTG(0x1E0, EXYNOS4210_GPIO_F3, "gpf3"), +}; + +/* pin banks of exynos4210 pin-controller 1 */ +static struct samsung_pin_bank exynos4210_pin_banks1[] = { + EXYNOS_PIN_BANK_EINTG(0x000, EXYNOS4210_GPIO_J0, "gpj0"), + EXYNOS_PIN_BANK_EINTG(0x020, EXYNOS4210_GPIO_J1, "gpj1"), + EXYNOS_PIN_BANK_EINTG(0x040, EXYNOS4210_GPIO_K0, "gpk0"), + EXYNOS_PIN_BANK_EINTG(0x060, EXYNOS4210_GPIO_K1, "gpk1"), + EXYNOS_PIN_BANK_EINTG(0x080, EXYNOS4210_GPIO_K2, "gpk2"), + EXYNOS_PIN_BANK_EINTG(0x0A0, EXYNOS4210_GPIO_K3, "gpk3"), + EXYNOS_PIN_BANK_EINTG(0x0C0, EXYNOS4210_GPIO_L0, "gpl0"), + EXYNOS_PIN_BANK_EINTG(0x0E0, EXYNOS4210_GPIO_L1, "gpl1"), + EXYNOS_PIN_BANK_EINTG(0x100, EXYNOS4210_GPIO_L2, "gpl2"), + EXYNOS_PIN_BANK_EINTN(0x120, EXYNOS4210_GPIO_Y0, "gpy0"), + EXYNOS_PIN_BANK_EINTN(0x140, EXYNOS4210_GPIO_Y1, "gpy1"), + EXYNOS_PIN_BANK_EINTN(0x160, EXYNOS4210_GPIO_Y2, "gpy2"), + EXYNOS_PIN_BANK_EINTN(0x180, EXYNOS4210_GPIO_Y3, "gpy3"), + EXYNOS_PIN_BANK_EINTN(0x1A0, EXYNOS4210_GPIO_Y4, "gpy4"), + EXYNOS_PIN_BANK_EINTN(0x1C0, EXYNOS4210_GPIO_Y5, "gpy5"), + EXYNOS_PIN_BANK_EINTN(0x1E0, EXYNOS4210_GPIO_Y6, "gpy6"), + EXYNOS_PIN_BANK_EINTN(0xC00, EXYNOS4210_GPIO_X0, "gpx0"), + EXYNOS_PIN_BANK_EINTN(0xC20, EXYNOS4210_GPIO_X1, "gpx1"), + EXYNOS_PIN_BANK_EINTN(0xC40, EXYNOS4210_GPIO_X2, "gpx2"), + EXYNOS_PIN_BANK_EINTN(0xC60, EXYNOS4210_GPIO_X3, "gpx3"), +}; + +/* pin banks of exynos4210 pin-controller 2 */ +static struct samsung_pin_bank exynos4210_pin_banks2[] = { + EXYNOS_PIN_BANK_EINTN(0x000, EXYNOS4210_GPIO_Z, "gpz"), +}; + +/* + * Samsung pinctrl driver data for Exynos4210 SoC. Exynos4210 SoC includes + * three gpio/pin-mux/pinconfig controllers. + */ +struct samsung_pin_ctrl exynos4210_pin_ctrl[] = { + { + /* pin-controller instance 0 data */ + .pin_banks = exynos4210_pin_banks0, + .nr_banks = ARRAY_SIZE(exynos4210_pin_banks0), + .base = EXYNOS4210_GPIO_A0_START, + .nr_pins = EXYNOS4210_GPIOA_NR_PINS, + .nr_gint = EXYNOS4210_GPIOA_NR_GINT, + .geint_con = EXYNOS_GPIO_ECON_OFFSET, + .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, + .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, + .svc = EXYNOS_SVC_OFFSET, + .eint_gpio_init = exynos_eint_gpio_init, + .label = "exynos4210-gpio-ctrl0", + }, { + /* pin-controller instance 1 data */ + .pin_banks = exynos4210_pin_banks1, + .nr_banks = ARRAY_SIZE(exynos4210_pin_banks1), + .base = EXYNOS4210_GPIOA_NR_PINS, + .nr_pins = EXYNOS4210_GPIOB_NR_PINS, + .nr_gint = EXYNOS4210_GPIOB_NR_GINT, + .nr_wint = 32, + .geint_con = EXYNOS_GPIO_ECON_OFFSET, + .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, + .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, + .weint_con = EXYNOS_WKUP_ECON_OFFSET, + .weint_mask = EXYNOS_WKUP_EMASK_OFFSET, + .weint_pend = EXYNOS_WKUP_EPEND_OFFSET, + .svc = EXYNOS_SVC_OFFSET, + .eint_gpio_init = exynos_eint_gpio_init, + .eint_wkup_init = exynos_eint_wkup_init, + .label = "exynos4210-gpio-ctrl1", + }, { + /* pin-controller instance 2 data */ + .pin_banks = exynos4210_pin_banks2, + .nr_banks = ARRAY_SIZE(exynos4210_pin_banks2), + .base = EXYNOS4210_GPIOA_NR_PINS + + EXYNOS4210_GPIOB_NR_PINS, + .nr_pins = EXYNOS4210_GPIOC_NR_PINS, + .label = "exynos4210-gpio-ctrl2", + }, +}; diff --git a/drivers/pinctrl/pinctrl-exynos.h b/drivers/pinctrl/pinctrl-exynos.h new file mode 100644 index 000000000000..31d0a06174e4 --- /dev/null +++ b/drivers/pinctrl/pinctrl-exynos.h @@ -0,0 +1,218 @@ +/* + * Exynos specific definitions for Samsung pinctrl and gpiolib driver. + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * Copyright (c) 2012 Linaro Ltd + * http://www.linaro.org + * + * This file contains the Exynos specific definitions for the Samsung + * pinctrl/gpiolib interface drivers. + * + * Author: Thomas Abraham <thomas.ab@samsung.com> + * + * 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. + */ + +#define EXYNOS_GPIO_START(__gpio) ((__gpio##_START) + (__gpio##_NR)) + +#define EXYNOS4210_GPIO_A0_NR (8) +#define EXYNOS4210_GPIO_A1_NR (6) +#define EXYNOS4210_GPIO_B_NR (8) +#define EXYNOS4210_GPIO_C0_NR (5) +#define EXYNOS4210_GPIO_C1_NR (5) +#define EXYNOS4210_GPIO_D0_NR (4) +#define EXYNOS4210_GPIO_D1_NR (4) +#define EXYNOS4210_GPIO_E0_NR (5) +#define EXYNOS4210_GPIO_E1_NR (8) +#define EXYNOS4210_GPIO_E2_NR (6) +#define EXYNOS4210_GPIO_E3_NR (8) +#define EXYNOS4210_GPIO_E4_NR (8) +#define EXYNOS4210_GPIO_F0_NR (8) +#define EXYNOS4210_GPIO_F1_NR (8) +#define EXYNOS4210_GPIO_F2_NR (8) +#define EXYNOS4210_GPIO_F3_NR (6) +#define EXYNOS4210_GPIO_J0_NR (8) +#define EXYNOS4210_GPIO_J1_NR (5) +#define EXYNOS4210_GPIO_K0_NR (7) +#define EXYNOS4210_GPIO_K1_NR (7) +#define EXYNOS4210_GPIO_K2_NR (7) +#define EXYNOS4210_GPIO_K3_NR (7) +#define EXYNOS4210_GPIO_L0_NR (8) +#define EXYNOS4210_GPIO_L1_NR (3) +#define EXYNOS4210_GPIO_L2_NR (8) +#define EXYNOS4210_GPIO_Y0_NR (6) +#define EXYNOS4210_GPIO_Y1_NR (4) +#define EXYNOS4210_GPIO_Y2_NR (6) +#define EXYNOS4210_GPIO_Y3_NR (8) +#define EXYNOS4210_GPIO_Y4_NR (8) +#define EXYNOS4210_GPIO_Y5_NR (8) +#define EXYNOS4210_GPIO_Y6_NR (8) +#define EXYNOS4210_GPIO_X0_NR (8) +#define EXYNOS4210_GPIO_X1_NR (8) +#define EXYNOS4210_GPIO_X2_NR (8) +#define EXYNOS4210_GPIO_X3_NR (8) +#define EXYNOS4210_GPIO_Z_NR (7) + +enum exynos4210_gpio_xa_start { + EXYNOS4210_GPIO_A0_START = 0, + EXYNOS4210_GPIO_A1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_A0), + EXYNOS4210_GPIO_B_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_A1), + EXYNOS4210_GPIO_C0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_B), + EXYNOS4210_GPIO_C1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_C0), + EXYNOS4210_GPIO_D0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_C1), + EXYNOS4210_GPIO_D1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_D0), + EXYNOS4210_GPIO_E0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_D1), + EXYNOS4210_GPIO_E1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E0), + EXYNOS4210_GPIO_E2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E1), + EXYNOS4210_GPIO_E3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E2), + EXYNOS4210_GPIO_E4_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E3), + EXYNOS4210_GPIO_F0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E4), + EXYNOS4210_GPIO_F1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_F0), + EXYNOS4210_GPIO_F2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_F1), + EXYNOS4210_GPIO_F3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_F2), +}; + +enum exynos4210_gpio_xb_start { + EXYNOS4210_GPIO_J0_START = 0, + EXYNOS4210_GPIO_J1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_J0), + EXYNOS4210_GPIO_K0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_J1), + EXYNOS4210_GPIO_K1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K0), + EXYNOS4210_GPIO_K2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K1), + EXYNOS4210_GPIO_K3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K2), + EXYNOS4210_GPIO_L0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K3), + EXYNOS4210_GPIO_L1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_L0), + EXYNOS4210_GPIO_L2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_L1), + EXYNOS4210_GPIO_Y0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_L2), + EXYNOS4210_GPIO_Y1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y0), + EXYNOS4210_GPIO_Y2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y1), + EXYNOS4210_GPIO_Y3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y2), + EXYNOS4210_GPIO_Y4_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y3), + EXYNOS4210_GPIO_Y5_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y4), + EXYNOS4210_GPIO_Y6_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y5), + EXYNOS4210_GPIO_X0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y6), + EXYNOS4210_GPIO_X1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_X0), + EXYNOS4210_GPIO_X2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_X1), + EXYNOS4210_GPIO_X3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_X2), +}; + +enum exynos4210_gpio_xc_start { + EXYNOS4210_GPIO_Z_START = 0, +}; + +#define EXYNOS4210_GPIO_A0_IRQ EXYNOS4210_GPIO_A0_START +#define EXYNOS4210_GPIO_A1_IRQ EXYNOS4210_GPIO_A1_START +#define EXYNOS4210_GPIO_B_IRQ EXYNOS4210_GPIO_B_START +#define EXYNOS4210_GPIO_C0_IRQ EXYNOS4210_GPIO_C0_START +#define EXYNOS4210_GPIO_C1_IRQ EXYNOS4210_GPIO_C1_START +#define EXYNOS4210_GPIO_D0_IRQ EXYNOS4210_GPIO_D0_START +#define EXYNOS4210_GPIO_D1_IRQ EXYNOS4210_GPIO_D1_START +#define EXYNOS4210_GPIO_E0_IRQ EXYNOS4210_GPIO_E0_START +#define EXYNOS4210_GPIO_E1_IRQ EXYNOS4210_GPIO_E1_START +#define EXYNOS4210_GPIO_E2_IRQ EXYNOS4210_GPIO_E2_START +#define EXYNOS4210_GPIO_E3_IRQ EXYNOS4210_GPIO_E3_START +#define EXYNOS4210_GPIO_E4_IRQ EXYNOS4210_GPIO_E4_START +#define EXYNOS4210_GPIO_F0_IRQ EXYNOS4210_GPIO_F0_START +#define EXYNOS4210_GPIO_F1_IRQ EXYNOS4210_GPIO_F1_START +#define EXYNOS4210_GPIO_F2_IRQ EXYNOS4210_GPIO_F2_START +#define EXYNOS4210_GPIO_F3_IRQ EXYNOS4210_GPIO_F3_START +#define EXYNOS4210_GPIO_J0_IRQ EXYNOS4210_GPIO_J0_START +#define EXYNOS4210_GPIO_J1_IRQ EXYNOS4210_GPIO_J1_START +#define EXYNOS4210_GPIO_K0_IRQ EXYNOS4210_GPIO_K0_START +#define EXYNOS4210_GPIO_K1_IRQ EXYNOS4210_GPIO_K1_START +#define EXYNOS4210_GPIO_K2_IRQ EXYNOS4210_GPIO_K2_START +#define EXYNOS4210_GPIO_K3_IRQ EXYNOS4210_GPIO_K3_START +#define EXYNOS4210_GPIO_L0_IRQ EXYNOS4210_GPIO_L0_START +#define EXYNOS4210_GPIO_L1_IRQ EXYNOS4210_GPIO_L1_START +#define EXYNOS4210_GPIO_L2_IRQ EXYNOS4210_GPIO_L2_START +#define EXYNOS4210_GPIO_Z_IRQ EXYNOS4210_GPIO_Z_START + +#define EXYNOS4210_GPIOA_NR_PINS EXYNOS_GPIO_START(EXYNOS4210_GPIO_F3) +#define EXYNOS4210_GPIOA_NR_GINT EXYNOS_GPIO_START(EXYNOS4210_GPIO_F3) +#define EXYNOS4210_GPIOB_NR_PINS EXYNOS_GPIO_START(EXYNOS4210_GPIO_X3) +#define EXYNOS4210_GPIOB_NR_GINT EXYNOS_GPIO_START(EXYNOS4210_GPIO_L2) +#define EXYNOS4210_GPIOC_NR_PINS EXYNOS_GPIO_START(EXYNOS4210_GPIO_Z) + +/* External GPIO and wakeup interrupt related definitions */ +#define EXYNOS_GPIO_ECON_OFFSET 0x700 +#define EXYNOS_GPIO_EMASK_OFFSET 0x900 +#define EXYNOS_GPIO_EPEND_OFFSET 0xA00 +#define EXYNOS_WKUP_ECON_OFFSET 0xE00 +#define EXYNOS_WKUP_EMASK_OFFSET 0xF00 +#define EXYNOS_WKUP_EPEND_OFFSET 0xF40 +#define EXYNOS_SVC_OFFSET 0xB08 +#define EXYNOS_EINT_FUNC 0xF + +/* helpers to access interrupt service register */ +#define EXYNOS_SVC_GROUP_SHIFT 3 +#define EXYNOS_SVC_GROUP_MASK 0x1f +#define EXYNOS_SVC_NUM_MASK 7 +#define EXYNOS_SVC_GROUP(x) ((x >> EXYNOS_SVC_GROUP_SHIFT) & \ + EXYNOS_SVC_GROUP_MASK) + +/* Exynos specific external interrupt trigger types */ +#define EXYNOS_EINT_LEVEL_LOW 0 +#define EXYNOS_EINT_LEVEL_HIGH 1 +#define EXYNOS_EINT_EDGE_FALLING 2 +#define EXYNOS_EINT_EDGE_RISING 3 +#define EXYNOS_EINT_EDGE_BOTH 4 +#define EXYNOS_EINT_CON_MASK 0xF +#define EXYNOS_EINT_CON_LEN 4 + +#define EXYNOS_EINT_MAX_PER_BANK 8 +#define EXYNOS_EINT_NR_WKUP_EINT + +#define EXYNOS_PIN_BANK_EINTN(reg, __gpio, id) \ + { \ + .pctl_offset = reg, \ + .pin_base = (__gpio##_START), \ + .nr_pins = (__gpio##_NR), \ + .func_width = 4, \ + .pud_width = 2, \ + .drv_width = 2, \ + .conpdn_width = 2, \ + .pudpdn_width = 2, \ + .eint_type = EINT_TYPE_NONE, \ + .name = id \ + } + +#define EXYNOS_PIN_BANK_EINTG(reg, __gpio, id) \ + { \ + .pctl_offset = reg, \ + .pin_base = (__gpio##_START), \ + .nr_pins = (__gpio##_NR), \ + .func_width = 4, \ + .pud_width = 2, \ + .drv_width = 2, \ + .conpdn_width = 2, \ + .pudpdn_width = 2, \ + .eint_type = EINT_TYPE_GPIO, \ + .irq_base = (__gpio##_IRQ), \ + .name = id \ + } + +/** + * struct exynos_geint_data: gpio eint specific data for irq_chip callbacks. + * @bank: pin bank from which this gpio interrupt originates. + * @pin: pin number within the bank. + * @eint_offset: offset to be added to the con/pend/mask register bank base. + */ +struct exynos_geint_data { + struct samsung_pin_bank *bank; + u32 pin; + u32 eint_offset; +}; + +/** + * struct exynos_weint_data: irq specific data for all the wakeup interrupts + * generated by the external wakeup interrupt controller. + * @domain: irq domain representing the external wakeup interrupts + * @irq: interrupt number within the domain. + */ +struct exynos_weint_data { + struct irq_domain *domain; + u32 irq; +}; diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c new file mode 100644 index 000000000000..dd108a94acf9 --- /dev/null +++ b/drivers/pinctrl/pinctrl-samsung.c @@ -0,0 +1,888 @@ +/* + * pin-controller/pin-mux/pin-config/gpio-driver for Samsung's SoC's. + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * Copyright (c) 2012 Linaro Ltd + * http://www.linaro.org + * + * Author: Thomas Abraham <thomas.ab@samsung.com> + * + * 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 driver implements the Samsung pinctrl driver. It supports setting up of + * pinmux and pinconf configurations. The gpiolib interface is also included. + * External interrupt (gpio and wakeup) support are not included in this driver + * but provides extensions to which platform specific implementation of the gpio + * and wakeup interrupts can be hooked to. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/gpio.h> + +#include "core.h" +#include "pinctrl-samsung.h" + +#define GROUP_SUFFIX "-grp" +#define GSUFFIX_LEN sizeof(GROUP_SUFFIX) +#define FUNCTION_SUFFIX "-mux" +#define FSUFFIX_LEN sizeof(FUNCTION_SUFFIX) + +/* list of all possible config options supported */ +struct pin_config { + char *prop_cfg; + unsigned int cfg_type; +} pcfgs[] = { + { "samsung,pin-pud", PINCFG_TYPE_PUD }, + { "samsung,pin-drv", PINCFG_TYPE_DRV }, + { "samsung,pin-con-pdn", PINCFG_TYPE_CON_PDN }, + { "samsung,pin-pud-pdn", PINCFG_TYPE_PUD_PDN }, +}; + +/* check if the selector is a valid pin group selector */ +static int samsung_get_group_count(struct pinctrl_dev *pctldev) +{ + struct samsung_pinctrl_drv_data *drvdata; + + drvdata = pinctrl_dev_get_drvdata(pctldev); + return drvdata->nr_groups; +} + +/* return the name of the group selected by the group selector */ +static const char *samsung_get_group_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct samsung_pinctrl_drv_data *drvdata; + + drvdata = pinctrl_dev_get_drvdata(pctldev); + return drvdata->pin_groups[selector].name; +} + +/* return the pin numbers associated with the specified group */ +static int samsung_get_group_pins(struct pinctrl_dev *pctldev, + unsigned selector, const unsigned **pins, unsigned *num_pins) +{ + struct samsung_pinctrl_drv_data *drvdata; + + drvdata = pinctrl_dev_get_drvdata(pctldev); + *pins = drvdata->pin_groups[selector].pins; + *num_pins = drvdata->pin_groups[selector].num_pins; + return 0; +} + +/* create pinctrl_map entries by parsing device tree nodes */ +static int samsung_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, struct pinctrl_map **maps, + unsigned *nmaps) +{ + struct device *dev = pctldev->dev; + struct pinctrl_map *map; + unsigned long *cfg = NULL; + char *gname, *fname; + int cfg_cnt = 0, map_cnt = 0, idx = 0; + + /* count the number of config options specfied in the node */ + for (idx = 0; idx < ARRAY_SIZE(pcfgs); idx++) { + if (of_find_property(np, pcfgs[idx].prop_cfg, NULL)) + cfg_cnt++; + } + + /* + * Find out the number of map entries to create. All the config options + * can be accomadated into a single config map entry. + */ + if (cfg_cnt) + map_cnt = 1; + if (of_find_property(np, "samsung,pin-function", NULL)) + map_cnt++; + if (!map_cnt) { + dev_err(dev, "node %s does not have either config or function " + "configurations\n", np->name); + return -EINVAL; + } + + /* Allocate memory for pin-map entries */ + map = kzalloc(sizeof(*map) * map_cnt, GFP_KERNEL); + if (!map) { + dev_err(dev, "could not alloc memory for pin-maps\n"); + return -ENOMEM; + } + *nmaps = 0; + + /* + * Allocate memory for pin group name. The pin group name is derived + * from the node name from which these map entries are be created. + */ + gname = kzalloc(strlen(np->name) + GSUFFIX_LEN, GFP_KERNEL); + if (!gname) { + dev_err(dev, "failed to alloc memory for group name\n"); + goto free_map; + } + sprintf(gname, "%s%s", np->name, GROUP_SUFFIX); + + /* + * don't have config options? then skip over to creating function + * map entries. + */ + if (!cfg_cnt) + goto skip_cfgs; + + /* Allocate memory for config entries */ + cfg = kzalloc(sizeof(*cfg) * cfg_cnt, GFP_KERNEL); + if (!cfg) { + dev_err(dev, "failed to alloc memory for configs\n"); + goto free_gname; + } + + /* Prepare a list of config settings */ + for (idx = 0, cfg_cnt = 0; idx < ARRAY_SIZE(pcfgs); idx++) { + u32 value; + if (!of_property_read_u32(np, pcfgs[idx].prop_cfg, &value)) + cfg[cfg_cnt++] = + PINCFG_PACK(pcfgs[idx].cfg_type, value); + } + + /* create the config map entry */ + map[*nmaps].data.configs.group_or_pin = gname; + map[*nmaps].data.configs.configs = cfg; + map[*nmaps].data.configs.num_configs = cfg_cnt; + map[*nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP; + *nmaps += 1; + +skip_cfgs: + /* create the function map entry */ + if (of_find_property(np, "samsung,pin-function", NULL)) { + fname = kzalloc(strlen(np->name) + FSUFFIX_LEN, GFP_KERNEL); + if (!fname) { + dev_err(dev, "failed to alloc memory for func name\n"); + goto free_cfg; + } + sprintf(fname, "%s%s", np->name, FUNCTION_SUFFIX); + + map[*nmaps].data.mux.group = gname; + map[*nmaps].data.mux.function = fname; + map[*nmaps].type = PIN_MAP_TYPE_MUX_GROUP; + *nmaps += 1; + } + + *maps = map; + return 0; + +free_cfg: + kfree(cfg); +free_gname: + kfree(gname); +free_map: + kfree(map); + return -ENOMEM; +} + +/* free the memory allocated to hold the pin-map table */ +static void samsung_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) +{ + int idx; + + for (idx = 0; idx < num_maps; idx++) { + if (map[idx].type == PIN_MAP_TYPE_MUX_GROUP) { + kfree(map[idx].data.mux.function); + if (!idx) + kfree(map[idx].data.mux.group); + } else if (map->type == PIN_MAP_TYPE_CONFIGS_GROUP) { + kfree(map[idx].data.configs.configs); + if (!idx) + kfree(map[idx].data.configs.group_or_pin); + } + }; + + kfree(map); +} + +/* list of pinctrl callbacks for the pinctrl core */ +static struct pinctrl_ops samsung_pctrl_ops = { + .get_groups_count = samsung_get_group_count, + .get_group_name = samsung_get_group_name, + .get_group_pins = samsung_get_group_pins, + .dt_node_to_map = samsung_dt_node_to_map, + .dt_free_map = samsung_dt_free_map, +}; + +/* check if the selector is a valid pin function selector */ +static int samsung_get_functions_count(struct pinctrl_dev *pctldev) +{ + struct samsung_pinctrl_drv_data *drvdata; + + drvdata = pinctrl_dev_get_drvdata(pctldev); + return drvdata->nr_functions; +} + +/* return the name of the pin function specified */ +static const char *samsung_pinmux_get_fname(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct samsung_pinctrl_drv_data *drvdata; + + drvdata = pinctrl_dev_get_drvdata(pctldev); + return drvdata->pmx_functions[selector].name; +} + +/* return the groups associated for the specified function selector */ +static int samsung_pinmux_get_groups(struct pinctrl_dev *pctldev, + unsigned selector, const char * const **groups, + unsigned * const num_groups) +{ + struct samsung_pinctrl_drv_data *drvdata; + + drvdata = pinctrl_dev_get_drvdata(pctldev); + *groups = drvdata->pmx_functions[selector].groups; + *num_groups = drvdata->pmx_functions[selector].num_groups; + return 0; +} + +/* + * given a pin number that is local to a pin controller, find out the pin bank + * and the register base of the pin bank. + */ +static void pin_to_reg_bank(struct gpio_chip *gc, unsigned pin, + void __iomem **reg, u32 *offset, + struct samsung_pin_bank **bank) +{ + struct samsung_pinctrl_drv_data *drvdata; + struct samsung_pin_bank *b; + + drvdata = dev_get_drvdata(gc->dev); + b = drvdata->ctrl->pin_banks; + + while ((pin >= b->pin_base) && + ((b->pin_base + b->nr_pins - 1) < pin)) + b++; + + *reg = drvdata->virt_base + b->pctl_offset; + *offset = pin - b->pin_base; + if (bank) + *bank = b; + + /* some banks have two config registers in a single bank */ + if (*offset * b->func_width > BITS_PER_LONG) + *reg += 4; +} + +/* enable or disable a pinmux function */ +static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group, bool enable) +{ + struct samsung_pinctrl_drv_data *drvdata; + const unsigned int *pins; + struct samsung_pin_bank *bank; + void __iomem *reg; + u32 mask, shift, data, pin_offset, cnt; + + drvdata = pinctrl_dev_get_drvdata(pctldev); + pins = drvdata->pin_groups[group].pins; + + /* + * for each pin in the pin group selected, program the correspoding pin + * pin function number in the config register. + */ + for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) { + pin_to_reg_bank(drvdata->gc, pins[cnt] - drvdata->ctrl->base, + ®, &pin_offset, &bank); + mask = (1 << bank->func_width) - 1; + shift = pin_offset * bank->func_width; + + data = readl(reg); + data &= ~(mask << shift); + if (enable) + data |= drvdata->pin_groups[group].func << shift; + writel(data, reg); + } +} + +/* enable a specified pinmux by writing to registers */ +static int samsung_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group) +{ + samsung_pinmux_setup(pctldev, selector, group, true); + return 0; +} + +/* disable a specified pinmux by writing to registers */ +static void samsung_pinmux_disable(struct pinctrl_dev *pctldev, + unsigned selector, unsigned group) +{ + samsung_pinmux_setup(pctldev, selector, group, false); +} + +/* + * The calls to gpio_direction_output() and gpio_direction_input() + * leads to this function call (via the pinctrl_gpio_direction_{input|output}() + * function called from the gpiolib interface). + */ +static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, unsigned offset, bool input) +{ + struct samsung_pin_bank *bank; + void __iomem *reg; + u32 data, pin_offset, mask, shift; + + pin_to_reg_bank(range->gc, offset, ®, &pin_offset, &bank); + mask = (1 << bank->func_width) - 1; + shift = pin_offset * bank->func_width; + + data = readl(reg); + data &= ~(mask << shift); + if (!input) + data |= FUNC_OUTPUT << shift; + writel(data, reg); + return 0; +} + +/* list of pinmux callbacks for the pinmux vertical in pinctrl core */ +static struct pinmux_ops samsung_pinmux_ops = { + .get_functions_count = samsung_get_functions_count, + .get_function_name = samsung_pinmux_get_fname, + .get_function_groups = samsung_pinmux_get_groups, + .enable = samsung_pinmux_enable, + .disable = samsung_pinmux_disable, + .gpio_set_direction = samsung_pinmux_gpio_set_direction, +}; + +/* set or get the pin config settings for a specified pin */ +static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *config, bool set) +{ + struct samsung_pinctrl_drv_data *drvdata; + struct samsung_pin_bank *bank; + void __iomem *reg_base; + enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(*config); + u32 data, width, pin_offset, mask, shift; + u32 cfg_value, cfg_reg; + + drvdata = pinctrl_dev_get_drvdata(pctldev); + pin_to_reg_bank(drvdata->gc, pin - drvdata->ctrl->base, ®_base, + &pin_offset, &bank); + + switch (cfg_type) { + case PINCFG_TYPE_PUD: + width = bank->pud_width; + cfg_reg = PUD_REG; + break; + case PINCFG_TYPE_DRV: + width = bank->drv_width; + cfg_reg = DRV_REG; + break; + case PINCFG_TYPE_CON_PDN: + width = bank->conpdn_width; + cfg_reg = CONPDN_REG; + break; + case PINCFG_TYPE_PUD_PDN: + width = bank->pudpdn_width; + cfg_reg = PUDPDN_REG; + break; + default: + WARN_ON(1); + return -EINVAL; + } + + mask = (1 << width) - 1; + shift = pin_offset * width; + data = readl(reg_base + cfg_reg); + + if (set) { + cfg_value = PINCFG_UNPACK_VALUE(*config); + data &= ~(mask << shift); + data |= (cfg_value << shift); + writel(data, reg_base + cfg_reg); + } else { + data >>= shift; + data &= mask; + *config = PINCFG_PACK(cfg_type, data); + } + return 0; +} + +/* set the pin config settings for a specified pin */ +static int samsung_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long config) +{ + return samsung_pinconf_rw(pctldev, pin, &config, true); +} + +/* get the pin config settings for a specified pin */ +static int samsung_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *config) +{ + return samsung_pinconf_rw(pctldev, pin, config, false); +} + +/* set the pin config settings for a specified pin group */ +static int samsung_pinconf_group_set(struct pinctrl_dev *pctldev, + unsigned group, unsigned long config) +{ + struct samsung_pinctrl_drv_data *drvdata; + const unsigned int *pins; + unsigned int cnt; + + drvdata = pinctrl_dev_get_drvdata(pctldev); + pins = drvdata->pin_groups[group].pins; + + for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) + samsung_pinconf_set(pctldev, pins[cnt], config); + + return 0; +} + +/* get the pin config settings for a specified pin group */ +static int samsung_pinconf_group_get(struct pinctrl_dev *pctldev, + unsigned int group, unsigned long *config) +{ + struct samsung_pinctrl_drv_data *drvdata; + const unsigned int *pins; + + drvdata = pinctrl_dev_get_drvdata(pctldev); + pins = drvdata->pin_groups[group].pins; + samsung_pinconf_get(pctldev, pins[0], config); + return 0; +} + +/* list of pinconfig callbacks for pinconfig vertical in the pinctrl code */ +static struct pinconf_ops samsung_pinconf_ops = { + .pin_config_get = samsung_pinconf_get, + .pin_config_set = samsung_pinconf_set, + .pin_config_group_get = samsung_pinconf_group_get, + .pin_config_group_set = samsung_pinconf_group_set, +}; + +/* gpiolib gpio_set callback function */ +static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) +{ + void __iomem *reg; + u32 pin_offset, data; + + pin_to_reg_bank(gc, offset, ®, &pin_offset, NULL); + data = readl(reg + DAT_REG); + data &= ~(1 << pin_offset); + if (value) + data |= 1 << pin_offset; + writel(data, reg + DAT_REG); +} + +/* gpiolib gpio_get callback function */ +static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset) +{ + void __iomem *reg; + u32 pin_offset, data; + + pin_to_reg_bank(gc, offset, ®, &pin_offset, NULL); + data = readl(reg + DAT_REG); + data >>= pin_offset; + data &= 1; + return data; +} + +/* + * gpiolib gpio_direction_input callback function. The setting of the pin + * mux function as 'gpio input' will be handled by the pinctrl susbsystem + * interface. + */ +static int samsung_gpio_direction_input(struct gpio_chip *gc, unsigned offset) +{ + return pinctrl_gpio_direction_input(gc->base + offset); +} + +/* + * gpiolib gpio_direction_output callback function. The setting of the pin + * mux function as 'gpio output' will be handled by the pinctrl susbsystem + * interface. + */ +static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset, + int value) +{ + samsung_gpio_set(gc, offset, value); + return pinctrl_gpio_direction_output(gc->base + offset); +} + +/* + * Parse the pin names listed in the 'samsung,pins' property and convert it + * into a list of gpio numbers are create a pin group from it. + */ +static int __init samsung_pinctrl_parse_dt_pins(struct platform_device *pdev, + struct device_node *cfg_np, struct pinctrl_desc *pctl, + unsigned int **pin_list, unsigned int *npins) +{ + struct device *dev = &pdev->dev; + struct property *prop; + struct pinctrl_pin_desc const *pdesc = pctl->pins; + unsigned int idx = 0, cnt; + const char *pin_name; + + *npins = of_property_count_strings(cfg_np, "samsung,pins"); + if (*npins < 0) { + dev_err(dev, "invalid pin list in %s node", cfg_np->name); + return -EINVAL; + } + + *pin_list = devm_kzalloc(dev, *npins * sizeof(**pin_list), GFP_KERNEL); + if (!*pin_list) { + dev_err(dev, "failed to allocate memory for pin list\n"); + return -ENOMEM; + } + + of_property_for_each_string(cfg_np, "samsung,pins", prop, pin_name) { + for (cnt = 0; cnt < pctl->npins; cnt++) { + if (pdesc[cnt].name) { + if (!strcmp(pin_name, pdesc[cnt].name)) { + (*pin_list)[idx++] = pdesc[cnt].number; + break; + } + } + } + if (cnt == pctl->npins) { + dev_err(dev, "pin %s not valid in %s node\n", + pin_name, cfg_np->name); + devm_kfree(dev, *pin_list); + return -EINVAL; + } + } + + return 0; +} + +/* + * Parse the information about all the available pin groups and pin functions + * from device node of the pin-controller. A pin group is formed with all + * the pins listed in the "samsung,pins" property. + */ +static int __init samsung_pinctrl_parse_dt(struct platform_device *pdev, + struct samsung_pinctrl_drv_data *drvdata) +{ + struct device *dev = &pdev->dev; + struct device_node *dev_np = dev->of_node; + struct device_node *cfg_np; + struct samsung_pin_group *groups, *grp; + struct samsung_pmx_func *functions, *func; + unsigned *pin_list; + unsigned int npins, grp_cnt, func_idx = 0; + char *gname, *fname; + int ret; + + grp_cnt = of_get_child_count(dev_np); + if (!grp_cnt) + return -EINVAL; + + groups = devm_kzalloc(dev, grp_cnt * sizeof(*groups), GFP_KERNEL); + if (!groups) { + dev_err(dev, "failed allocate memory for ping group list\n"); + return -EINVAL; + } + grp = groups; + + functions = devm_kzalloc(dev, grp_cnt * sizeof(*functions), GFP_KERNEL); + if (!functions) { + dev_err(dev, "failed to allocate memory for function list\n"); + return -EINVAL; + } + func = functions; + + /* + * Iterate over all the child nodes of the pin controller node + * and create pin groups and pin function lists. + */ + for_each_child_of_node(dev_np, cfg_np) { + u32 function; + if (of_find_property(cfg_np, "interrupt-controller", NULL)) + continue; + + ret = samsung_pinctrl_parse_dt_pins(pdev, cfg_np, + &drvdata->pctl, &pin_list, &npins); + if (ret) + return ret; + + /* derive pin group name from the node name */ + gname = devm_kzalloc(dev, strlen(cfg_np->name) + GSUFFIX_LEN, + GFP_KERNEL); + if (!gname) { + dev_err(dev, "failed to alloc memory for group name\n"); + return -ENOMEM; + } + sprintf(gname, "%s%s", cfg_np->name, GROUP_SUFFIX); + + grp->name = gname; + grp->pins = pin_list; + grp->num_pins = npins; + of_property_read_u32(cfg_np, "samsung,pin-function", &function); + grp->func = function; + grp++; + + if (!of_find_property(cfg_np, "samsung,pin-function", NULL)) + continue; + + /* derive function name from the node name */ + fname = devm_kzalloc(dev, strlen(cfg_np->name) + FSUFFIX_LEN, + GFP_KERNEL); + if (!fname) { + dev_err(dev, "failed to alloc memory for func name\n"); + return -ENOMEM; + } + sprintf(fname, "%s%s", cfg_np->name, FUNCTION_SUFFIX); + + func->name = fname; + func->groups = devm_kzalloc(dev, sizeof(char *), GFP_KERNEL); + if (!func->groups) { + dev_err(dev, "failed to alloc memory for group list " + "in pin function"); + return -ENOMEM; + } + func->groups[0] = gname; + func->num_groups = 1; + func++; + func_idx++; + } + + drvdata->pin_groups = groups; + drvdata->nr_groups = grp_cnt; + drvdata->pmx_functions = functions; + drvdata->nr_functions = func_idx; + + return 0; +} + +/* register the pinctrl interface with the pinctrl subsystem */ +static int __init samsung_pinctrl_register(struct platform_device *pdev, + struct samsung_pinctrl_drv_data *drvdata) +{ + struct pinctrl_desc *ctrldesc = &drvdata->pctl; + struct pinctrl_pin_desc *pindesc, *pdesc; + struct samsung_pin_bank *pin_bank; + char *pin_names; + int pin, bank, ret; + + ctrldesc->name = "samsung-pinctrl"; + ctrldesc->owner = THIS_MODULE; + ctrldesc->pctlops = &samsung_pctrl_ops; + ctrldesc->pmxops = &samsung_pinmux_ops; + ctrldesc->confops = &samsung_pinconf_ops; + + pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) * + drvdata->ctrl->nr_pins, GFP_KERNEL); + if (!pindesc) { + dev_err(&pdev->dev, "mem alloc for pin descriptors failed\n"); + return -ENOMEM; + } + ctrldesc->pins = pindesc; + ctrldesc->npins = drvdata->ctrl->nr_pins; + ctrldesc->npins = drvdata->ctrl->nr_pins; + + /* dynamically populate the pin number and pin name for pindesc */ + for (pin = 0, pdesc = pindesc; pin < ctrldesc->npins; pin++, pdesc++) + pdesc->number = pin + drvdata->ctrl->base; + + /* + * allocate space for storing the dynamically generated names for all + * the pins which belong to this pin-controller. + */ + pin_names = devm_kzalloc(&pdev->dev, sizeof(char) * PIN_NAME_LENGTH * + drvdata->ctrl->nr_pins, GFP_KERNEL); + if (!pin_names) { + dev_err(&pdev->dev, "mem alloc for pin names failed\n"); + return -ENOMEM; + } + + /* for each pin, the name of the pin is pin-bank name + pin number */ + for (bank = 0; bank < drvdata->ctrl->nr_banks; bank++) { + pin_bank = &drvdata->ctrl->pin_banks[bank]; + for (pin = 0; pin < pin_bank->nr_pins; pin++) { + sprintf(pin_names, "%s-%d", pin_bank->name, pin); + pdesc = pindesc + pin_bank->pin_base + pin; + pdesc->name = pin_names; + pin_names += PIN_NAME_LENGTH; + } + } + + drvdata->pctl_dev = pinctrl_register(ctrldesc, &pdev->dev, drvdata); + if (!drvdata->pctl_dev) { + dev_err(&pdev->dev, "could not register pinctrl driver\n"); + return -EINVAL; + } + + drvdata->grange.name = "samsung-pctrl-gpio-range"; + drvdata->grange.id = 0; + drvdata->grange.base = drvdata->ctrl->base; + drvdata->grange.npins = drvdata->ctrl->nr_pins; + drvdata->grange.gc = drvdata->gc; + pinctrl_add_gpio_range(drvdata->pctl_dev, &drvdata->grange); + + ret = samsung_pinctrl_parse_dt(pdev, drvdata); + if (ret) { + pinctrl_unregister(drvdata->pctl_dev); + return ret; + } + + return 0; +} + +/* register the gpiolib interface with the gpiolib subsystem */ +static int __init samsung_gpiolib_register(struct platform_device *pdev, + struct samsung_pinctrl_drv_data *drvdata) +{ + struct gpio_chip *gc; + int ret; + + gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL); + if (!gc) { + dev_err(&pdev->dev, "mem alloc for gpio_chip failed\n"); + return -ENOMEM; + } + + drvdata->gc = gc; + gc->base = drvdata->ctrl->base; + gc->ngpio = drvdata->ctrl->nr_pins; + gc->dev = &pdev->dev; + gc->set = samsung_gpio_set; + gc->get = samsung_gpio_get; + gc->direction_input = samsung_gpio_direction_input; + gc->direction_output = samsung_gpio_direction_output; + gc->label = drvdata->ctrl->label; + gc->owner = THIS_MODULE; + ret = gpiochip_add(gc); + if (ret) { + dev_err(&pdev->dev, "failed to register gpio_chip %s, error " + "code: %d\n", gc->label, ret); + return ret; + } + + return 0; +} + +/* unregister the gpiolib interface with the gpiolib subsystem */ +static int __init samsung_gpiolib_unregister(struct platform_device *pdev, + struct samsung_pinctrl_drv_data *drvdata) +{ + int ret = gpiochip_remove(drvdata->gc); + if (ret) { + dev_err(&pdev->dev, "gpio chip remove failed\n"); + return ret; + } + return 0; +} + +static const struct of_device_id samsung_pinctrl_dt_match[]; + +/* retrieve the soc specific data */ +static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( + struct platform_device *pdev) +{ + int id; + const struct of_device_id *match; + const struct device_node *node = pdev->dev.of_node; + + id = of_alias_get_id(pdev->dev.of_node, "pinctrl"); + if (id < 0) { + dev_err(&pdev->dev, "failed to get alias id\n"); + return NULL; + } + match = of_match_node(samsung_pinctrl_dt_match, node); + return (struct samsung_pin_ctrl *)match->data + id; +} + +static int __devinit samsung_pinctrl_probe(struct platform_device *pdev) +{ + struct samsung_pinctrl_drv_data *drvdata; + struct device *dev = &pdev->dev; + struct samsung_pin_ctrl *ctrl; + struct resource *res; + int ret; + + if (!dev->of_node) { + dev_err(dev, "device tree node not found\n"); + return -ENODEV; + } + + ctrl = samsung_pinctrl_get_soc_data(pdev); + if (!ctrl) { + dev_err(&pdev->dev, "driver data not available\n"); + return -EINVAL; + } + + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) { + dev_err(dev, "failed to allocate memory for driver's " + "private data\n"); + return -ENOMEM; + } + drvdata->ctrl = ctrl; + drvdata->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "cannot find IO resource\n"); + return -ENOENT; + } + + drvdata->virt_base = devm_request_and_ioremap(&pdev->dev, res); + if (!drvdata->virt_base) { + dev_err(dev, "ioremap failed\n"); + return -ENODEV; + } + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (res) + drvdata->irq = res->start; + + ret = samsung_gpiolib_register(pdev, drvdata); + if (ret) + return ret; + + ret = samsung_pinctrl_register(pdev, drvdata); + if (ret) { + samsung_gpiolib_unregister(pdev, drvdata); + return ret; + } + + if (ctrl->eint_gpio_init) + ctrl->eint_gpio_init(drvdata); + if (ctrl->eint_wkup_init) + ctrl->eint_wkup_init(drvdata); + + platform_set_drvdata(pdev, drvdata); + return 0; +} + +static const struct of_device_id samsung_pinctrl_dt_match[] = { + { .compatible = "samsung,pinctrl-exynos4210", + .data = (void *)exynos4210_pin_ctrl }, + {}, +}; +MODULE_DEVICE_TABLE(of, samsung_pinctrl_dt_match); + +static struct platform_driver samsung_pinctrl_driver = { + .probe = samsung_pinctrl_probe, + .driver = { + .name = "samsung-pinctrl", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(samsung_pinctrl_dt_match), + }, +}; + +static int __init samsung_pinctrl_drv_register(void) +{ + return platform_driver_register(&samsung_pinctrl_driver); +} +postcore_initcall(samsung_pinctrl_drv_register); + +static void __exit samsung_pinctrl_drv_unregister(void) +{ + platform_driver_unregister(&samsung_pinctrl_driver); +} +module_exit(samsung_pinctrl_drv_unregister); + +MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com>"); +MODULE_DESCRIPTION("Samsung pinctrl driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h new file mode 100644 index 000000000000..b8956934cda6 --- /dev/null +++ b/drivers/pinctrl/pinctrl-samsung.h @@ -0,0 +1,239 @@ +/* + * pin-controller/pin-mux/pin-config/gpio-driver for Samsung's SoC's. + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * Copyright (c) 2012 Linaro Ltd + * http://www.linaro.org + * + * Author: Thomas Abraham <thomas.ab@samsung.com> + * + * 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. + */ + +#ifndef __PINCTRL_SAMSUNG_H +#define __PINCTRL_SAMSUNG_H + +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/consumer.h> +#include <linux/pinctrl/machine.h> + +/* register offsets within a pin bank */ +#define DAT_REG 0x4 +#define PUD_REG 0x8 +#define DRV_REG 0xC +#define CONPDN_REG 0x10 +#define PUDPDN_REG 0x14 + +/* pinmux function number for pin as gpio output line */ +#define FUNC_OUTPUT 0x1 + +/** + * enum pincfg_type - possible pin configuration types supported. + * @PINCFG_TYPE_PUD: Pull up/down configuration. + * @PINCFG_TYPE_DRV: Drive strength configuration. + * @PINCFG_TYPE_CON_PDN: Pin function in power down mode. + * @PINCFG_TYPE_PUD_PDN: Pull up/down configuration in power down mode. + */ +enum pincfg_type { + PINCFG_TYPE_PUD, + PINCFG_TYPE_DRV, + PINCFG_TYPE_CON_PDN, + PINCFG_TYPE_PUD_PDN, +}; + +/* + * pin configuration (pull up/down and drive strength) type and its value are + * packed together into a 16-bits. The upper 8-bits represent the configuration + * type and the lower 8-bits hold the value of the configuration type. + */ +#define PINCFG_TYPE_MASK 0xFF +#define PINCFG_VALUE_SHIFT 8 +#define PINCFG_VALUE_MASK (0xFF << PINCFG_VALUE_SHIFT) +#define PINCFG_PACK(type, value) (((value) << PINCFG_VALUE_SHIFT) | type) +#define PINCFG_UNPACK_TYPE(cfg) ((cfg) & PINCFG_TYPE_MASK) +#define PINCFG_UNPACK_VALUE(cfg) (((cfg) & PINCFG_VALUE_MASK) >> \ + PINCFG_VALUE_SHIFT) +/** + * enum eint_type - possible external interrupt types. + * @EINT_TYPE_NONE: bank does not support external interrupts + * @EINT_TYPE_GPIO: bank supportes external gpio interrupts + * @EINT_TYPE_WKUP: bank supportes external wakeup interrupts + * + * Samsung GPIO controller groups all the available pins into banks. The pins + * in a pin bank can support external gpio interrupts or external wakeup + * interrupts or no interrupts at all. From a software perspective, the only + * difference between external gpio and external wakeup interrupts is that + * the wakeup interrupts can additionally wakeup the system if it is in + * suspended state. + */ +enum eint_type { + EINT_TYPE_NONE, + EINT_TYPE_GPIO, + EINT_TYPE_WKUP, +}; + +/* maximum length of a pin in pin descriptor (example: "gpa0-0") */ +#define PIN_NAME_LENGTH 10 + +#define PIN_GROUP(n, p, f) \ + { \ + .name = n, \ + .pins = p, \ + .num_pins = ARRAY_SIZE(p), \ + .func = f \ + } + +#define PMX_FUNC(n, g) \ + { \ + .name = n, \ + .groups = g, \ + .num_groups = ARRAY_SIZE(g), \ + } + +struct samsung_pinctrl_drv_data; + +/** + * struct samsung_pin_bank: represent a controller pin-bank. + * @reg_offset: starting offset of the pin-bank registers. + * @pin_base: starting pin number of the bank. + * @nr_pins: number of pins included in this bank. + * @func_width: width of the function selector bit field. + * @pud_width: width of the pin pull up/down selector bit field. + * @drv_width: width of the pin driver strength selector bit field. + * @conpdn_width: width of the sleep mode function selector bin field. + * @pudpdn_width: width of the sleep mode pull up/down selector bit field. + * @eint_type: type of the external interrupt supported by the bank. + * @irq_base: starting controller local irq number of the bank. + * @name: name to be prefixed for each pin in this pin bank. + */ +struct samsung_pin_bank { + u32 pctl_offset; + u32 pin_base; + u8 nr_pins; + u8 func_width; + u8 pud_width; + u8 drv_width; + u8 conpdn_width; + u8 pudpdn_width; + enum eint_type eint_type; + u32 irq_base; + char *name; +}; + +/** + * struct samsung_pin_ctrl: represent a pin controller. + * @pin_banks: list of pin banks included in this controller. + * @nr_banks: number of pin banks. + * @base: starting system wide pin number. + * @nr_pins: number of pins supported by the controller. + * @nr_gint: number of external gpio interrupts supported. + * @nr_wint: number of external wakeup interrupts supported. + * @geint_con: offset of the ext-gpio controller registers. + * @geint_mask: offset of the ext-gpio interrupt mask registers. + * @geint_pend: offset of the ext-gpio interrupt pending registers. + * @weint_con: offset of the ext-wakeup controller registers. + * @weint_mask: offset of the ext-wakeup interrupt mask registers. + * @weint_pend: offset of the ext-wakeup interrupt pending registers. + * @svc: offset of the interrupt service register. + * @eint_gpio_init: platform specific callback to setup the external gpio + * interrupts for the controller. + * @eint_wkup_init: platform specific callback to setup the external wakeup + * interrupts for the controller. + * @label: for debug information. + */ +struct samsung_pin_ctrl { + struct samsung_pin_bank *pin_banks; + u32 nr_banks; + + u32 base; + u32 nr_pins; + u32 nr_gint; + u32 nr_wint; + + u32 geint_con; + u32 geint_mask; + u32 geint_pend; + + u32 weint_con; + u32 weint_mask; + u32 weint_pend; + + u32 svc; + + int (*eint_gpio_init)(struct samsung_pinctrl_drv_data *); + int (*eint_wkup_init)(struct samsung_pinctrl_drv_data *); + char *label; +}; + +/** + * struct samsung_pinctrl_drv_data: wrapper for holding driver data together. + * @virt_base: register base address of the controller. + * @dev: device instance representing the controller. + * @irq: interrpt number used by the controller to notify gpio interrupts. + * @ctrl: pin controller instance managed by the driver. + * @pctl: pin controller descriptor registered with the pinctrl subsystem. + * @pctl_dev: cookie representing pinctrl device instance. + * @pin_groups: list of pin groups available to the driver. + * @nr_groups: number of such pin groups. + * @pmx_functions: list of pin functions available to the driver. + * @nr_function: number of such pin functions. + * @gc: gpio_chip instance registered with gpiolib. + * @grange: linux gpio pin range supported by this controller. + */ +struct samsung_pinctrl_drv_data { + void __iomem *virt_base; + struct device *dev; + int irq; + + struct samsung_pin_ctrl *ctrl; + struct pinctrl_desc pctl; + struct pinctrl_dev *pctl_dev; + + const struct samsung_pin_group *pin_groups; + unsigned int nr_groups; + const struct samsung_pmx_func *pmx_functions; + unsigned int nr_functions; + + struct irq_domain *gpio_irqd; + struct irq_domain *wkup_irqd; + + struct gpio_chip *gc; + struct pinctrl_gpio_range grange; +}; + +/** + * struct samsung_pin_group: represent group of pins of a pinmux function. + * @name: name of the pin group, used to lookup the group. + * @pins: the pins included in this group. + * @num_pins: number of pins included in this group. + * @func: the function number to be programmed when selected. + */ +struct samsung_pin_group { + const char *name; + const unsigned int *pins; + u8 num_pins; + u8 func; +}; + +/** + * struct samsung_pmx_func: represent a pin function. + * @name: name of the pin function, used to lookup the function. + * @groups: one or more names of pin groups that provide this function. + * @num_groups: number of groups included in @groups. + */ +struct samsung_pmx_func { + const char *name; + const char **groups; + u8 num_groups; +}; + +/* list of all exported SoC specific data */ +extern struct samsung_pin_ctrl exynos4210_pin_ctrl[]; + +#endif /* __PINCTRL_SAMSUNG_H */ diff --git a/include/linux/leds.h b/include/linux/leds.h index 3aade1d8f410..c6f8dad2ceb0 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -237,4 +237,20 @@ struct gpio_led_platform_data { struct platform_device *gpio_led_register_device( int id, const struct gpio_led_platform_data *pdata); +enum cpu_led_event { + CPU_LED_IDLE_START, /* CPU enters idle */ + CPU_LED_IDLE_END, /* CPU idle ends */ + CPU_LED_START, /* Machine starts, especially resume */ + CPU_LED_STOP, /* Machine stops, especially suspend */ + CPU_LED_HALTED, /* Machine shutdown */ +}; +#ifdef CONFIG_LEDS_TRIGGER_CPU +extern void ledtrig_cpu(enum cpu_led_event evt); +#else +static inline void ledtrig_cpu(enum cpu_led_event evt) +{ + return; +} +#endif + #endif /* __LINUX_LEDS_H_INCLUDED */ |