summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/bus/omap-ocp2scp.txt10
-rw-r--r--Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt196
-rw-r--r--arch/arm/Kconfig54
-rw-r--r--arch/arm/boot/dts/exynos4210-pinctrl.dtsi457
-rw-r--r--arch/arm/boot/dts/exynos4210.dtsi37
-rw-r--r--arch/arm/boot/dts/omap4.dtsi8
-rw-r--r--arch/arm/configs/afeb9260_defconfig1
-rw-r--r--arch/arm/configs/at91rm9200_defconfig2
-rw-r--r--arch/arm/configs/at91sam9261_defconfig2
-rw-r--r--arch/arm/configs/at91sam9263_defconfig3
-rw-r--r--arch/arm/configs/at91sam9g20_defconfig2
-rw-r--r--arch/arm/configs/at91sam9rl_defconfig2
-rw-r--r--arch/arm/configs/cpu9260_defconfig2
-rw-r--r--arch/arm/configs/cpu9g20_defconfig2
-rw-r--r--arch/arm/configs/qil-a9260_defconfig3
-rw-r--r--arch/arm/configs/stamp9g20_defconfig1
-rw-r--r--arch/arm/configs/usb-a9260_defconfig1
-rw-r--r--arch/arm/include/asm/leds.h50
-rw-r--r--arch/arm/kernel/Makefile1
-rw-r--r--arch/arm/kernel/leds.c121
-rw-r--r--arch/arm/kernel/process.c6
-rw-r--r--arch/arm/kernel/time.c17
-rw-r--r--arch/arm/mach-at91/at91rm9200_devices.c92
-rw-r--r--arch/arm/mach-at91/at91sam9260_devices.c84
-rw-r--r--arch/arm/mach-at91/at91sam9261_devices.c60
-rw-r--r--arch/arm/mach-at91/at91sam9263.c4
-rw-r--r--arch/arm/mach-at91/at91sam9263_devices.c161
-rw-r--r--arch/arm/mach-at91/at91sam9rl_devices.c60
-rw-r--r--arch/arm/mach-at91/board-afeb-9260v1.c14
-rw-r--r--arch/arm/mach-at91/board-carmeva.c14
-rw-r--r--arch/arm/mach-at91/board-cpu9krea.c17
-rw-r--r--arch/arm/mach-at91/board-cpuat91.c13
-rw-r--r--arch/arm/mach-at91/board-csb337.c16
-rw-r--r--arch/arm/mach-at91/board-eb9200.c14
-rw-r--r--arch/arm/mach-at91/board-ecbat91.c32
-rw-r--r--arch/arm/mach-at91/board-eco920.c36
-rw-r--r--arch/arm/mach-at91/board-flexibity.c14
-rw-r--r--arch/arm/mach-at91/board-foxg20.c16
-rw-r--r--arch/arm/mach-at91/board-kafa.c17
-rw-r--r--arch/arm/mach-at91/board-kb9202.c37
-rw-r--r--arch/arm/mach-at91/board-neocore926.c13
-rw-r--r--arch/arm/mach-at91/board-picotux200.c14
-rw-r--r--arch/arm/mach-at91/board-qil-a9260.c14
-rw-r--r--arch/arm/mach-at91/board-rm9200dk.c17
-rw-r--r--arch/arm/mach-at91/board-rm9200ek.c17
-rw-r--r--arch/arm/mach-at91/board-rsi-ews.c16
-rw-r--r--arch/arm/mach-at91/board-sam9-l9260.c39
-rw-r--r--arch/arm/mach-at91/board-sam9260ek.c16
-rw-r--r--arch/arm/mach-at91/board-sam9261ek.c16
-rw-r--r--arch/arm/mach-at91/board-sam9263ek.c13
-rw-r--r--arch/arm/mach-at91/board-sam9g20ek.c16
-rw-r--r--arch/arm/mach-at91/board-sam9rlek.c13
-rw-r--r--arch/arm/mach-at91/board-stamp9g20.c14
-rw-r--r--arch/arm/mach-at91/board-usb-a926x.c2
-rw-r--r--arch/arm/mach-at91/board-yl-9200.c16
-rw-r--r--arch/arm/mach-at91/include/mach/board.h1
-rw-r--r--arch/arm/mach-at91/leds.c105
-rw-r--r--arch/arm/mach-clps711x/Makefile2
-rw-r--r--arch/arm/mach-clps711x/common.c1
-rw-r--r--arch/arm/mach-clps711x/p720t-leds.c63
-rw-r--r--arch/arm/mach-clps711x/p720t.c62
-rw-r--r--arch/arm/mach-ebsa110/Makefile4
-rw-r--r--arch/arm/mach-ebsa110/leds.c81
-rw-r--r--arch/arm/mach-exynos/Kconfig2
-rw-r--r--arch/arm/mach-exynos/common.c26
-rw-r--r--arch/arm/mach-footbridge/Makefile4
-rw-r--r--arch/arm/mach-footbridge/ebsa285-leds.c138
-rw-r--r--arch/arm/mach-footbridge/ebsa285.c81
-rw-r--r--arch/arm/mach-footbridge/netwinder-hw.c112
-rw-r--r--arch/arm/mach-footbridge/netwinder-leds.c138
-rw-r--r--arch/arm/mach-integrator/Makefile3
-rw-r--r--arch/arm/mach-integrator/core.c3
-rw-r--r--arch/arm/mach-integrator/include/mach/cm.h2
-rw-r--r--arch/arm/mach-integrator/leds.c161
-rw-r--r--arch/arm/mach-ks8695/Makefile3
-rw-r--r--arch/arm/mach-ks8695/devices.c21
-rw-r--r--arch/arm/mach-ks8695/include/mach/devices.h5
-rw-r--r--arch/arm/mach-ks8695/leds.c92
-rw-r--r--arch/arm/mach-omap1/Makefile8
-rw-r--r--arch/arm/mach-omap1/board-h2.c32
-rw-r--r--arch/arm/mach-omap1/board-h3.c32
-rw-r--r--arch/arm/mach-omap1/board-osk.c33
-rw-r--r--arch/arm/mach-omap1/leds-h2p2-debug.c166
-rw-r--r--arch/arm/mach-omap1/leds-innovator.c98
-rw-r--r--arch/arm/mach-omap1/leds-osk.c113
-rw-r--r--arch/arm/mach-omap1/leds.c69
-rw-r--r--arch/arm/mach-omap1/leds.h3
-rw-r--r--arch/arm/mach-omap1/time.c1
-rw-r--r--arch/arm/mach-omap1/timer32k.c1
-rw-r--r--arch/arm/mach-omap2/Kconfig2
-rw-r--r--arch/arm/mach-omap2/Makefile5
-rw-r--r--arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c1
-rw-r--r--arch/arm/mach-orion5x/rd88f5181l-ge-setup.c1
-rw-r--r--arch/arm/mach-orion5x/rd88f5182-setup.c72
-rw-r--r--arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c1
-rw-r--r--arch/arm/mach-pnx4008/time.c1
-rw-r--r--arch/arm/mach-pxa/Makefile8
-rw-r--r--arch/arm/mach-pxa/idp.c81
-rw-r--r--arch/arm/mach-pxa/leds-idp.c115
-rw-r--r--arch/arm/mach-pxa/leds-lubbock.c124
-rw-r--r--arch/arm/mach-pxa/leds-mainstone.c119
-rw-r--r--arch/arm/mach-pxa/leds.c32
-rw-r--r--arch/arm/mach-pxa/leds.h13
-rw-r--r--arch/arm/mach-pxa/lubbock.c95
-rw-r--r--arch/arm/mach-pxa/mainstone.c94
-rw-r--r--arch/arm/mach-realview/core.c39
-rw-r--r--arch/arm/mach-realview/core.h2
-rw-r--r--arch/arm/mach-realview/realview_eb.c5
-rw-r--r--arch/arm/mach-realview/realview_pb1176.c5
-rw-r--r--arch/arm/mach-realview/realview_pb11mp.c5
-rw-r--r--arch/arm/mach-realview/realview_pba8.c5
-rw-r--r--arch/arm/mach-realview/realview_pbx.c5
-rw-r--r--arch/arm/mach-sa1100/Makefile9
-rw-r--r--arch/arm/mach-sa1100/assabet.c85
-rw-r--r--arch/arm/mach-sa1100/badge4.c30
-rw-r--r--arch/arm/mach-sa1100/cerf.c42
-rw-r--r--arch/arm/mach-sa1100/hackkit.c32
-rw-r--r--arch/arm/mach-sa1100/lart.c26
-rw-r--r--arch/arm/mach-sa1100/leds-assabet.c113
-rw-r--r--arch/arm/mach-sa1100/leds-badge4.c110
-rw-r--r--arch/arm/mach-sa1100/leds-cerf.c110
-rw-r--r--arch/arm/mach-sa1100/leds-hackkit.c112
-rw-r--r--arch/arm/mach-sa1100/leds-lart.c101
-rw-r--r--arch/arm/mach-sa1100/leds.c50
-rw-r--r--arch/arm/mach-sa1100/leds.h13
-rw-r--r--arch/arm/mach-shark/Makefile4
-rw-r--r--arch/arm/mach-shark/core.c1
-rw-r--r--arch/arm/mach-shark/leds.c220
-rw-r--r--arch/arm/mach-tegra/Makefile4
-rw-r--r--arch/arm/mach-tegra/board-dt-tegra20.c1
-rw-r--r--arch/arm/mach-tegra/clock.c570
-rw-r--r--arch/arm/mach-tegra/clock.h40
-rw-r--r--arch/arm/mach-tegra/common.c1
-rw-r--r--arch/arm/mach-tegra/cpu-tegra.c48
-rw-r--r--arch/arm/mach-tegra/include/mach/clk.h3
-rw-r--r--arch/arm/mach-tegra/tegra20_clocks.c1555
-rw-r--r--arch/arm/mach-tegra/tegra20_clocks.h42
-rw-r--r--arch/arm/mach-tegra/tegra20_clocks_data.c1138
-rw-r--r--arch/arm/mach-tegra/tegra2_clocks.c2484
-rw-r--r--arch/arm/mach-tegra/tegra30_clocks.c2475
-rw-r--r--arch/arm/mach-tegra/tegra30_clocks.h53
-rw-r--r--arch/arm/mach-tegra/tegra30_clocks_data.c1374
-rw-r--r--arch/arm/mach-versatile/core.c5
-rw-r--r--arch/arm/plat-omap/Kconfig3
-rw-r--r--arch/arm/plat-omap/debug-leds.c293
-rw-r--r--arch/arm/plat-samsung/time.c1
-rw-r--r--arch/arm/plat-versatile/Kconfig4
-rw-r--r--arch/arm/plat-versatile/leds.c8
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/bus/Kconfig21
-rw-r--r--drivers/bus/Makefile8
-rw-r--r--drivers/bus/omap-ocp2scp.c88
-rw-r--r--drivers/bus/omap_l3_noc.c (renamed from arch/arm/mach-omap2/omap_l3_noc.c)4
-rw-r--r--drivers/bus/omap_l3_noc.h (renamed from arch/arm/mach-omap2/omap_l3_noc.h)0
-rw-r--r--drivers/bus/omap_l3_smx.c (renamed from arch/arm/mach-omap2/omap_l3_smx.c)0
-rw-r--r--drivers/bus/omap_l3_smx.h (renamed from arch/arm/mach-omap2/omap_l3_smx.h)0
-rw-r--r--drivers/char/nwflash.c34
-rw-r--r--drivers/gpio/gpio-samsung.c21
-rw-r--r--drivers/i2c/busses/i2c-tegra.c130
-rw-r--r--drivers/leds/Kconfig10
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/ledtrig-cpu.c163
-rw-r--r--drivers/mtd/nand/Kconfig40
-rw-r--r--drivers/pinctrl/Kconfig9
-rw-r--r--drivers/pinctrl/Makefile2
-rw-r--r--drivers/pinctrl/pinctrl-exynos.c560
-rw-r--r--drivers/pinctrl/pinctrl-exynos.h217
-rw-r--r--drivers/pinctrl/pinctrl-samsung.c888
-rw-r--r--drivers/pinctrl/pinctrl-samsung.h239
-rw-r--r--include/linux/leds.h16
171 files changed, 9770 insertions, 8256 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/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 c5f9ae5dbd1a..aad7400e0913 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -686,6 +686,7 @@ config ARCH_TEGRA
select NEED_MACH_IO_H if PCI
select ARCH_HAS_CPUFREQ
select USE_OF
+ select COMMON_CLK
help
This enables support for NVIDIA Tegra based systems (Tegra APX,
Tegra 6xx and Tegra 2 series).
@@ -1781,59 +1782,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/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi
index 04cbbcb6ff91..8a780b2a5083 100644
--- a/arch/arm/boot/dts/omap4.dtsi
+++ b/arch/arm/boot/dts/omap4.dtsi
@@ -295,5 +295,13 @@
interrupt-parent = <&gic>;
ti,hwmods = "dmic";
};
+
+ 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 7ad2d5cf7008..8951577c4ced 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 7b9c2ba396ed..156e639257c9 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 8df5c1bdff92..06c0c6e025b9 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 eb6bbf86fb9f..1e176aaaaecb 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 f09fff932172..ea4479e7c3f4 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 f2f0256232e3..5872b49bfaed 100644
--- a/arch/arm/mach-clps711x/Makefile
+++ b/arch/arm/mach-clps711x/Makefile
@@ -16,5 +16,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/common.c b/arch/arm/mach-clps711x/common.c
index f15293bd7974..3a4af00db9e3 100644
--- a/arch/arm/mach-clps711x/common.c
+++ b/arch/arm/mach-clps711x/common.c
@@ -30,7 +30,6 @@
#include <asm/sizes.h>
#include <mach/hardware.h>
#include <asm/irq.h>
-#include <asm/leds.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/mach/map.h>
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 b5b4c8c9db11..195b50eb1e57 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/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-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 3fa6c51390da..2af5034ea29e 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 44a4ab195fbc..cd8836f43f01 100644
--- a/arch/arm/mach-omap1/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -31,6 +31,7 @@
#include <linux/i2c/tps65010.h>
#include <linux/smc91x.h>
#include <linux/omapfb.h>
+#include <linux/leds.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -306,12 +307,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)
@@ -406,6 +434,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 86cb5a04a404..1fa9c45c1ae5 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -31,6 +31,7 @@
#include <linux/i2c/tps65010.h>
#include <linux/smc91x.h>
#include <linux/omapfb.h>
+#include <linux/leds.h>
#include <asm/setup.h>
#include <asm/page.h>
@@ -324,6 +325,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,
@@ -331,6 +358,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 = {
@@ -398,6 +426,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 8784705edb60..7ee1c1eac356 100644
--- a/arch/arm/mach-omap1/board-osk.c
+++ b/arch/arm/mach-omap1/board-osk.c
@@ -380,10 +380,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)
@@ -508,6 +535,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 f6b14a14a957..000000000000
--- a/arch/arm/mach-omap1/leds-h2p2-debug.c
+++ /dev/null
@@ -1,166 +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 <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);
- }
-
- __raw_writew(~0, &fpga->leds);
- led_state &= ~LED_STATE_ENABLED;
- 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)
- __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 ae6dd93b8ddc..000000000000
--- a/arch/arm/mach-omap1/leds.c
+++ /dev/null
@@ -1,69 +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 <asm/leds.h>
-#include <asm/mach-types.h>
-
-#include <plat/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 fcd4e85c4ddc..728b05eb2964 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -44,6 +44,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"
@@ -63,6 +64,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 f6a24b3f9c4f..7fed980acb93 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -199,11 +199,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-pnx4008/time.c b/arch/arm/mach-pnx4008/time.c
index 0cfe8af3d3be..47a7ae96156a 100644
--- a/arch/arm/mach-pnx4008/time.c
+++ b/arch/arm/mach-pnx4008/time.c
@@ -25,7 +25,6 @@
#include <linux/io.h>
#include <mach/hardware.h>
-#include <asm/leds.h>
#include <asm/mach/time.h>
#include <asm/errno.h>
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index be0f7df8685c..d4337e300ada 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -95,12 +95,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 45868bb43cbd..d22dee96484d 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -35,7 +35,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>
@@ -436,44 +435,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 baf382c5e776..21661ade885f 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -30,7 +30,6 @@
#include <mach/hardware.h>
#include <asm/irq.h>
-#include <asm/leds.h>
#include <asm/mach-types.h>
#include <asm/pmu.h>
#include <asm/pgtable.h>
@@ -462,10 +461,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 b1d7cafa1a6d..c0ff882c5cb8 100644
--- a/arch/arm/mach-realview/realview_pb1176.c
+++ b/arch/arm/mach-realview/realview_pb1176.c
@@ -32,7 +32,6 @@
#include <mach/hardware.h>
#include <asm/irq.h>
-#include <asm/leds.h>
#include <asm/mach-types.h>
#include <asm/pmu.h>
#include <asm/pgtable.h>
@@ -375,10 +374,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 a98c536e3327..30779ae40c04 100644
--- a/arch/arm/mach-realview/realview_pb11mp.c
+++ b/arch/arm/mach-realview/realview_pb11mp.c
@@ -30,7 +30,6 @@
#include <mach/hardware.h>
#include <asm/irq.h>
-#include <asm/leds.h>
#include <asm/mach-types.h>
#include <asm/pmu.h>
#include <asm/pgtable.h>
@@ -357,10 +356,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 59650174e6ed..081cd72c090e 100644
--- a/arch/arm/mach-realview/realview_pba8.c
+++ b/arch/arm/mach-realview/realview_pba8.c
@@ -29,7 +29,6 @@
#include <linux/io.h>
#include <asm/irq.h>
-#include <asm/leds.h>
#include <asm/mach-types.h>
#include <asm/pmu.h>
#include <asm/pgtable.h>
@@ -299,10 +298,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 3f2f605624e9..1ce62b9f846c 100644
--- a/arch/arm/mach-realview/realview_pbx.c
+++ b/arch/arm/mach-realview/realview_pbx.c
@@ -28,7 +28,6 @@
#include <linux/io.h>
#include <asm/irq.h>
-#include <asm/leds.h>
#include <asm/mach-types.h>
#include <asm/pmu.h>
#include <asm/smp_twd.h>
@@ -394,10 +393,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 2704bcd869cd..c709979ee751 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/Makefile b/arch/arm/mach-tegra/Makefile
index c3d7303b9ac8..f07f99452a98 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -12,9 +12,11 @@ obj-y += powergate.o
obj-y += apbio.o
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
obj-$(CONFIG_CPU_IDLE) += sleep.o
-obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_clocks.o
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks.o
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks_data.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks.o
+obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks_data.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
obj-$(CONFIG_SMP) += reset.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c
index c0999633a9ab..b4e7cc14713c 100644
--- a/arch/arm/mach-tegra/board-dt-tegra20.c
+++ b/arch/arm/mach-tegra/board-dt-tegra20.c
@@ -71,6 +71,7 @@ struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = {
/* name parent rate enabled */
+ { "uarta", "pll_p", 216000000, true },
{ "uartd", "pll_p", 216000000, true },
{ "usbd", "clk_m", 12000000, false },
{ "usb2", "clk_m", 12000000, false },
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
index 58f981c0819c..632133fc985b 100644
--- a/arch/arm/mach-tegra/clock.c
+++ b/arch/arm/mach-tegra/clock.c
@@ -1,6 +1,7 @@
/*
*
* Copyright (C) 2010 Google, Inc.
+ * Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved.
*
* Author:
* Colin Cross <ccross@google.com>
@@ -19,8 +20,6 @@
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
-#include <linux/debugfs.h>
-#include <linux/delay.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
@@ -36,321 +35,67 @@
/*
* Locking:
*
- * Each struct clk has a spinlock.
- *
- * To avoid AB-BA locking problems, locks must always be traversed from child
- * clock to parent clock. For example, when enabling a clock, the clock's lock
- * is taken, and then clk_enable is called on the parent, which take's the
- * parent clock's lock. There is one exceptions to this ordering: When dumping
- * the clock tree through debugfs. In this case, clk_lock_all is called,
- * which attemps to iterate through the entire list of clocks and take every
- * clock lock. If any call to spin_trylock fails, all locked clocks are
- * unlocked, and the process is retried. When all the locks are held,
- * the only clock operation that can be called is clk_get_rate_all_locked.
- *
- * Within a single clock, no clock operation can call another clock operation
- * on itself, except for clk_get_rate_locked and clk_set_rate_locked. Any
- * clock operation can call any other clock operation on any of it's possible
- * parents.
- *
* An additional mutex, clock_list_lock, is used to protect the list of all
* clocks.
*
- * The clock operations must lock internally to protect against
- * read-modify-write on registers that are shared by multiple clocks
*/
static DEFINE_MUTEX(clock_list_lock);
static LIST_HEAD(clocks);
-struct clk *tegra_get_clock_by_name(const char *name)
+void tegra_clk_add(struct clk *clk)
{
- struct clk *c;
- struct clk *ret = NULL;
- mutex_lock(&clock_list_lock);
- list_for_each_entry(c, &clocks, node) {
- if (strcmp(c->name, name) == 0) {
- ret = c;
- break;
- }
- }
- mutex_unlock(&clock_list_lock);
- return ret;
-}
-
-/* Must be called with c->spinlock held */
-static unsigned long clk_predict_rate_from_parent(struct clk *c, struct clk *p)
-{
- u64 rate;
-
- rate = clk_get_rate(p);
-
- if (c->mul != 0 && c->div != 0) {
- rate *= c->mul;
- rate += c->div - 1; /* round up */
- do_div(rate, c->div);
- }
-
- return rate;
-}
-
-/* Must be called with c->spinlock held */
-unsigned long clk_get_rate_locked(struct clk *c)
-{
- unsigned long rate;
-
- if (c->parent)
- rate = clk_predict_rate_from_parent(c, c->parent);
- else
- rate = c->rate;
-
- return rate;
-}
-
-unsigned long clk_get_rate(struct clk *c)
-{
- unsigned long flags;
- unsigned long rate;
-
- spin_lock_irqsave(&c->spinlock, flags);
-
- rate = clk_get_rate_locked(c);
-
- spin_unlock_irqrestore(&c->spinlock, flags);
-
- return rate;
-}
-EXPORT_SYMBOL(clk_get_rate);
-
-int clk_reparent(struct clk *c, struct clk *parent)
-{
- c->parent = parent;
- return 0;
-}
-
-void clk_init(struct clk *c)
-{
- spin_lock_init(&c->spinlock);
-
- if (c->ops && c->ops->init)
- c->ops->init(c);
-
- if (!c->ops || !c->ops->enable) {
- c->refcnt++;
- c->set = true;
- if (c->parent)
- c->state = c->parent->state;
- else
- c->state = ON;
- }
+ struct clk_tegra *c = to_clk_tegra(__clk_get_hw(clk));
mutex_lock(&clock_list_lock);
list_add(&c->node, &clocks);
mutex_unlock(&clock_list_lock);
}
-int clk_enable(struct clk *c)
-{
- int ret = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&c->spinlock, flags);
-
- if (c->refcnt == 0) {
- if (c->parent) {
- ret = clk_enable(c->parent);
- if (ret)
- goto out;
- }
-
- if (c->ops && c->ops->enable) {
- ret = c->ops->enable(c);
- if (ret) {
- if (c->parent)
- clk_disable(c->parent);
- goto out;
- }
- c->state = ON;
- c->set = true;
- }
- }
- c->refcnt++;
-out:
- spin_unlock_irqrestore(&c->spinlock, flags);
- return ret;
-}
-EXPORT_SYMBOL(clk_enable);
-
-void clk_disable(struct clk *c)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&c->spinlock, flags);
-
- if (c->refcnt == 0) {
- WARN(1, "Attempting to disable clock %s with refcnt 0", c->name);
- spin_unlock_irqrestore(&c->spinlock, flags);
- return;
- }
- if (c->refcnt == 1) {
- if (c->ops && c->ops->disable)
- c->ops->disable(c);
-
- if (c->parent)
- clk_disable(c->parent);
-
- c->state = OFF;
- }
- c->refcnt--;
-
- spin_unlock_irqrestore(&c->spinlock, flags);
-}
-EXPORT_SYMBOL(clk_disable);
-
-int clk_set_parent(struct clk *c, struct clk *parent)
-{
- int ret;
- unsigned long flags;
- unsigned long new_rate;
- unsigned long old_rate;
-
- spin_lock_irqsave(&c->spinlock, flags);
-
- if (!c->ops || !c->ops->set_parent) {
- ret = -ENOSYS;
- goto out;
- }
-
- new_rate = clk_predict_rate_from_parent(c, parent);
- old_rate = clk_get_rate_locked(c);
-
- ret = c->ops->set_parent(c, parent);
- if (ret)
- goto out;
-
-out:
- spin_unlock_irqrestore(&c->spinlock, flags);
- return ret;
-}
-EXPORT_SYMBOL(clk_set_parent);
-
-struct clk *clk_get_parent(struct clk *c)
-{
- return c->parent;
-}
-EXPORT_SYMBOL(clk_get_parent);
-
-int clk_set_rate_locked(struct clk *c, unsigned long rate)
-{
- long new_rate;
-
- if (!c->ops || !c->ops->set_rate)
- return -ENOSYS;
-
- if (rate > c->max_rate)
- rate = c->max_rate;
-
- if (c->ops && c->ops->round_rate) {
- new_rate = c->ops->round_rate(c, rate);
-
- if (new_rate < 0)
- return new_rate;
-
- rate = new_rate;
- }
-
- return c->ops->set_rate(c, rate);
-}
-
-int clk_set_rate(struct clk *c, unsigned long rate)
-{
- int ret;
- unsigned long flags;
-
- spin_lock_irqsave(&c->spinlock, flags);
-
- ret = clk_set_rate_locked(c, rate);
-
- spin_unlock_irqrestore(&c->spinlock, flags);
-
- return ret;
-}
-EXPORT_SYMBOL(clk_set_rate);
-
-
-/* Must be called with clocks lock and all indvidual clock locks held */
-unsigned long clk_get_rate_all_locked(struct clk *c)
+struct clk *tegra_get_clock_by_name(const char *name)
{
- u64 rate;
- int mul = 1;
- int div = 1;
- struct clk *p = c;
-
- while (p) {
- c = p;
- if (c->mul != 0 && c->div != 0) {
- mul *= c->mul;
- div *= c->div;
+ struct clk_tegra *c;
+ struct clk *ret = NULL;
+ mutex_lock(&clock_list_lock);
+ list_for_each_entry(c, &clocks, node) {
+ if (strcmp(__clk_get_name(c->hw.clk), name) == 0) {
+ ret = c->hw.clk;
+ break;
}
- p = c->parent;
}
-
- rate = c->rate;
- rate *= mul;
- do_div(rate, div);
-
- return rate;
-}
-
-long clk_round_rate(struct clk *c, unsigned long rate)
-{
- unsigned long flags;
- long ret;
-
- spin_lock_irqsave(&c->spinlock, flags);
-
- if (!c->ops || !c->ops->round_rate) {
- ret = -ENOSYS;
- goto out;
- }
-
- if (rate > c->max_rate)
- rate = c->max_rate;
-
- ret = c->ops->round_rate(c, rate);
-
-out:
- spin_unlock_irqrestore(&c->spinlock, flags);
+ mutex_unlock(&clock_list_lock);
return ret;
}
-EXPORT_SYMBOL(clk_round_rate);
static int tegra_clk_init_one_from_table(struct tegra_clk_init_table *table)
{
struct clk *c;
struct clk *p;
+ struct clk *parent;
int ret = 0;
c = tegra_get_clock_by_name(table->name);
if (!c) {
- pr_warning("Unable to initialize clock %s\n",
+ pr_warn("Unable to initialize clock %s\n",
table->name);
return -ENODEV;
}
+ parent = clk_get_parent(c);
+
if (table->parent) {
p = tegra_get_clock_by_name(table->parent);
if (!p) {
- pr_warning("Unable to find parent %s of clock %s\n",
+ pr_warn("Unable to find parent %s of clock %s\n",
table->parent, table->name);
return -ENODEV;
}
- if (c->parent != p) {
+ if (parent != p) {
ret = clk_set_parent(c, p);
if (ret) {
- pr_warning("Unable to set parent %s of clock %s: %d\n",
+ pr_warn("Unable to set parent %s of clock %s: %d\n",
table->parent, table->name, ret);
return -EINVAL;
}
@@ -360,16 +105,16 @@ static int tegra_clk_init_one_from_table(struct tegra_clk_init_table *table)
if (table->rate && table->rate != clk_get_rate(c)) {
ret = clk_set_rate(c, table->rate);
if (ret) {
- pr_warning("Unable to set clock %s to rate %lu: %d\n",
+ pr_warn("Unable to set clock %s to rate %lu: %d\n",
table->name, table->rate, ret);
return -EINVAL;
}
}
if (table->enabled) {
- ret = clk_enable(c);
+ ret = clk_prepare_enable(c);
if (ret) {
- pr_warning("Unable to enable clock %s: %d\n",
+ pr_warn("Unable to enable clock %s: %d\n",
table->name, ret);
return -EINVAL;
}
@@ -383,19 +128,20 @@ void tegra_clk_init_from_table(struct tegra_clk_init_table *table)
for (; table->name; table++)
tegra_clk_init_one_from_table(table);
}
-EXPORT_SYMBOL(tegra_clk_init_from_table);
void tegra_periph_reset_deassert(struct clk *c)
{
- BUG_ON(!c->ops->reset);
- c->ops->reset(c, false);
+ struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c));
+ BUG_ON(!clk->reset);
+ clk->reset(__clk_get_hw(c), false);
}
EXPORT_SYMBOL(tegra_periph_reset_deassert);
void tegra_periph_reset_assert(struct clk *c)
{
- BUG_ON(!c->ops->reset);
- c->ops->reset(c, true);
+ struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c));
+ BUG_ON(!clk->reset);
+ clk->reset(__clk_get_hw(c), true);
}
EXPORT_SYMBOL(tegra_periph_reset_assert);
@@ -405,268 +151,14 @@ EXPORT_SYMBOL(tegra_periph_reset_assert);
int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
{
int ret = 0;
- unsigned long flags;
+ struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c));
- spin_lock_irqsave(&c->spinlock, flags);
-
- if (!c->ops || !c->ops->clk_cfg_ex) {
+ if (!clk->clk_cfg_ex) {
ret = -ENOSYS;
goto out;
}
- ret = c->ops->clk_cfg_ex(c, p, setting);
+ ret = clk->clk_cfg_ex(__clk_get_hw(c), p, setting);
out:
- spin_unlock_irqrestore(&c->spinlock, flags);
-
return ret;
}
-
-#ifdef CONFIG_DEBUG_FS
-
-static int __clk_lock_all_spinlocks(void)
-{
- struct clk *c;
-
- list_for_each_entry(c, &clocks, node)
- if (!spin_trylock(&c->spinlock))
- goto unlock_spinlocks;
-
- return 0;
-
-unlock_spinlocks:
- list_for_each_entry_continue_reverse(c, &clocks, node)
- spin_unlock(&c->spinlock);
-
- return -EAGAIN;
-}
-
-static void __clk_unlock_all_spinlocks(void)
-{
- struct clk *c;
-
- list_for_each_entry_reverse(c, &clocks, node)
- spin_unlock(&c->spinlock);
-}
-
-/*
- * This function retries until it can take all locks, and may take
- * an arbitrarily long time to complete.
- * Must be called with irqs enabled, returns with irqs disabled
- * Must be called with clock_list_lock held
- */
-static void clk_lock_all(void)
-{
- int ret;
-retry:
- local_irq_disable();
-
- ret = __clk_lock_all_spinlocks();
- if (ret)
- goto failed_spinlocks;
-
- /* All locks taken successfully, return */
- return;
-
-failed_spinlocks:
- local_irq_enable();
- yield();
- goto retry;
-}
-
-/*
- * Unlocks all clocks after a clk_lock_all
- * Must be called with irqs disabled, returns with irqs enabled
- * Must be called with clock_list_lock held
- */
-static void clk_unlock_all(void)
-{
- __clk_unlock_all_spinlocks();
-
- local_irq_enable();
-}
-
-static struct dentry *clk_debugfs_root;
-
-
-static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level)
-{
- struct clk *child;
- const char *state = "uninit";
- char div[8] = {0};
-
- if (c->state == ON)
- state = "on";
- else if (c->state == OFF)
- state = "off";
-
- if (c->mul != 0 && c->div != 0) {
- if (c->mul > c->div) {
- int mul = c->mul / c->div;
- int mul2 = (c->mul * 10 / c->div) % 10;
- int mul3 = (c->mul * 10) % c->div;
- if (mul2 == 0 && mul3 == 0)
- snprintf(div, sizeof(div), "x%d", mul);
- else if (mul3 == 0)
- snprintf(div, sizeof(div), "x%d.%d", mul, mul2);
- else
- snprintf(div, sizeof(div), "x%d.%d..", mul, mul2);
- } else {
- snprintf(div, sizeof(div), "%d%s", c->div / c->mul,
- (c->div % c->mul) ? ".5" : "");
- }
- }
-
- seq_printf(s, "%*s%c%c%-*s %-6s %-3d %-8s %-10lu\n",
- level * 3 + 1, "",
- c->rate > c->max_rate ? '!' : ' ',
- !c->set ? '*' : ' ',
- 30 - level * 3, c->name,
- state, c->refcnt, div, clk_get_rate_all_locked(c));
-
- list_for_each_entry(child, &clocks, node) {
- if (child->parent != c)
- continue;
-
- clock_tree_show_one(s, child, level + 1);
- }
-}
-
-static int clock_tree_show(struct seq_file *s, void *data)
-{
- struct clk *c;
- seq_printf(s, " clock state ref div rate\n");
- seq_printf(s, "--------------------------------------------------------------\n");
-
- mutex_lock(&clock_list_lock);
-
- clk_lock_all();
-
- list_for_each_entry(c, &clocks, node)
- if (c->parent == NULL)
- clock_tree_show_one(s, c, 0);
-
- clk_unlock_all();
-
- mutex_unlock(&clock_list_lock);
- return 0;
-}
-
-static int clock_tree_open(struct inode *inode, struct file *file)
-{
- return single_open(file, clock_tree_show, inode->i_private);
-}
-
-static const struct file_operations clock_tree_fops = {
- .open = clock_tree_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int possible_parents_show(struct seq_file *s, void *data)
-{
- struct clk *c = s->private;
- int i;
-
- for (i = 0; c->inputs[i].input; i++) {
- char *first = (i == 0) ? "" : " ";
- seq_printf(s, "%s%s", first, c->inputs[i].input->name);
- }
- seq_printf(s, "\n");
- return 0;
-}
-
-static int possible_parents_open(struct inode *inode, struct file *file)
-{
- return single_open(file, possible_parents_show, inode->i_private);
-}
-
-static const struct file_operations possible_parents_fops = {
- .open = possible_parents_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int clk_debugfs_register_one(struct clk *c)
-{
- struct dentry *d;
-
- d = debugfs_create_dir(c->name, clk_debugfs_root);
- if (!d)
- return -ENOMEM;
- c->dent = d;
-
- d = debugfs_create_u8("refcnt", S_IRUGO, c->dent, (u8 *)&c->refcnt);
- if (!d)
- goto err_out;
-
- d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate);
- if (!d)
- goto err_out;
-
- d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags);
- if (!d)
- goto err_out;
-
- if (c->inputs) {
- d = debugfs_create_file("possible_parents", S_IRUGO, c->dent,
- c, &possible_parents_fops);
- if (!d)
- goto err_out;
- }
-
- return 0;
-
-err_out:
- debugfs_remove_recursive(c->dent);
- return -ENOMEM;
-}
-
-static int clk_debugfs_register(struct clk *c)
-{
- int err;
- struct clk *pa = c->parent;
-
- if (pa && !pa->dent) {
- err = clk_debugfs_register(pa);
- if (err)
- return err;
- }
-
- if (!c->dent) {
- err = clk_debugfs_register_one(c);
- if (err)
- return err;
- }
- return 0;
-}
-
-int __init tegra_clk_debugfs_init(void)
-{
- struct clk *c;
- struct dentry *d;
- int err = -ENOMEM;
-
- d = debugfs_create_dir("clock", NULL);
- if (!d)
- return -ENOMEM;
- clk_debugfs_root = d;
-
- d = debugfs_create_file("clock_tree", S_IRUGO, clk_debugfs_root, NULL,
- &clock_tree_fops);
- if (!d)
- goto err_out;
-
- list_for_each_entry(c, &clocks, node) {
- err = clk_debugfs_register(c);
- if (err)
- goto err_out;
- }
- return 0;
-err_out:
- debugfs_remove_recursive(clk_debugfs_root);
- return err;
-}
-
-#endif
diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
index bc300657deba..2aa37f5c44c0 100644
--- a/arch/arm/mach-tegra/clock.h
+++ b/arch/arm/mach-tegra/clock.h
@@ -2,6 +2,7 @@
* arch/arm/mach-tegra/include/mach/clock.h
*
* Copyright (C) 2010 Google, Inc.
+ * Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved.
*
* Author:
* Colin Cross <ccross@google.com>
@@ -20,9 +21,9 @@
#ifndef __MACH_TEGRA_CLOCK_H
#define __MACH_TEGRA_CLOCK_H
+#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/list.h>
-#include <linux/spinlock.h>
#include <mach/clk.h>
@@ -52,7 +53,8 @@
#define ENABLE_ON_INIT (1 << 28)
#define PERIPH_ON_APB (1 << 29)
-struct clk;
+struct clk_tegra;
+#define to_clk_tegra(_hw) container_of(_hw, struct clk_tegra, hw)
struct clk_mux_sel {
struct clk *input;
@@ -68,47 +70,29 @@ struct clk_pll_freq_table {
u8 cpcon;
};
-struct clk_ops {
- void (*init)(struct clk *);
- int (*enable)(struct clk *);
- void (*disable)(struct clk *);
- int (*set_parent)(struct clk *, struct clk *);
- int (*set_rate)(struct clk *, unsigned long);
- long (*round_rate)(struct clk *, unsigned long);
- void (*reset)(struct clk *, bool);
- int (*clk_cfg_ex)(struct clk *,
- enum tegra_clk_ex_param, u32);
-};
-
enum clk_state {
UNINITIALIZED = 0,
ON,
OFF,
};
-struct clk {
+struct clk_tegra {
/* node for master clocks list */
- struct list_head node; /* node for list of all clocks */
+ struct list_head node; /* node for list of all clocks */
struct clk_lookup lookup;
+ struct clk_hw hw;
-#ifdef CONFIG_DEBUG_FS
- struct dentry *dent;
-#endif
bool set;
- struct clk_ops *ops;
- unsigned long rate;
+ unsigned long fixed_rate;
unsigned long max_rate;
unsigned long min_rate;
u32 flags;
const char *name;
- u32 refcnt;
enum clk_state state;
- struct clk *parent;
u32 div;
u32 mul;
- const struct clk_mux_sel *inputs;
u32 reg;
u32 reg_shift;
@@ -144,7 +128,8 @@ struct clk {
} shared_bus_user;
} u;
- spinlock_t spinlock;
+ void (*reset)(struct clk_hw *, bool);
+ int (*clk_cfg_ex)(struct clk_hw *, enum tegra_clk_ex_param, u32);
};
struct clk_duplicate {
@@ -159,13 +144,10 @@ struct tegra_clk_init_table {
bool enabled;
};
+void tegra_clk_add(struct clk *c);
void tegra2_init_clocks(void);
void tegra30_init_clocks(void);
-void clk_init(struct clk *clk);
struct clk *tegra_get_clock_by_name(const char *name);
-int clk_reparent(struct clk *c, struct clk *parent);
void tegra_clk_init_from_table(struct tegra_clk_init_table *table);
-unsigned long clk_get_rate_locked(struct clk *c);
-int clk_set_rate_locked(struct clk *c, unsigned long rate);
#endif
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c
index 96fef6bcc651..f3654f830991 100644
--- a/arch/arm/mach-tegra/common.c
+++ b/arch/arm/mach-tegra/common.c
@@ -152,6 +152,5 @@ void __init tegra30_init_early(void)
void __init tegra_init_late(void)
{
- tegra_clk_debugfs_init();
tegra_powergate_debugfs_init();
}
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c
index ceb52db1e2f1..627bf0f4262e 100644
--- a/arch/arm/mach-tegra/cpu-tegra.c
+++ b/arch/arm/mach-tegra/cpu-tegra.c
@@ -49,6 +49,8 @@ static struct cpufreq_frequency_table freq_table[] = {
#define NUM_CPUS 2
static struct clk *cpu_clk;
+static struct clk *pll_x_clk;
+static struct clk *pll_p_clk;
static struct clk *emc_clk;
static unsigned long target_cpu_speed[NUM_CPUS];
@@ -71,6 +73,42 @@ static unsigned int tegra_getspeed(unsigned int cpu)
return rate;
}
+static int tegra_cpu_clk_set_rate(unsigned long rate)
+{
+ int ret;
+
+ /*
+ * Take an extra reference to the main pll so it doesn't turn
+ * off when we move the cpu off of it
+ */
+ clk_prepare_enable(pll_x_clk);
+
+ ret = clk_set_parent(cpu_clk, pll_p_clk);
+ if (ret) {
+ pr_err("Failed to switch cpu to clock pll_p\n");
+ goto out;
+ }
+
+ if (rate == clk_get_rate(pll_p_clk))
+ goto out;
+
+ ret = clk_set_rate(pll_x_clk, rate);
+ if (ret) {
+ pr_err("Failed to change pll_x to %lu\n", rate);
+ goto out;
+ }
+
+ ret = clk_set_parent(cpu_clk, pll_x_clk);
+ if (ret) {
+ pr_err("Failed to switch cpu to clock pll_x\n");
+ goto out;
+ }
+
+out:
+ clk_disable_unprepare(pll_x_clk);
+ return ret;
+}
+
static int tegra_update_cpu_speed(unsigned long rate)
{
int ret = 0;
@@ -101,7 +139,7 @@ static int tegra_update_cpu_speed(unsigned long rate)
freqs.old, freqs.new);
#endif
- ret = clk_set_rate(cpu_clk, freqs.new * 1000);
+ ret = tegra_cpu_clk_set_rate(freqs.new * 1000);
if (ret) {
pr_err("cpu-tegra: Failed to set cpu frequency to %d kHz\n",
freqs.new);
@@ -183,6 +221,14 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)
if (IS_ERR(cpu_clk))
return PTR_ERR(cpu_clk);
+ pll_x_clk = clk_get_sys(NULL, "pll_x");
+ if (IS_ERR(pll_x_clk))
+ return PTR_ERR(pll_x_clk);
+
+ pll_p_clk = clk_get_sys(NULL, "pll_p");
+ if (IS_ERR(pll_p_clk))
+ return PTR_ERR(pll_p_clk);
+
emc_clk = clk_get_sys("cpu", "emc");
if (IS_ERR(emc_clk)) {
clk_put(cpu_clk);
diff --git a/arch/arm/mach-tegra/include/mach/clk.h b/arch/arm/mach-tegra/include/mach/clk.h
index d97e403303a0..95f3a547c770 100644
--- a/arch/arm/mach-tegra/include/mach/clk.h
+++ b/arch/arm/mach-tegra/include/mach/clk.h
@@ -34,7 +34,10 @@ enum tegra_clk_ex_param {
void tegra_periph_reset_deassert(struct clk *c);
void tegra_periph_reset_assert(struct clk *c);
+#ifndef CONFIG_COMMON_CLK
unsigned long clk_get_rate_all_locked(struct clk *c);
+#endif
+
void tegra2_sdmmc_tap_delay(struct clk *c, int delay);
int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting);
diff --git a/arch/arm/mach-tegra/tegra20_clocks.c b/arch/arm/mach-tegra/tegra20_clocks.c
new file mode 100644
index 000000000000..840ab262272a
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20_clocks.c
@@ -0,0 +1,1555 @@
+/*
+ * arch/arm/mach-tegra/tegra20_clocks.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Copyright (c) 2010-2012 NVIDIA CORPORATION. All rights reserved.
+ *
+ * Author:
+ * Colin Cross <ccross@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clkdev.h>
+#include <linux/clk.h>
+
+#include <mach/iomap.h>
+#include <mach/suspend.h>
+
+#include "clock.h"
+#include "fuse.h"
+#include "tegra2_emc.h"
+
+#define RST_DEVICES 0x004
+#define RST_DEVICES_SET 0x300
+#define RST_DEVICES_CLR 0x304
+#define RST_DEVICES_NUM 3
+
+#define CLK_OUT_ENB 0x010
+#define CLK_OUT_ENB_SET 0x320
+#define CLK_OUT_ENB_CLR 0x324
+#define CLK_OUT_ENB_NUM 3
+
+#define CLK_MASK_ARM 0x44
+#define MISC_CLK_ENB 0x48
+
+#define OSC_CTRL 0x50
+#define OSC_CTRL_OSC_FREQ_MASK (3<<30)
+#define OSC_CTRL_OSC_FREQ_13MHZ (0<<30)
+#define OSC_CTRL_OSC_FREQ_19_2MHZ (1<<30)
+#define OSC_CTRL_OSC_FREQ_12MHZ (2<<30)
+#define OSC_CTRL_OSC_FREQ_26MHZ (3<<30)
+#define OSC_CTRL_MASK (0x3f2 | OSC_CTRL_OSC_FREQ_MASK)
+
+#define OSC_FREQ_DET 0x58
+#define OSC_FREQ_DET_TRIG (1<<31)
+
+#define OSC_FREQ_DET_STATUS 0x5C
+#define OSC_FREQ_DET_BUSY (1<<31)
+#define OSC_FREQ_DET_CNT_MASK 0xFFFF
+
+#define PERIPH_CLK_SOURCE_I2S1 0x100
+#define PERIPH_CLK_SOURCE_EMC 0x19c
+#define PERIPH_CLK_SOURCE_OSC 0x1fc
+#define PERIPH_CLK_SOURCE_NUM \
+ ((PERIPH_CLK_SOURCE_OSC - PERIPH_CLK_SOURCE_I2S1) / 4)
+
+#define PERIPH_CLK_SOURCE_MASK (3<<30)
+#define PERIPH_CLK_SOURCE_SHIFT 30
+#define PERIPH_CLK_SOURCE_PWM_MASK (7<<28)
+#define PERIPH_CLK_SOURCE_PWM_SHIFT 28
+#define PERIPH_CLK_SOURCE_ENABLE (1<<28)
+#define PERIPH_CLK_SOURCE_DIVU71_MASK 0xFF
+#define PERIPH_CLK_SOURCE_DIVU16_MASK 0xFFFF
+#define PERIPH_CLK_SOURCE_DIV_SHIFT 0
+
+#define SDMMC_CLK_INT_FB_SEL (1 << 23)
+#define SDMMC_CLK_INT_FB_DLY_SHIFT 16
+#define SDMMC_CLK_INT_FB_DLY_MASK (0xF << SDMMC_CLK_INT_FB_DLY_SHIFT)
+
+#define PLL_BASE 0x0
+#define PLL_BASE_BYPASS (1<<31)
+#define PLL_BASE_ENABLE (1<<30)
+#define PLL_BASE_REF_ENABLE (1<<29)
+#define PLL_BASE_OVERRIDE (1<<28)
+#define PLL_BASE_DIVP_MASK (0x7<<20)
+#define PLL_BASE_DIVP_SHIFT 20
+#define PLL_BASE_DIVN_MASK (0x3FF<<8)
+#define PLL_BASE_DIVN_SHIFT 8
+#define PLL_BASE_DIVM_MASK (0x1F)
+#define PLL_BASE_DIVM_SHIFT 0
+
+#define PLL_OUT_RATIO_MASK (0xFF<<8)
+#define PLL_OUT_RATIO_SHIFT 8
+#define PLL_OUT_OVERRIDE (1<<2)
+#define PLL_OUT_CLKEN (1<<1)
+#define PLL_OUT_RESET_DISABLE (1<<0)
+
+#define PLL_MISC(c) (((c)->flags & PLL_ALT_MISC_REG) ? 0x4 : 0xc)
+
+#define PLL_MISC_DCCON_SHIFT 20
+#define PLL_MISC_CPCON_SHIFT 8
+#define PLL_MISC_CPCON_MASK (0xF<<PLL_MISC_CPCON_SHIFT)
+#define PLL_MISC_LFCON_SHIFT 4
+#define PLL_MISC_LFCON_MASK (0xF<<PLL_MISC_LFCON_SHIFT)
+#define PLL_MISC_VCOCON_SHIFT 0
+#define PLL_MISC_VCOCON_MASK (0xF<<PLL_MISC_VCOCON_SHIFT)
+
+#define PLLU_BASE_POST_DIV (1<<20)
+
+#define PLLD_MISC_CLKENABLE (1<<30)
+#define PLLD_MISC_DIV_RST (1<<23)
+#define PLLD_MISC_DCCON_SHIFT 12
+
+#define PLLE_MISC_READY (1 << 15)
+
+#define PERIPH_CLK_TO_ENB_REG(c) ((c->u.periph.clk_num / 32) * 4)
+#define PERIPH_CLK_TO_ENB_SET_REG(c) ((c->u.periph.clk_num / 32) * 8)
+#define PERIPH_CLK_TO_ENB_BIT(c) (1 << (c->u.periph.clk_num % 32))
+
+#define SUPER_CLK_MUX 0x00
+#define SUPER_STATE_SHIFT 28
+#define SUPER_STATE_MASK (0xF << SUPER_STATE_SHIFT)
+#define SUPER_STATE_STANDBY (0x0 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_IDLE (0x1 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_RUN (0x2 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_IRQ (0x3 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_FIQ (0x4 << SUPER_STATE_SHIFT)
+#define SUPER_SOURCE_MASK 0xF
+#define SUPER_FIQ_SOURCE_SHIFT 12
+#define SUPER_IRQ_SOURCE_SHIFT 8
+#define SUPER_RUN_SOURCE_SHIFT 4
+#define SUPER_IDLE_SOURCE_SHIFT 0
+
+#define SUPER_CLK_DIVIDER 0x04
+
+#define BUS_CLK_DISABLE (1<<3)
+#define BUS_CLK_DIV_MASK 0x3
+
+#define PMC_CTRL 0x0
+ #define PMC_CTRL_BLINK_ENB (1 << 7)
+
+#define PMC_DPD_PADS_ORIDE 0x1c
+ #define PMC_DPD_PADS_ORIDE_BLINK_ENB (1 << 20)
+
+#define PMC_BLINK_TIMER_DATA_ON_SHIFT 0
+#define PMC_BLINK_TIMER_DATA_ON_MASK 0x7fff
+#define PMC_BLINK_TIMER_ENB (1 << 15)
+#define PMC_BLINK_TIMER_DATA_OFF_SHIFT 16
+#define PMC_BLINK_TIMER_DATA_OFF_MASK 0xffff
+
+static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
+static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+
+/*
+ * Some clocks share a register with other clocks. Any clock op that
+ * non-atomically modifies a register used by another clock must lock
+ * clock_register_lock first.
+ */
+static DEFINE_SPINLOCK(clock_register_lock);
+
+/*
+ * Some peripheral clocks share an enable bit, so refcount the enable bits
+ * in registers CLK_ENABLE_L, CLK_ENABLE_H, and CLK_ENABLE_U
+ */
+static int tegra_periph_clk_enable_refcount[3 * 32];
+
+#define clk_writel(value, reg) \
+ __raw_writel(value, reg_clk_base + (reg))
+#define clk_readl(reg) \
+ __raw_readl(reg_clk_base + (reg))
+#define pmc_writel(value, reg) \
+ __raw_writel(value, reg_pmc_base + (reg))
+#define pmc_readl(reg) \
+ __raw_readl(reg_pmc_base + (reg))
+
+static unsigned long clk_measure_input_freq(void)
+{
+ u32 clock_autodetect;
+ clk_writel(OSC_FREQ_DET_TRIG | 1, OSC_FREQ_DET);
+ do {} while (clk_readl(OSC_FREQ_DET_STATUS) & OSC_FREQ_DET_BUSY);
+ clock_autodetect = clk_readl(OSC_FREQ_DET_STATUS);
+ if (clock_autodetect >= 732 - 3 && clock_autodetect <= 732 + 3) {
+ return 12000000;
+ } else if (clock_autodetect >= 794 - 3 && clock_autodetect <= 794 + 3) {
+ return 13000000;
+ } else if (clock_autodetect >= 1172 - 3 && clock_autodetect <= 1172 + 3) {
+ return 19200000;
+ } else if (clock_autodetect >= 1587 - 3 && clock_autodetect <= 1587 + 3) {
+ return 26000000;
+ } else {
+ pr_err("%s: Unexpected clock autodetect value %d",
+ __func__, clock_autodetect);
+ BUG();
+ return 0;
+ }
+}
+
+static int clk_div71_get_divider(unsigned long parent_rate, unsigned long rate)
+{
+ s64 divider_u71 = parent_rate * 2;
+ divider_u71 += rate - 1;
+ do_div(divider_u71, rate);
+
+ if (divider_u71 - 2 < 0)
+ return 0;
+
+ if (divider_u71 - 2 > 255)
+ return -EINVAL;
+
+ return divider_u71 - 2;
+}
+
+static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate)
+{
+ s64 divider_u16;
+
+ divider_u16 = parent_rate;
+ divider_u16 += rate - 1;
+ do_div(divider_u16, rate);
+
+ if (divider_u16 - 1 < 0)
+ return 0;
+
+ if (divider_u16 - 1 > 0xFFFF)
+ return -EINVAL;
+
+ return divider_u16 - 1;
+}
+
+static unsigned long tegra_clk_fixed_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return to_clk_tegra(hw)->fixed_rate;
+}
+
+struct clk_ops tegra_clk_32k_ops = {
+ .recalc_rate = tegra_clk_fixed_recalc_rate,
+};
+
+/* clk_m functions */
+static unsigned long tegra20_clk_m_recalc_rate(struct clk_hw *hw,
+ unsigned long prate)
+{
+ if (!to_clk_tegra(hw)->fixed_rate)
+ to_clk_tegra(hw)->fixed_rate = clk_measure_input_freq();
+ return to_clk_tegra(hw)->fixed_rate;
+}
+
+static void tegra20_clk_m_init(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u32 osc_ctrl = clk_readl(OSC_CTRL);
+ u32 auto_clock_control = osc_ctrl & ~OSC_CTRL_OSC_FREQ_MASK;
+
+ switch (c->fixed_rate) {
+ case 12000000:
+ auto_clock_control |= OSC_CTRL_OSC_FREQ_12MHZ;
+ break;
+ case 13000000:
+ auto_clock_control |= OSC_CTRL_OSC_FREQ_13MHZ;
+ break;
+ case 19200000:
+ auto_clock_control |= OSC_CTRL_OSC_FREQ_19_2MHZ;
+ break;
+ case 26000000:
+ auto_clock_control |= OSC_CTRL_OSC_FREQ_26MHZ;
+ break;
+ default:
+ BUG();
+ }
+ clk_writel(auto_clock_control, OSC_CTRL);
+}
+
+struct clk_ops tegra_clk_m_ops = {
+ .init = tegra20_clk_m_init,
+ .recalc_rate = tegra20_clk_m_recalc_rate,
+};
+
+/* super clock functions */
+/* "super clocks" on tegra have two-stage muxes and a clock skipping
+ * super divider. We will ignore the clock skipping divider, since we
+ * can't lower the voltage when using the clock skip, but we can if we
+ * lower the PLL frequency.
+ */
+static int tegra20_super_clk_is_enabled(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u32 val;
+
+ val = clk_readl(c->reg + SUPER_CLK_MUX);
+ BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
+ ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
+ c->state = ON;
+ return c->state;
+}
+
+static int tegra20_super_clk_enable(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ clk_writel(0, c->reg + SUPER_CLK_DIVIDER);
+ return 0;
+}
+
+static void tegra20_super_clk_disable(struct clk_hw *hw)
+{
+ pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
+
+ /* oops - don't disable the CPU clock! */
+ BUG();
+}
+
+static u8 tegra20_super_clk_get_parent(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ int val = clk_readl(c->reg + SUPER_CLK_MUX);
+ int source;
+ int shift;
+
+ BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
+ ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
+ shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
+ SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
+ source = (val >> shift) & SUPER_SOURCE_MASK;
+ return source;
+}
+
+static int tegra20_super_clk_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u32 val = clk_readl(c->reg + SUPER_CLK_MUX);
+ int shift;
+
+ BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
+ ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
+ shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
+ SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
+ val &= ~(SUPER_SOURCE_MASK << shift);
+ val |= index << shift;
+
+ clk_writel(val, c->reg);
+
+ return 0;
+}
+
+/* FIX ME: Need to switch parents to change the source PLL rate */
+static unsigned long tegra20_super_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long prate)
+{
+ return prate;
+}
+
+static long tegra20_super_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ return *prate;
+}
+
+static int tegra20_super_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ return 0;
+}
+
+struct clk_ops tegra_super_ops = {
+ .is_enabled = tegra20_super_clk_is_enabled,
+ .enable = tegra20_super_clk_enable,
+ .disable = tegra20_super_clk_disable,
+ .set_parent = tegra20_super_clk_set_parent,
+ .get_parent = tegra20_super_clk_get_parent,
+ .set_rate = tegra20_super_clk_set_rate,
+ .round_rate = tegra20_super_clk_round_rate,
+ .recalc_rate = tegra20_super_clk_recalc_rate,
+};
+
+static unsigned long tegra20_twd_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u64 rate = parent_rate;
+
+ if (c->mul != 0 && c->div != 0) {
+ rate *= c->mul;
+ rate += c->div - 1; /* round up */
+ do_div(rate, c->div);
+ }
+
+ return rate;
+}
+
+struct clk_ops tegra_twd_ops = {
+ .recalc_rate = tegra20_twd_clk_recalc_rate,
+};
+
+static u8 tegra20_cop_clk_get_parent(struct clk_hw *hw)
+{
+ return 0;
+}
+
+struct clk_ops tegra_cop_ops = {
+ .get_parent = tegra20_cop_clk_get_parent,
+};
+
+/* virtual cop clock functions. Used to acquire the fake 'cop' clock to
+ * reset the COP block (i.e. AVP) */
+void tegra2_cop_clk_reset(struct clk_hw *hw, bool assert)
+{
+ unsigned long reg = assert ? RST_DEVICES_SET : RST_DEVICES_CLR;
+
+ pr_debug("%s %s\n", __func__, assert ? "assert" : "deassert");
+ clk_writel(1 << 1, reg);
+}
+
+/* bus clock functions */
+static int tegra20_bus_clk_is_enabled(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u32 val = clk_readl(c->reg);
+
+ c->state = ((val >> c->reg_shift) & BUS_CLK_DISABLE) ? OFF : ON;
+ return c->state;
+}
+
+static int tegra20_bus_clk_enable(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&clock_register_lock, flags);
+
+ val = clk_readl(c->reg);
+ val &= ~(BUS_CLK_DISABLE << c->reg_shift);
+ clk_writel(val, c->reg);
+
+ spin_unlock_irqrestore(&clock_register_lock, flags);
+
+ return 0;
+}
+
+static void tegra20_bus_clk_disable(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&clock_register_lock, flags);
+
+ val = clk_readl(c->reg);
+ val |= BUS_CLK_DISABLE << c->reg_shift;
+ clk_writel(val, c->reg);
+
+ spin_unlock_irqrestore(&clock_register_lock, flags);
+}
+
+static unsigned long tegra20_bus_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long prate)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u32 val = clk_readl(c->reg);
+ u64 rate = prate;
+
+ c->div = ((val >> c->reg_shift) & BUS_CLK_DIV_MASK) + 1;
+ c->mul = 1;
+
+ if (c->mul != 0 && c->div != 0) {
+ rate *= c->mul;
+ rate += c->div - 1; /* round up */
+ do_div(rate, c->div);
+ }
+ return rate;
+}
+
+static int tegra20_bus_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ int ret = -EINVAL;
+ unsigned long flags;
+ u32 val;
+ int i;
+
+ spin_lock_irqsave(&clock_register_lock, flags);
+
+ val = clk_readl(c->reg);
+ for (i = 1; i <= 4; i++) {
+ if (rate == parent_rate / i) {
+ val &= ~(BUS_CLK_DIV_MASK << c->reg_shift);
+ val |= (i - 1) << c->reg_shift;
+ clk_writel(val, c->reg);
+ c->div = i;
+ c->mul = 1;
+ ret = 0;
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore(&clock_register_lock, flags);
+
+ return ret;
+}
+
+static long tegra20_bus_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ unsigned long parent_rate = *prate;
+ s64 divider;
+
+ if (rate >= parent_rate)
+ return rate;
+
+ divider = parent_rate;
+ divider += rate - 1;
+ do_div(divider, rate);
+
+ if (divider < 0)
+ return divider;
+
+ if (divider > 4)
+ divider = 4;
+ do_div(parent_rate, divider);
+
+ return parent_rate;
+}
+
+struct clk_ops tegra_bus_ops = {
+ .is_enabled = tegra20_bus_clk_is_enabled,
+ .enable = tegra20_bus_clk_enable,
+ .disable = tegra20_bus_clk_disable,
+ .set_rate = tegra20_bus_clk_set_rate,
+ .round_rate = tegra20_bus_clk_round_rate,
+ .recalc_rate = tegra20_bus_clk_recalc_rate,
+};
+
+/* Blink output functions */
+static int tegra20_blink_clk_is_enabled(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u32 val;
+
+ val = pmc_readl(PMC_CTRL);
+ c->state = (val & PMC_CTRL_BLINK_ENB) ? ON : OFF;
+ return c->state;
+}
+
+static unsigned long tegra20_blink_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long prate)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u64 rate = prate;
+ u32 val;
+
+ c->mul = 1;
+ val = pmc_readl(c->reg);
+
+ if (val & PMC_BLINK_TIMER_ENB) {
+ unsigned int on_off;
+
+ on_off = (val >> PMC_BLINK_TIMER_DATA_ON_SHIFT) &
+ PMC_BLINK_TIMER_DATA_ON_MASK;
+ val >>= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
+ val &= PMC_BLINK_TIMER_DATA_OFF_MASK;
+ on_off += val;
+ /* each tick in the blink timer is 4 32KHz clocks */
+ c->div = on_off * 4;
+ } else {
+ c->div = 1;
+ }
+
+ if (c->mul != 0 && c->div != 0) {
+ rate *= c->mul;
+ rate += c->div - 1; /* round up */
+ do_div(rate, c->div);
+ }
+ return rate;
+}
+
+static int tegra20_blink_clk_enable(struct clk_hw *hw)
+{
+ u32 val;
+
+ val = pmc_readl(PMC_DPD_PADS_ORIDE);
+ pmc_writel(val | PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
+
+ val = pmc_readl(PMC_CTRL);
+ pmc_writel(val | PMC_CTRL_BLINK_ENB, PMC_CTRL);
+
+ return 0;
+}
+
+static void tegra20_blink_clk_disable(struct clk_hw *hw)
+{
+ u32 val;
+
+ val = pmc_readl(PMC_CTRL);
+ pmc_writel(val & ~PMC_CTRL_BLINK_ENB, PMC_CTRL);
+
+ val = pmc_readl(PMC_DPD_PADS_ORIDE);
+ pmc_writel(val & ~PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
+}
+
+static int tegra20_blink_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+
+ if (rate >= parent_rate) {
+ c->div = 1;
+ pmc_writel(0, c->reg);
+ } else {
+ unsigned int on_off;
+ u32 val;
+
+ on_off = DIV_ROUND_UP(parent_rate / 8, rate);
+ c->div = on_off * 8;
+
+ val = (on_off & PMC_BLINK_TIMER_DATA_ON_MASK) <<
+ PMC_BLINK_TIMER_DATA_ON_SHIFT;
+ on_off &= PMC_BLINK_TIMER_DATA_OFF_MASK;
+ on_off <<= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
+ val |= on_off;
+ val |= PMC_BLINK_TIMER_ENB;
+ pmc_writel(val, c->reg);
+ }
+
+ return 0;
+}
+
+static long tegra20_blink_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ int div;
+ int mul;
+ long round_rate = *prate;
+
+ mul = 1;
+
+ if (rate >= *prate) {
+ div = 1;
+ } else {
+ div = DIV_ROUND_UP(*prate / 8, rate);
+ div *= 8;
+ }
+
+ round_rate *= mul;
+ round_rate += div - 1;
+ do_div(round_rate, div);
+
+ return round_rate;
+}
+
+struct clk_ops tegra_blink_clk_ops = {
+ .is_enabled = tegra20_blink_clk_is_enabled,
+ .enable = tegra20_blink_clk_enable,
+ .disable = tegra20_blink_clk_disable,
+ .set_rate = tegra20_blink_clk_set_rate,
+ .round_rate = tegra20_blink_clk_round_rate,
+ .recalc_rate = tegra20_blink_clk_recalc_rate,
+};
+
+/* PLL Functions */
+static int tegra20_pll_clk_wait_for_lock(struct clk_tegra *c)
+{
+ udelay(c->u.pll.lock_delay);
+ return 0;
+}
+
+static int tegra20_pll_clk_is_enabled(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u32 val = clk_readl(c->reg + PLL_BASE);
+
+ c->state = (val & PLL_BASE_ENABLE) ? ON : OFF;
+ return c->state;
+}
+
+static unsigned long tegra20_pll_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long prate)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u32 val = clk_readl(c->reg + PLL_BASE);
+ u64 rate = prate;
+
+ if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) {
+ const struct clk_pll_freq_table *sel;
+ for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
+ if (sel->input_rate == prate &&
+ sel->output_rate == c->u.pll.fixed_rate) {
+ c->mul = sel->n;
+ c->div = sel->m * sel->p;
+ break;
+ }
+ }
+ pr_err("Clock %s has unknown fixed frequency\n",
+ __clk_get_name(hw->clk));
+ BUG();
+ } else if (val & PLL_BASE_BYPASS) {
+ c->mul = 1;
+ c->div = 1;
+ } else {
+ c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT;
+ c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT;
+ if (c->flags & PLLU)
+ c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2;
+ else
+ c->div *= (val & PLL_BASE_DIVP_MASK) ? 2 : 1;
+ }
+
+ if (c->mul != 0 && c->div != 0) {
+ rate *= c->mul;
+ rate += c->div - 1; /* round up */
+ do_div(rate, c->div);
+ }
+ return rate;
+}
+
+static int tegra20_pll_clk_enable(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u32 val;
+ pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
+
+ val = clk_readl(c->reg + PLL_BASE);
+ val &= ~PLL_BASE_BYPASS;
+ val |= PLL_BASE_ENABLE;
+ clk_writel(val, c->reg + PLL_BASE);
+
+ tegra20_pll_clk_wait_for_lock(c);
+
+ return 0;
+}
+
+static void tegra20_pll_clk_disable(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u32 val;
+ pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
+
+ val = clk_readl(c->reg);
+ val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
+ clk_writel(val, c->reg);
+}
+
+static int tegra20_pll_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ unsigned long input_rate = parent_rate;
+ const struct clk_pll_freq_table *sel;
+ u32 val;
+
+ pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate);
+
+ if (c->flags & PLL_FIXED) {
+ int ret = 0;
+ if (rate != c->u.pll.fixed_rate) {
+ pr_err("%s: Can not change %s fixed rate %lu to %lu\n",
+ __func__, __clk_get_name(hw->clk),
+ c->u.pll.fixed_rate, rate);
+ ret = -EINVAL;
+ }
+ return ret;
+ }
+
+ for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
+ if (sel->input_rate == input_rate && sel->output_rate == rate) {
+ c->mul = sel->n;
+ c->div = sel->m * sel->p;
+
+ val = clk_readl(c->reg + PLL_BASE);
+ if (c->flags & PLL_FIXED)
+ val |= PLL_BASE_OVERRIDE;
+ val &= ~(PLL_BASE_DIVP_MASK | PLL_BASE_DIVN_MASK |
+ PLL_BASE_DIVM_MASK);
+ val |= (sel->m << PLL_BASE_DIVM_SHIFT) |
+ (sel->n << PLL_BASE_DIVN_SHIFT);
+ BUG_ON(sel->p < 1 || sel->p > 2);
+ if (c->flags & PLLU) {
+ if (sel->p == 1)
+ val |= PLLU_BASE_POST_DIV;
+ } else {
+ if (sel->p == 2)
+ val |= 1 << PLL_BASE_DIVP_SHIFT;
+ }
+ clk_writel(val, c->reg + PLL_BASE);
+
+ if (c->flags & PLL_HAS_CPCON) {
+ val = clk_readl(c->reg + PLL_MISC(c));
+ val &= ~PLL_MISC_CPCON_MASK;
+ val |= sel->cpcon << PLL_MISC_CPCON_SHIFT;
+ clk_writel(val, c->reg + PLL_MISC(c));
+ }
+
+ if (c->state == ON)
+ tegra20_pll_clk_enable(hw);
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+static long tegra20_pll_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ const struct clk_pll_freq_table *sel;
+ unsigned long input_rate = *prate;
+ u64 output_rate = *prate;
+ int mul;
+ int div;
+
+ if (c->flags & PLL_FIXED)
+ return c->u.pll.fixed_rate;
+
+ for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++)
+ if (sel->input_rate == input_rate && sel->output_rate == rate) {
+ mul = sel->n;
+ div = sel->m * sel->p;
+ break;
+ }
+
+ if (sel->input_rate == 0)
+ return -EINVAL;
+
+ output_rate *= mul;
+ output_rate += div - 1; /* round up */
+ do_div(output_rate, div);
+
+ return output_rate;
+}
+
+struct clk_ops tegra_pll_ops = {
+ .is_enabled = tegra20_pll_clk_is_enabled,
+ .enable = tegra20_pll_clk_enable,
+ .disable = tegra20_pll_clk_disable,
+ .set_rate = tegra20_pll_clk_set_rate,
+ .recalc_rate = tegra20_pll_clk_recalc_rate,
+ .round_rate = tegra20_pll_clk_round_rate,
+};
+
+static void tegra20_pllx_clk_init(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+
+ if (tegra_sku_id == 7)
+ c->max_rate = 750000000;
+}
+
+struct clk_ops tegra_pllx_ops = {
+ .init = tegra20_pllx_clk_init,
+ .is_enabled = tegra20_pll_clk_is_enabled,
+ .enable = tegra20_pll_clk_enable,
+ .disable = tegra20_pll_clk_disable,
+ .set_rate = tegra20_pll_clk_set_rate,
+ .recalc_rate = tegra20_pll_clk_recalc_rate,
+ .round_rate = tegra20_pll_clk_round_rate,
+};
+
+static int tegra20_plle_clk_enable(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u32 val;
+
+ pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
+
+ mdelay(1);
+
+ val = clk_readl(c->reg + PLL_BASE);
+ if (!(val & PLLE_MISC_READY))
+ return -EBUSY;
+
+ val = clk_readl(c->reg + PLL_BASE);
+ val |= PLL_BASE_ENABLE | PLL_BASE_BYPASS;
+ clk_writel(val, c->reg + PLL_BASE);
+
+ return 0;
+}
+
+struct clk_ops tegra_plle_ops = {
+ .is_enabled = tegra20_pll_clk_is_enabled,
+ .enable = tegra20_plle_clk_enable,
+ .set_rate = tegra20_pll_clk_set_rate,
+ .recalc_rate = tegra20_pll_clk_recalc_rate,
+ .round_rate = tegra20_pll_clk_round_rate,
+};
+
+/* Clock divider ops */
+static int tegra20_pll_div_clk_is_enabled(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u32 val = clk_readl(c->reg);
+
+ val >>= c->reg_shift;
+ c->state = (val & PLL_OUT_CLKEN) ? ON : OFF;
+ if (!(val & PLL_OUT_RESET_DISABLE))
+ c->state = OFF;
+ return c->state;
+}
+
+static unsigned long tegra20_pll_div_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long prate)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u64 rate = prate;
+ u32 val = clk_readl(c->reg);
+ u32 divu71;
+
+ val >>= c->reg_shift;
+
+ if (c->flags & DIV_U71) {
+ divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT;
+ c->div = (divu71 + 2);
+ c->mul = 2;
+ } else if (c->flags & DIV_2) {
+ c->div = 2;
+ c->mul = 1;
+ } else {
+ c->div = 1;
+ c->mul = 1;
+ }
+
+ rate *= c->mul;
+ rate += c->div - 1; /* round up */
+ do_div(rate, c->div);
+
+ return rate;
+}
+
+static int tegra20_pll_div_clk_enable(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ unsigned long flags;
+ u32 new_val;
+ u32 val;
+
+ pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk));
+
+ if (c->flags & DIV_U71) {
+ spin_lock_irqsave(&clock_register_lock, flags);
+ val = clk_readl(c->reg);
+ new_val = val >> c->reg_shift;
+ new_val &= 0xFFFF;
+
+ new_val |= PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE;
+
+ val &= ~(0xFFFF << c->reg_shift);
+ val |= new_val << c->reg_shift;
+ clk_writel(val, c->reg);
+ spin_unlock_irqrestore(&clock_register_lock, flags);
+ return 0;
+ } else if (c->flags & DIV_2) {
+ BUG_ON(!(c->flags & PLLD));
+ spin_lock_irqsave(&clock_register_lock, flags);
+ val = clk_readl(c->reg);
+ val &= ~PLLD_MISC_DIV_RST;
+ clk_writel(val, c->reg);
+ spin_unlock_irqrestore(&clock_register_lock, flags);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static void tegra20_pll_div_clk_disable(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ unsigned long flags;
+ u32 new_val;
+ u32 val;
+
+ pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk));
+
+ if (c->flags & DIV_U71) {
+ spin_lock_irqsave(&clock_register_lock, flags);
+ val = clk_readl(c->reg);
+ new_val = val >> c->reg_shift;
+ new_val &= 0xFFFF;
+
+ new_val &= ~(PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE);
+
+ val &= ~(0xFFFF << c->reg_shift);
+ val |= new_val << c->reg_shift;
+ clk_writel(val, c->reg);
+ spin_unlock_irqrestore(&clock_register_lock, flags);
+ } else if (c->flags & DIV_2) {
+ BUG_ON(!(c->flags & PLLD));
+ spin_lock_irqsave(&clock_register_lock, flags);
+ val = clk_readl(c->reg);
+ val |= PLLD_MISC_DIV_RST;
+ clk_writel(val, c->reg);
+ spin_unlock_irqrestore(&clock_register_lock, flags);
+ }
+}
+
+static int tegra20_pll_div_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ unsigned long flags;
+ int divider_u71;
+ u32 new_val;
+ u32 val;
+
+ pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate);
+
+ if (c->flags & DIV_U71) {
+ divider_u71 = clk_div71_get_divider(parent_rate, rate);
+ if (divider_u71 >= 0) {
+ spin_lock_irqsave(&clock_register_lock, flags);
+ val = clk_readl(c->reg);
+ new_val = val >> c->reg_shift;
+ new_val &= 0xFFFF;
+ if (c->flags & DIV_U71_FIXED)
+ new_val |= PLL_OUT_OVERRIDE;
+ new_val &= ~PLL_OUT_RATIO_MASK;
+ new_val |= divider_u71 << PLL_OUT_RATIO_SHIFT;
+
+ val &= ~(0xFFFF << c->reg_shift);
+ val |= new_val << c->reg_shift;
+ clk_writel(val, c->reg);
+ c->div = divider_u71 + 2;
+ c->mul = 2;
+ spin_unlock_irqrestore(&clock_register_lock, flags);
+ return 0;
+ }
+ } else if (c->flags & DIV_2) {
+ if (parent_rate == rate * 2)
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static long tegra20_pll_div_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ unsigned long parent_rate = *prate;
+ int divider;
+
+ pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate);
+
+ if (c->flags & DIV_U71) {
+ divider = clk_div71_get_divider(parent_rate, rate);
+ if (divider < 0)
+ return divider;
+ return DIV_ROUND_UP(parent_rate * 2, divider + 2);
+ } else if (c->flags & DIV_2) {
+ return DIV_ROUND_UP(parent_rate, 2);
+ }
+ return -EINVAL;
+}
+
+struct clk_ops tegra_pll_div_ops = {
+ .is_enabled = tegra20_pll_div_clk_is_enabled,
+ .enable = tegra20_pll_div_clk_enable,
+ .disable = tegra20_pll_div_clk_disable,
+ .set_rate = tegra20_pll_div_clk_set_rate,
+ .round_rate = tegra20_pll_div_clk_round_rate,
+ .recalc_rate = tegra20_pll_div_clk_recalc_rate,
+};
+
+/* Periph clk ops */
+
+static int tegra20_periph_clk_is_enabled(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+
+ c->state = ON;
+
+ if (!c->u.periph.clk_num)
+ goto out;
+
+ if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
+ PERIPH_CLK_TO_ENB_BIT(c)))
+ c->state = OFF;
+
+ if (!(c->flags & PERIPH_NO_RESET))
+ if (clk_readl(RST_DEVICES + PERIPH_CLK_TO_ENB_REG(c)) &
+ PERIPH_CLK_TO_ENB_BIT(c))
+ c->state = OFF;
+
+out:
+ return c->state;
+}
+
+static int tegra20_periph_clk_enable(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ unsigned long flags;
+ u32 val;
+
+ pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
+
+ if (!c->u.periph.clk_num)
+ return 0;
+
+ tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++;
+ if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 1)
+ return 0;
+
+ spin_lock_irqsave(&clock_register_lock, flags);
+
+ clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
+ CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c));
+ if (!(c->flags & PERIPH_NO_RESET) && !(c->flags & PERIPH_MANUAL_RESET))
+ clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
+ RST_DEVICES_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
+ if (c->flags & PERIPH_EMC_ENB) {
+ /* The EMC peripheral clock has 2 extra enable bits */
+ /* FIXME: Do they need to be disabled? */
+ val = clk_readl(c->reg);
+ val |= 0x3 << 24;
+ clk_writel(val, c->reg);
+ }
+
+ spin_unlock_irqrestore(&clock_register_lock, flags);
+
+ return 0;
+}
+
+static void tegra20_periph_clk_disable(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ unsigned long flags;
+
+ pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
+
+ if (!c->u.periph.clk_num)
+ return;
+
+ tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--;
+
+ if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 0)
+ return;
+
+ spin_lock_irqsave(&clock_register_lock, flags);
+
+ clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
+ CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
+
+ spin_unlock_irqrestore(&clock_register_lock, flags);
+}
+
+void tegra2_periph_clk_reset(struct clk_hw *hw, bool assert)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ unsigned long base = assert ? RST_DEVICES_SET : RST_DEVICES_CLR;
+
+ pr_debug("%s %s on clock %s\n", __func__,
+ assert ? "assert" : "deassert", __clk_get_name(hw->clk));
+
+ BUG_ON(!c->u.periph.clk_num);
+
+ if (!(c->flags & PERIPH_NO_RESET))
+ clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
+ base + PERIPH_CLK_TO_ENB_SET_REG(c));
+}
+
+static int tegra20_periph_clk_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u32 val;
+ u32 mask;
+ u32 shift;
+
+ pr_debug("%s: %s %d\n", __func__, __clk_get_name(hw->clk), index);
+
+ if (c->flags & MUX_PWM) {
+ shift = PERIPH_CLK_SOURCE_PWM_SHIFT;
+ mask = PERIPH_CLK_SOURCE_PWM_MASK;
+ } else {
+ shift = PERIPH_CLK_SOURCE_SHIFT;
+ mask = PERIPH_CLK_SOURCE_MASK;
+ }
+
+ val = clk_readl(c->reg);
+ val &= ~mask;
+ val |= (index) << shift;
+
+ clk_writel(val, c->reg);
+
+ return 0;
+}
+
+static u8 tegra20_periph_clk_get_parent(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u32 val = clk_readl(c->reg);
+ u32 mask;
+ u32 shift;
+
+ if (c->flags & MUX_PWM) {
+ shift = PERIPH_CLK_SOURCE_PWM_SHIFT;
+ mask = PERIPH_CLK_SOURCE_PWM_MASK;
+ } else {
+ shift = PERIPH_CLK_SOURCE_SHIFT;
+ mask = PERIPH_CLK_SOURCE_MASK;
+ }
+
+ if (c->flags & MUX)
+ return (val & mask) >> shift;
+ else
+ return 0;
+}
+
+static unsigned long tegra20_periph_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long prate)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ unsigned long rate = prate;
+ u32 val = clk_readl(c->reg);
+
+ if (c->flags & DIV_U71) {
+ u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
+ c->div = divu71 + 2;
+ c->mul = 2;
+ } else if (c->flags & DIV_U16) {
+ u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK;
+ c->div = divu16 + 1;
+ c->mul = 1;
+ } else {
+ c->div = 1;
+ c->mul = 1;
+ return rate;
+ }
+
+ if (c->mul != 0 && c->div != 0) {
+ rate *= c->mul;
+ rate += c->div - 1; /* round up */
+ do_div(rate, c->div);
+ }
+
+ return rate;
+}
+
+static int tegra20_periph_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u32 val;
+ int divider;
+
+ val = clk_readl(c->reg);
+
+ if (c->flags & DIV_U71) {
+ divider = clk_div71_get_divider(parent_rate, rate);
+
+ if (divider >= 0) {
+ val = clk_readl(c->reg);
+ val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK;
+ val |= divider;
+ clk_writel(val, c->reg);
+ c->div = divider + 2;
+ c->mul = 2;
+ return 0;
+ }
+ } else if (c->flags & DIV_U16) {
+ divider = clk_div16_get_divider(parent_rate, rate);
+ if (divider >= 0) {
+ val = clk_readl(c->reg);
+ val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK;
+ val |= divider;
+ clk_writel(val, c->reg);
+ c->div = divider + 1;
+ c->mul = 1;
+ return 0;
+ }
+ } else if (parent_rate <= rate) {
+ c->div = 1;
+ c->mul = 1;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static long tegra20_periph_clk_round_rate(struct clk_hw *hw,
+ unsigned long rate, unsigned long *prate)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ unsigned long parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
+ int divider;
+
+ pr_debug("%s: %s %lu\n", __func__, __clk_get_name(hw->clk), rate);
+
+ if (prate)
+ parent_rate = *prate;
+
+ if (c->flags & DIV_U71) {
+ divider = clk_div71_get_divider(parent_rate, rate);
+ if (divider < 0)
+ return divider;
+
+ return DIV_ROUND_UP(parent_rate * 2, divider + 2);
+ } else if (c->flags & DIV_U16) {
+ divider = clk_div16_get_divider(parent_rate, rate);
+ if (divider < 0)
+ return divider;
+ return DIV_ROUND_UP(parent_rate, divider + 1);
+ }
+ return -EINVAL;
+}
+
+struct clk_ops tegra_periph_clk_ops = {
+ .is_enabled = tegra20_periph_clk_is_enabled,
+ .enable = tegra20_periph_clk_enable,
+ .disable = tegra20_periph_clk_disable,
+ .set_parent = tegra20_periph_clk_set_parent,
+ .get_parent = tegra20_periph_clk_get_parent,
+ .set_rate = tegra20_periph_clk_set_rate,
+ .round_rate = tegra20_periph_clk_round_rate,
+ .recalc_rate = tegra20_periph_clk_recalc_rate,
+};
+
+/* External memory controller clock ops */
+static void tegra20_emc_clk_init(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ c->max_rate = __clk_get_rate(hw->clk);
+}
+
+static long tegra20_emc_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ long emc_rate;
+ long clk_rate;
+
+ /*
+ * The slowest entry in the EMC clock table that is at least as
+ * fast as rate.
+ */
+ emc_rate = tegra_emc_round_rate(rate);
+ if (emc_rate < 0)
+ return c->max_rate;
+
+ /*
+ * The fastest rate the PLL will generate that is at most the
+ * requested rate.
+ */
+ clk_rate = tegra20_periph_clk_round_rate(hw, emc_rate, NULL);
+
+ /*
+ * If this fails, and emc_rate > clk_rate, it's because the maximum
+ * rate in the EMC tables is larger than the maximum rate of the EMC
+ * clock. The EMC clock's max rate is the rate it was running when the
+ * kernel booted. Such a mismatch is probably due to using the wrong
+ * BCT, i.e. using a Tegra20 BCT with an EMC table written for Tegra25.
+ */
+ WARN_ONCE(emc_rate != clk_rate,
+ "emc_rate %ld != clk_rate %ld",
+ emc_rate, clk_rate);
+
+ return emc_rate;
+}
+
+static int tegra20_emc_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ int ret;
+
+ /*
+ * The Tegra2 memory controller has an interlock with the clock
+ * block that allows memory shadowed registers to be updated,
+ * and then transfer them to the main registers at the same
+ * time as the clock update without glitches.
+ */
+ ret = tegra_emc_set_rate(rate);
+ if (ret < 0)
+ return ret;
+
+ ret = tegra20_periph_clk_set_rate(hw, rate, parent_rate);
+ udelay(1);
+
+ return ret;
+}
+
+struct clk_ops tegra_emc_clk_ops = {
+ .init = tegra20_emc_clk_init,
+ .is_enabled = tegra20_periph_clk_is_enabled,
+ .enable = tegra20_periph_clk_enable,
+ .disable = tegra20_periph_clk_disable,
+ .set_parent = tegra20_periph_clk_set_parent,
+ .get_parent = tegra20_periph_clk_get_parent,
+ .set_rate = tegra20_emc_clk_set_rate,
+ .round_rate = tegra20_emc_clk_round_rate,
+ .recalc_rate = tegra20_periph_clk_recalc_rate,
+};
+
+/* Clock doubler ops */
+static int tegra20_clk_double_is_enabled(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+
+ c->state = ON;
+
+ if (!c->u.periph.clk_num)
+ goto out;
+
+ if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
+ PERIPH_CLK_TO_ENB_BIT(c)))
+ c->state = OFF;
+
+out:
+ return c->state;
+};
+
+static unsigned long tegra20_clk_double_recalc_rate(struct clk_hw *hw,
+ unsigned long prate)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u64 rate = prate;
+
+ c->mul = 2;
+ c->div = 1;
+
+ rate *= c->mul;
+ rate += c->div - 1; /* round up */
+ do_div(rate, c->div);
+
+ return rate;
+}
+
+static long tegra20_clk_double_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ unsigned long output_rate = *prate;
+
+ do_div(output_rate, 2);
+ return output_rate;
+}
+
+static int tegra20_clk_double_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ if (rate != 2 * parent_rate)
+ return -EINVAL;
+ return 0;
+}
+
+struct clk_ops tegra_clk_double_ops = {
+ .is_enabled = tegra20_clk_double_is_enabled,
+ .enable = tegra20_periph_clk_enable,
+ .disable = tegra20_periph_clk_disable,
+ .set_rate = tegra20_clk_double_set_rate,
+ .recalc_rate = tegra20_clk_double_recalc_rate,
+ .round_rate = tegra20_clk_double_round_rate,
+};
+
+/* Audio sync clock ops */
+static int tegra20_audio_sync_clk_is_enabled(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u32 val = clk_readl(c->reg);
+
+ c->state = (val & (1<<4)) ? OFF : ON;
+ return c->state;
+}
+
+static int tegra20_audio_sync_clk_enable(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+
+ clk_writel(0, c->reg);
+ return 0;
+}
+
+static void tegra20_audio_sync_clk_disable(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ clk_writel(1, c->reg);
+}
+
+static u8 tegra20_audio_sync_clk_get_parent(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u32 val = clk_readl(c->reg);
+ int source;
+
+ source = val & 0xf;
+ return source;
+}
+
+static int tegra20_audio_sync_clk_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u32 val;
+
+ val = clk_readl(c->reg);
+ val &= ~0xf;
+ val |= index;
+
+ clk_writel(val, c->reg);
+
+ return 0;
+}
+
+struct clk_ops tegra_audio_sync_clk_ops = {
+ .is_enabled = tegra20_audio_sync_clk_is_enabled,
+ .enable = tegra20_audio_sync_clk_enable,
+ .disable = tegra20_audio_sync_clk_disable,
+ .set_parent = tegra20_audio_sync_clk_set_parent,
+ .get_parent = tegra20_audio_sync_clk_get_parent,
+};
+
+/* cdev1 and cdev2 (dap_mclk1 and dap_mclk2) ops */
+
+static int tegra20_cdev_clk_is_enabled(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ /* We could un-tristate the cdev1 or cdev2 pingroup here; this is
+ * currently done in the pinmux code. */
+ c->state = ON;
+
+ BUG_ON(!c->u.periph.clk_num);
+
+ if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
+ PERIPH_CLK_TO_ENB_BIT(c)))
+ c->state = OFF;
+ return c->state;
+}
+
+static int tegra20_cdev_clk_enable(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ BUG_ON(!c->u.periph.clk_num);
+
+ clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
+ CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c));
+ return 0;
+}
+
+static void tegra20_cdev_clk_disable(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ BUG_ON(!c->u.periph.clk_num);
+
+ clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
+ CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
+}
+
+static unsigned long tegra20_cdev_recalc_rate(struct clk_hw *hw,
+ unsigned long prate)
+{
+ return to_clk_tegra(hw)->fixed_rate;
+}
+
+struct clk_ops tegra_cdev_clk_ops = {
+ .is_enabled = tegra20_cdev_clk_is_enabled,
+ .enable = tegra20_cdev_clk_enable,
+ .disable = tegra20_cdev_clk_disable,
+ .recalc_rate = tegra20_cdev_recalc_rate,
+};
diff --git a/arch/arm/mach-tegra/tegra20_clocks.h b/arch/arm/mach-tegra/tegra20_clocks.h
new file mode 100644
index 000000000000..8bfd31bcc490
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20_clocks.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MACH_TEGRA20_CLOCK_H
+#define __MACH_TEGRA20_CLOCK_H
+
+extern struct clk_ops tegra_clk_32k_ops;
+extern struct clk_ops tegra_pll_ops;
+extern struct clk_ops tegra_clk_m_ops;
+extern struct clk_ops tegra_pll_div_ops;
+extern struct clk_ops tegra_pllx_ops;
+extern struct clk_ops tegra_plle_ops;
+extern struct clk_ops tegra_clk_double_ops;
+extern struct clk_ops tegra_cdev_clk_ops;
+extern struct clk_ops tegra_audio_sync_clk_ops;
+extern struct clk_ops tegra_super_ops;
+extern struct clk_ops tegra_cpu_ops;
+extern struct clk_ops tegra_twd_ops;
+extern struct clk_ops tegra_cop_ops;
+extern struct clk_ops tegra_bus_ops;
+extern struct clk_ops tegra_blink_clk_ops;
+extern struct clk_ops tegra_emc_clk_ops;
+extern struct clk_ops tegra_periph_clk_ops;
+extern struct clk_ops tegra_clk_shared_bus_ops;
+
+void tegra2_periph_clk_reset(struct clk_hw *hw, bool assert);
+void tegra2_cop_clk_reset(struct clk_hw *hw, bool assert);
+
+#endif
diff --git a/arch/arm/mach-tegra/tegra20_clocks_data.c b/arch/arm/mach-tegra/tegra20_clocks_data.c
new file mode 100644
index 000000000000..6cfe2f9840fa
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20_clocks_data.c
@@ -0,0 +1,1138 @@
+/*
+ * arch/arm/mach-tegra/tegra2_clocks.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved.
+ *
+ * Author:
+ * Colin Cross <ccross@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/clk-private.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+
+#include <mach/iomap.h>
+#include <mach/suspend.h>
+
+#include "clock.h"
+#include "fuse.h"
+#include "tegra2_emc.h"
+#include "tegra20_clocks.h"
+
+/* Clock definitions */
+
+#define DEFINE_CLK_TEGRA(_name, _rate, _ops, _flags, \
+ _parent_names, _parents, _parent) \
+ static struct clk tegra_##_name = { \
+ .hw = &tegra_##_name##_hw.hw, \
+ .name = #_name, \
+ .rate = _rate, \
+ .ops = _ops, \
+ .flags = _flags, \
+ .parent_names = _parent_names, \
+ .parents = _parents, \
+ .num_parents = ARRAY_SIZE(_parent_names), \
+ .parent = _parent, \
+ };
+
+static struct clk tegra_clk_32k;
+static struct clk_tegra tegra_clk_32k_hw = {
+ .hw = {
+ .clk = &tegra_clk_32k,
+ },
+ .fixed_rate = 32768,
+};
+
+static struct clk tegra_clk_32k = {
+ .name = "clk_32k",
+ .rate = 32768,
+ .ops = &tegra_clk_32k_ops,
+ .hw = &tegra_clk_32k_hw.hw,
+ .flags = CLK_IS_ROOT,
+};
+
+static struct clk tegra_clk_m;
+static struct clk_tegra tegra_clk_m_hw = {
+ .hw = {
+ .clk = &tegra_clk_m,
+ },
+ .flags = ENABLE_ON_INIT,
+ .reg = 0x1fc,
+ .reg_shift = 28,
+ .max_rate = 26000000,
+ .fixed_rate = 0,
+};
+
+static struct clk tegra_clk_m = {
+ .name = "clk_m",
+ .ops = &tegra_clk_m_ops,
+ .hw = &tegra_clk_m_hw.hw,
+ .flags = CLK_IS_ROOT,
+};
+
+#define DEFINE_PLL(_name, _flags, _reg, _max_rate, _input_min, \
+ _input_max, _cf_min, _cf_max, _vco_min, \
+ _vco_max, _freq_table, _lock_delay, _ops, \
+ _fixed_rate, _parent) \
+ static const char *tegra_##_name##_parent_names[] = { \
+ #_parent, \
+ }; \
+ static struct clk *tegra_##_name##_parents[] = { \
+ &tegra_##_parent, \
+ }; \
+ static struct clk tegra_##_name; \
+ static struct clk_tegra tegra_##_name##_hw = { \
+ .hw = { \
+ .clk = &tegra_##_name, \
+ }, \
+ .flags = _flags, \
+ .reg = _reg, \
+ .max_rate = _max_rate, \
+ .u.pll = { \
+ .input_min = _input_min, \
+ .input_max = _input_max, \
+ .cf_min = _cf_min, \
+ .cf_max = _cf_max, \
+ .vco_min = _vco_min, \
+ .vco_max = _vco_max, \
+ .freq_table = _freq_table, \
+ .lock_delay = _lock_delay, \
+ .fixed_rate = _fixed_rate, \
+ }, \
+ }; \
+ static struct clk tegra_##_name = { \
+ .name = #_name, \
+ .ops = &_ops, \
+ .hw = &tegra_##_name##_hw.hw, \
+ .parent = &tegra_##_parent, \
+ .parent_names = tegra_##_name##_parent_names, \
+ .parents = tegra_##_name##_parents, \
+ .num_parents = 1, \
+ };
+
+#define DEFINE_PLL_OUT(_name, _flags, _reg, _reg_shift, \
+ _max_rate, _ops, _parent, _clk_flags) \
+ static const char *tegra_##_name##_parent_names[] = { \
+ #_parent, \
+ }; \
+ static struct clk *tegra_##_name##_parents[] = { \
+ &tegra_##_parent, \
+ }; \
+ static struct clk tegra_##_name; \
+ static struct clk_tegra tegra_##_name##_hw = { \
+ .hw = { \
+ .clk = &tegra_##_name, \
+ }, \
+ .flags = _flags, \
+ .reg = _reg, \
+ .max_rate = _max_rate, \
+ .reg_shift = _reg_shift, \
+ }; \
+ static struct clk tegra_##_name = { \
+ .name = #_name, \
+ .ops = &tegra_pll_div_ops, \
+ .hw = &tegra_##_name##_hw.hw, \
+ .parent = &tegra_##_parent, \
+ .parent_names = tegra_##_name##_parent_names, \
+ .parents = tegra_##_name##_parents, \
+ .num_parents = 1, \
+ .flags = _clk_flags, \
+ };
+
+
+static struct clk_pll_freq_table tegra_pll_s_freq_table[] = {
+ {32768, 12000000, 366, 1, 1, 0},
+ {32768, 13000000, 397, 1, 1, 0},
+ {32768, 19200000, 586, 1, 1, 0},
+ {32768, 26000000, 793, 1, 1, 0},
+ {0, 0, 0, 0, 0, 0},
+};
+
+DEFINE_PLL(pll_s, PLL_ALT_MISC_REG, 0xf0, 26000000, 32768, 32768, 0,
+ 0, 12000000, 26000000, tegra_pll_s_freq_table, 300,
+ tegra_pll_ops, 0, clk_32k);
+
+static struct clk_pll_freq_table tegra_pll_c_freq_table[] = {
+ { 12000000, 600000000, 600, 12, 1, 8 },
+ { 13000000, 600000000, 600, 13, 1, 8 },
+ { 19200000, 600000000, 500, 16, 1, 6 },
+ { 26000000, 600000000, 600, 26, 1, 8 },
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_c, PLL_HAS_CPCON, 0x80, 600000000, 2000000, 31000000, 1000000,
+ 6000000, 20000000, 1400000000, tegra_pll_c_freq_table, 300,
+ tegra_pll_ops, 0, clk_m);
+
+DEFINE_PLL_OUT(pll_c_out1, DIV_U71, 0x84, 0, 600000000,
+ tegra_pll_div_ops, pll_c, 0);
+
+static struct clk_pll_freq_table tegra_pll_m_freq_table[] = {
+ { 12000000, 666000000, 666, 12, 1, 8},
+ { 13000000, 666000000, 666, 13, 1, 8},
+ { 19200000, 666000000, 555, 16, 1, 8},
+ { 26000000, 666000000, 666, 26, 1, 8},
+ { 12000000, 600000000, 600, 12, 1, 8},
+ { 13000000, 600000000, 600, 13, 1, 8},
+ { 19200000, 600000000, 375, 12, 1, 6},
+ { 26000000, 600000000, 600, 26, 1, 8},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_m, PLL_HAS_CPCON, 0x90, 800000000, 2000000, 31000000, 1000000,
+ 6000000, 20000000, 1200000000, tegra_pll_m_freq_table, 300,
+ tegra_pll_ops, 0, clk_m);
+
+DEFINE_PLL_OUT(pll_m_out1, DIV_U71, 0x94, 0, 600000000,
+ tegra_pll_div_ops, pll_m, 0);
+
+static struct clk_pll_freq_table tegra_pll_p_freq_table[] = {
+ { 12000000, 216000000, 432, 12, 2, 8},
+ { 13000000, 216000000, 432, 13, 2, 8},
+ { 19200000, 216000000, 90, 4, 2, 1},
+ { 26000000, 216000000, 432, 26, 2, 8},
+ { 12000000, 432000000, 432, 12, 1, 8},
+ { 13000000, 432000000, 432, 13, 1, 8},
+ { 19200000, 432000000, 90, 4, 1, 1},
+ { 26000000, 432000000, 432, 26, 1, 8},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+
+DEFINE_PLL(pll_p, ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON, 0xa0, 432000000,
+ 2000000, 31000000, 1000000, 6000000, 20000000, 1400000000,
+ tegra_pll_p_freq_table, 300, tegra_pll_ops, 216000000, clk_m);
+
+DEFINE_PLL_OUT(pll_p_out1, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4, 0,
+ 432000000, tegra_pll_div_ops, pll_p, 0);
+DEFINE_PLL_OUT(pll_p_out2, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4, 16,
+ 432000000, tegra_pll_div_ops, pll_p, 0);
+DEFINE_PLL_OUT(pll_p_out3, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8, 0,
+ 432000000, tegra_pll_div_ops, pll_p, 0);
+DEFINE_PLL_OUT(pll_p_out4, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8, 16,
+ 432000000, tegra_pll_div_ops, pll_p, 0);
+
+static struct clk_pll_freq_table tegra_pll_a_freq_table[] = {
+ { 28800000, 56448000, 49, 25, 1, 1},
+ { 28800000, 73728000, 64, 25, 1, 1},
+ { 28800000, 24000000, 5, 6, 1, 1},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_a, PLL_HAS_CPCON, 0xb0, 73728000, 2000000, 31000000, 1000000,
+ 6000000, 20000000, 1400000000, tegra_pll_a_freq_table, 300,
+ tegra_pll_ops, 0, pll_p_out1);
+
+DEFINE_PLL_OUT(pll_a_out0, DIV_U71, 0xb4, 0, 73728000,
+ tegra_pll_div_ops, pll_a, 0);
+
+static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
+ { 12000000, 216000000, 216, 12, 1, 4},
+ { 13000000, 216000000, 216, 13, 1, 4},
+ { 19200000, 216000000, 135, 12, 1, 3},
+ { 26000000, 216000000, 216, 26, 1, 4},
+
+ { 12000000, 594000000, 594, 12, 1, 8},
+ { 13000000, 594000000, 594, 13, 1, 8},
+ { 19200000, 594000000, 495, 16, 1, 8},
+ { 26000000, 594000000, 594, 26, 1, 8},
+
+ { 12000000, 1000000000, 1000, 12, 1, 12},
+ { 13000000, 1000000000, 1000, 13, 1, 12},
+ { 19200000, 1000000000, 625, 12, 1, 8},
+ { 26000000, 1000000000, 1000, 26, 1, 12},
+
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_d, PLL_HAS_CPCON | PLLD, 0xd0, 1000000000, 2000000, 40000000,
+ 1000000, 6000000, 40000000, 1000000000, tegra_pll_d_freq_table,
+ 1000, tegra_pll_ops, 0, clk_m);
+
+DEFINE_PLL_OUT(pll_d_out0, DIV_2 | PLLD, 0, 0, 500000000,
+ tegra_pll_div_ops, pll_d, CLK_SET_RATE_PARENT);
+
+static struct clk_pll_freq_table tegra_pll_u_freq_table[] = {
+ { 12000000, 480000000, 960, 12, 2, 0},
+ { 13000000, 480000000, 960, 13, 2, 0},
+ { 19200000, 480000000, 200, 4, 2, 0},
+ { 26000000, 480000000, 960, 26, 2, 0},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_u, PLLU, 0xc0, 480000000, 2000000, 40000000, 1000000, 6000000,
+ 48000000, 960000000, tegra_pll_u_freq_table, 1000,
+ tegra_pll_ops, 0, clk_m);
+
+static struct clk_pll_freq_table tegra_pll_x_freq_table[] = {
+ /* 1 GHz */
+ { 12000000, 1000000000, 1000, 12, 1, 12},
+ { 13000000, 1000000000, 1000, 13, 1, 12},
+ { 19200000, 1000000000, 625, 12, 1, 8},
+ { 26000000, 1000000000, 1000, 26, 1, 12},
+
+ /* 912 MHz */
+ { 12000000, 912000000, 912, 12, 1, 12},
+ { 13000000, 912000000, 912, 13, 1, 12},
+ { 19200000, 912000000, 760, 16, 1, 8},
+ { 26000000, 912000000, 912, 26, 1, 12},
+
+ /* 816 MHz */
+ { 12000000, 816000000, 816, 12, 1, 12},
+ { 13000000, 816000000, 816, 13, 1, 12},
+ { 19200000, 816000000, 680, 16, 1, 8},
+ { 26000000, 816000000, 816, 26, 1, 12},
+
+ /* 760 MHz */
+ { 12000000, 760000000, 760, 12, 1, 12},
+ { 13000000, 760000000, 760, 13, 1, 12},
+ { 19200000, 760000000, 950, 24, 1, 8},
+ { 26000000, 760000000, 760, 26, 1, 12},
+
+ /* 750 MHz */
+ { 12000000, 750000000, 750, 12, 1, 12},
+ { 13000000, 750000000, 750, 13, 1, 12},
+ { 19200000, 750000000, 625, 16, 1, 8},
+ { 26000000, 750000000, 750, 26, 1, 12},
+
+ /* 608 MHz */
+ { 12000000, 608000000, 608, 12, 1, 12},
+ { 13000000, 608000000, 608, 13, 1, 12},
+ { 19200000, 608000000, 380, 12, 1, 8},
+ { 26000000, 608000000, 608, 26, 1, 12},
+
+ /* 456 MHz */
+ { 12000000, 456000000, 456, 12, 1, 12},
+ { 13000000, 456000000, 456, 13, 1, 12},
+ { 19200000, 456000000, 380, 16, 1, 8},
+ { 26000000, 456000000, 456, 26, 1, 12},
+
+ /* 312 MHz */
+ { 12000000, 312000000, 312, 12, 1, 12},
+ { 13000000, 312000000, 312, 13, 1, 12},
+ { 19200000, 312000000, 260, 16, 1, 8},
+ { 26000000, 312000000, 312, 26, 1, 12},
+
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_x, PLL_HAS_CPCON | PLL_ALT_MISC_REG, 0xe0, 1000000000, 2000000,
+ 31000000, 1000000, 6000000, 20000000, 1200000000,
+ tegra_pll_x_freq_table, 300, tegra_pllx_ops, 0, clk_m);
+
+static struct clk_pll_freq_table tegra_pll_e_freq_table[] = {
+ { 12000000, 100000000, 200, 24, 1, 0 },
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_e, PLL_ALT_MISC_REG, 0xe8, 100000000, 12000000, 12000000, 0, 0,
+ 0, 0, tegra_pll_e_freq_table, 0, tegra_plle_ops, 0, clk_m);
+
+static const char *tegra_common_parent_names[] = {
+ "clk_m",
+};
+
+static struct clk *tegra_common_parents[] = {
+ &tegra_clk_m,
+};
+
+static struct clk tegra_clk_d;
+static struct clk_tegra tegra_clk_d_hw = {
+ .hw = {
+ .clk = &tegra_clk_d,
+ },
+ .flags = PERIPH_NO_RESET,
+ .reg = 0x34,
+ .reg_shift = 12,
+ .max_rate = 52000000,
+ .u.periph = {
+ .clk_num = 90,
+ },
+};
+
+static struct clk tegra_clk_d = {
+ .name = "clk_d",
+ .hw = &tegra_clk_d_hw.hw,
+ .ops = &tegra_clk_double_ops,
+ .parent = &tegra_clk_m,
+ .parent_names = tegra_common_parent_names,
+ .parents = tegra_common_parents,
+ .num_parents = ARRAY_SIZE(tegra_common_parent_names),
+};
+
+static struct clk tegra_cdev1;
+static struct clk_tegra tegra_cdev1_hw = {
+ .hw = {
+ .clk = &tegra_cdev1,
+ },
+ .fixed_rate = 26000000,
+ .u.periph = {
+ .clk_num = 94,
+ },
+};
+static struct clk tegra_cdev1 = {
+ .name = "cdev1",
+ .hw = &tegra_cdev1_hw.hw,
+ .ops = &tegra_cdev_clk_ops,
+ .flags = CLK_IS_ROOT,
+};
+
+/* dap_mclk2, belongs to the cdev2 pingroup. */
+static struct clk tegra_cdev2;
+static struct clk_tegra tegra_cdev2_hw = {
+ .hw = {
+ .clk = &tegra_cdev2,
+ },
+ .fixed_rate = 26000000,
+ .u.periph = {
+ .clk_num = 93,
+ },
+};
+static struct clk tegra_cdev2 = {
+ .name = "cdev2",
+ .hw = &tegra_cdev2_hw.hw,
+ .ops = &tegra_cdev_clk_ops,
+ .flags = CLK_IS_ROOT,
+};
+
+/* initialized before peripheral clocks */
+static struct clk_mux_sel mux_audio_sync_clk[8+1];
+static const struct audio_sources {
+ const char *name;
+ int value;
+} mux_audio_sync_clk_sources[] = {
+ { .name = "spdif_in", .value = 0 },
+ { .name = "i2s1", .value = 1 },
+ { .name = "i2s2", .value = 2 },
+ { .name = "pll_a_out0", .value = 4 },
+#if 0 /* FIXME: not implemented */
+ { .name = "ac97", .value = 3 },
+ { .name = "ext_audio_clk2", .value = 5 },
+ { .name = "ext_audio_clk1", .value = 6 },
+ { .name = "ext_vimclk", .value = 7 },
+#endif
+ { NULL, 0 }
+};
+
+static const char *audio_parent_names[] = {
+ "spdif_in",
+ "i2s1",
+ "i2s2",
+ "dummy",
+ "pll_a_out0",
+ "dummy",
+ "dummy",
+ "dummy",
+};
+
+static struct clk *audio_parents[] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static struct clk tegra_audio;
+static struct clk_tegra tegra_audio_hw = {
+ .hw = {
+ .clk = &tegra_audio,
+ },
+ .reg = 0x38,
+ .max_rate = 73728000,
+};
+DEFINE_CLK_TEGRA(audio, 0, &tegra_audio_sync_clk_ops, 0, audio_parent_names,
+ audio_parents, NULL);
+
+static const char *audio_2x_parent_names[] = {
+ "audio",
+};
+
+static struct clk *audio_2x_parents[] = {
+ &tegra_audio,
+};
+
+static struct clk tegra_audio_2x;
+static struct clk_tegra tegra_audio_2x_hw = {
+ .hw = {
+ .clk = &tegra_audio_2x,
+ },
+ .flags = PERIPH_NO_RESET,
+ .max_rate = 48000000,
+ .reg = 0x34,
+ .reg_shift = 8,
+ .u.periph = {
+ .clk_num = 89,
+ },
+};
+DEFINE_CLK_TEGRA(audio_2x, 0, &tegra_clk_double_ops, 0, audio_2x_parent_names,
+ audio_2x_parents, &tegra_audio);
+
+static struct clk_lookup tegra_audio_clk_lookups[] = {
+ { .con_id = "audio", .clk = &tegra_audio },
+ { .con_id = "audio_2x", .clk = &tegra_audio_2x }
+};
+
+/* This is called after peripheral clocks are initialized, as the
+ * audio_sync clock depends on some of the peripheral clocks.
+ */
+
+static void init_audio_sync_clock_mux(void)
+{
+ int i;
+ struct clk_mux_sel *sel = mux_audio_sync_clk;
+ const struct audio_sources *src = mux_audio_sync_clk_sources;
+ struct clk_lookup *lookup;
+
+ for (i = 0; src->name; i++, sel++, src++) {
+ sel->input = tegra_get_clock_by_name(src->name);
+ if (!sel->input)
+ pr_err("%s: could not find clk %s\n", __func__,
+ src->name);
+ audio_parents[src->value] = sel->input;
+ sel->value = src->value;
+ }
+
+ lookup = tegra_audio_clk_lookups;
+ for (i = 0; i < ARRAY_SIZE(tegra_audio_clk_lookups); i++, lookup++) {
+ struct clk *c = lookup->clk;
+ struct clk_tegra *clk = to_clk_tegra(c->hw);
+ __clk_init(NULL, c);
+ INIT_LIST_HEAD(&clk->shared_bus_list);
+ clk->lookup.con_id = lookup->con_id;
+ clk->lookup.clk = c;
+ clkdev_add(&clk->lookup);
+ tegra_clk_add(c);
+ }
+}
+
+static const char *mux_cclk[] = {
+ "clk_m",
+ "pll_c",
+ "clk_32k",
+ "pll_m",
+ "pll_p",
+ "pll_p_out4",
+ "pll_p_out3",
+ "clk_d",
+ "pll_x",
+};
+
+
+static struct clk *mux_cclk_p[] = {
+ &tegra_clk_m,
+ &tegra_pll_c,
+ &tegra_clk_32k,
+ &tegra_pll_m,
+ &tegra_pll_p,
+ &tegra_pll_p_out4,
+ &tegra_pll_p_out3,
+ &tegra_clk_d,
+ &tegra_pll_x,
+};
+
+static const char *mux_sclk[] = {
+ "clk_m",
+ "pll_c_out1",
+ "pll_p_out4",
+ "pllp_p_out3",
+ "pll_p_out2",
+ "clk_d",
+ "clk_32k",
+ "pll_m_out1",
+};
+
+static struct clk *mux_sclk_p[] = {
+ &tegra_clk_m,
+ &tegra_pll_c_out1,
+ &tegra_pll_p_out4,
+ &tegra_pll_p_out3,
+ &tegra_pll_p_out2,
+ &tegra_clk_d,
+ &tegra_clk_32k,
+ &tegra_pll_m_out1,
+};
+
+static struct clk tegra_cclk;
+static struct clk_tegra tegra_cclk_hw = {
+ .hw = {
+ .clk = &tegra_cclk,
+ },
+ .reg = 0x20,
+ .max_rate = 1000000000,
+};
+DEFINE_CLK_TEGRA(cclk, 0, &tegra_super_ops, 0, mux_cclk,
+ mux_cclk_p, NULL);
+
+static const char *mux_twd[] = {
+ "cclk",
+};
+
+static struct clk *mux_twd_p[] = {
+ &tegra_cclk,
+};
+
+static struct clk tegra_clk_twd;
+static struct clk_tegra tegra_clk_twd_hw = {
+ .hw = {
+ .clk = &tegra_clk_twd,
+ },
+ .max_rate = 1000000000,
+ .mul = 1,
+ .div = 4,
+};
+
+static struct clk tegra_clk_twd = {
+ .name = "twd",
+ .ops = &tegra_twd_ops,
+ .hw = &tegra_clk_twd_hw.hw,
+ .parent = &tegra_cclk,
+ .parent_names = mux_twd,
+ .parents = mux_twd_p,
+ .num_parents = ARRAY_SIZE(mux_twd),
+};
+
+static struct clk tegra_sclk;
+static struct clk_tegra tegra_sclk_hw = {
+ .hw = {
+ .clk = &tegra_sclk,
+ },
+ .reg = 0x28,
+ .max_rate = 240000000,
+ .min_rate = 120000000,
+};
+DEFINE_CLK_TEGRA(sclk, 0, &tegra_super_ops, 0, mux_sclk,
+ mux_sclk_p, NULL);
+
+static const char *tegra_cop_parent_names[] = {
+ "tegra_sclk",
+};
+
+static struct clk *tegra_cop_parents[] = {
+ &tegra_sclk,
+};
+
+static struct clk tegra_cop;
+static struct clk_tegra tegra_cop_hw = {
+ .hw = {
+ .clk = &tegra_cop,
+ },
+ .max_rate = 240000000,
+ .reset = &tegra2_cop_clk_reset,
+};
+DEFINE_CLK_TEGRA(cop, 0, &tegra_cop_ops, CLK_SET_RATE_PARENT,
+ tegra_cop_parent_names, tegra_cop_parents, &tegra_sclk);
+
+static const char *tegra_hclk_parent_names[] = {
+ "tegra_sclk",
+};
+
+static struct clk *tegra_hclk_parents[] = {
+ &tegra_sclk,
+};
+
+static struct clk tegra_hclk;
+static struct clk_tegra tegra_hclk_hw = {
+ .hw = {
+ .clk = &tegra_hclk,
+ },
+ .flags = DIV_BUS,
+ .reg = 0x30,
+ .reg_shift = 4,
+ .max_rate = 240000000,
+};
+DEFINE_CLK_TEGRA(hclk, 0, &tegra_bus_ops, 0, tegra_hclk_parent_names,
+ tegra_hclk_parents, &tegra_sclk);
+
+static const char *tegra_pclk_parent_names[] = {
+ "tegra_hclk",
+};
+
+static struct clk *tegra_pclk_parents[] = {
+ &tegra_hclk,
+};
+
+static struct clk tegra_pclk;
+static struct clk_tegra tegra_pclk_hw = {
+ .hw = {
+ .clk = &tegra_pclk,
+ },
+ .flags = DIV_BUS,
+ .reg = 0x30,
+ .reg_shift = 0,
+ .max_rate = 120000000,
+};
+DEFINE_CLK_TEGRA(pclk, 0, &tegra_bus_ops, 0, tegra_pclk_parent_names,
+ tegra_pclk_parents, &tegra_hclk);
+
+static const char *tegra_blink_parent_names[] = {
+ "clk_32k",
+};
+
+static struct clk *tegra_blink_parents[] = {
+ &tegra_clk_32k,
+};
+
+static struct clk tegra_blink;
+static struct clk_tegra tegra_blink_hw = {
+ .hw = {
+ .clk = &tegra_blink,
+ },
+ .reg = 0x40,
+ .max_rate = 32768,
+};
+DEFINE_CLK_TEGRA(blink, 0, &tegra_blink_clk_ops, 0, tegra_blink_parent_names,
+ tegra_blink_parents, &tegra_clk_32k);
+
+static const char *mux_pllm_pllc_pllp_plla[] = {
+ "pll_m",
+ "pll_c",
+ "pll_p",
+ "pll_a_out0",
+};
+
+static struct clk *mux_pllm_pllc_pllp_plla_p[] = {
+ &tegra_pll_m,
+ &tegra_pll_c,
+ &tegra_pll_p,
+ &tegra_pll_a_out0,
+};
+
+static const char *mux_pllm_pllc_pllp_clkm[] = {
+ "pll_m",
+ "pll_c",
+ "pll_p",
+ "clk_m",
+};
+
+static struct clk *mux_pllm_pllc_pllp_clkm_p[] = {
+ &tegra_pll_m,
+ &tegra_pll_c,
+ &tegra_pll_p,
+ &tegra_clk_m,
+};
+
+static const char *mux_pllp_pllc_pllm_clkm[] = {
+ "pll_p",
+ "pll_c",
+ "pll_m",
+ "clk_m",
+};
+
+static struct clk *mux_pllp_pllc_pllm_clkm_p[] = {
+ &tegra_pll_p,
+ &tegra_pll_c,
+ &tegra_pll_m,
+ &tegra_clk_m,
+};
+
+static const char *mux_pllaout0_audio2x_pllp_clkm[] = {
+ "pll_a_out0",
+ "audio_2x",
+ "pll_p",
+ "clk_m",
+};
+
+static struct clk *mux_pllaout0_audio2x_pllp_clkm_p[] = {
+ &tegra_pll_a_out0,
+ &tegra_audio_2x,
+ &tegra_pll_p,
+ &tegra_clk_m,
+};
+
+static const char *mux_pllp_plld_pllc_clkm[] = {
+ "pllp",
+ "pll_d_out0",
+ "pll_c",
+ "clk_m",
+};
+
+static struct clk *mux_pllp_plld_pllc_clkm_p[] = {
+ &tegra_pll_p,
+ &tegra_pll_d_out0,
+ &tegra_pll_c,
+ &tegra_clk_m,
+};
+
+static const char *mux_pllp_pllc_audio_clkm_clk32[] = {
+ "pll_p",
+ "pll_c",
+ "audio",
+ "clk_m",
+ "clk_32k",
+};
+
+static struct clk *mux_pllp_pllc_audio_clkm_clk32_p[] = {
+ &tegra_pll_p,
+ &tegra_pll_c,
+ &tegra_audio,
+ &tegra_clk_m,
+ &tegra_clk_32k,
+};
+
+static const char *mux_pllp_pllc_pllm[] = {
+ "pll_p",
+ "pll_c",
+ "pll_m"
+};
+
+static struct clk *mux_pllp_pllc_pllm_p[] = {
+ &tegra_pll_p,
+ &tegra_pll_c,
+ &tegra_pll_m,
+};
+
+static const char *mux_clk_m[] = {
+ "clk_m",
+};
+
+static struct clk *mux_clk_m_p[] = {
+ &tegra_clk_m,
+};
+
+static const char *mux_pllp_out3[] = {
+ "pll_p_out3",
+};
+
+static struct clk *mux_pllp_out3_p[] = {
+ &tegra_pll_p_out3,
+};
+
+static const char *mux_plld[] = {
+ "pll_d",
+};
+
+static struct clk *mux_plld_p[] = {
+ &tegra_pll_d,
+};
+
+static const char *mux_clk_32k[] = {
+ "clk_32k",
+};
+
+static struct clk *mux_clk_32k_p[] = {
+ &tegra_clk_32k,
+};
+
+static const char *mux_pclk[] = {
+ "pclk",
+};
+
+static struct clk *mux_pclk_p[] = {
+ &tegra_pclk,
+};
+
+static struct clk tegra_emc;
+static struct clk_tegra tegra_emc_hw = {
+ .hw = {
+ .clk = &tegra_emc,
+ },
+ .reg = 0x19c,
+ .max_rate = 800000000,
+ .flags = MUX | DIV_U71 | PERIPH_EMC_ENB,
+ .reset = &tegra2_periph_clk_reset,
+ .u.periph = {
+ .clk_num = 57,
+ },
+};
+DEFINE_CLK_TEGRA(emc, 0, &tegra_emc_clk_ops, 0, mux_pllm_pllc_pllp_clkm,
+ mux_pllm_pllc_pllp_clkm_p, NULL);
+
+#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, \
+ _max, _inputs, _flags) \
+ static struct clk tegra_##_name; \
+ static struct clk_tegra tegra_##_name##_hw = { \
+ .hw = { \
+ .clk = &tegra_##_name, \
+ }, \
+ .lookup = { \
+ .dev_id = _dev, \
+ .con_id = _con, \
+ }, \
+ .reg = _reg, \
+ .flags = _flags, \
+ .max_rate = _max, \
+ .u.periph = { \
+ .clk_num = _clk_num, \
+ }, \
+ .reset = tegra2_periph_clk_reset, \
+ }; \
+ static struct clk tegra_##_name = { \
+ .name = #_name, \
+ .ops = &tegra_periph_clk_ops, \
+ .hw = &tegra_##_name##_hw.hw, \
+ .parent_names = _inputs, \
+ .parents = _inputs##_p, \
+ .num_parents = ARRAY_SIZE(_inputs), \
+ };
+
+PERIPH_CLK(apbdma, "tegra-apbdma", NULL, 34, 0, 108000000, mux_pclk, 0);
+PERIPH_CLK(rtc, "rtc-tegra", NULL, 4, 0, 32768, mux_clk_32k, PERIPH_NO_RESET);
+PERIPH_CLK(timer, "timer", NULL, 5, 0, 26000000, mux_clk_m, 0);
+PERIPH_CLK(i2s1, "tegra20-i2s.0", NULL, 11, 0x100, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71);
+PERIPH_CLK(i2s2, "tegra20-i2s.1", NULL, 18, 0x104, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71);
+PERIPH_CLK(spdif_out, "spdif_out", NULL, 10, 0x108, 100000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71);
+PERIPH_CLK(spdif_in, "spdif_in", NULL, 10, 0x10c, 100000000, mux_pllp_pllc_pllm, MUX | DIV_U71);
+PERIPH_CLK(pwm, "tegra-pwm", NULL, 17, 0x110, 432000000, mux_pllp_pllc_audio_clkm_clk32, MUX | DIV_U71 | MUX_PWM);
+PERIPH_CLK(spi, "spi", NULL, 43, 0x114, 40000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
+PERIPH_CLK(xio, "xio", NULL, 45, 0x120, 150000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
+PERIPH_CLK(twc, "twc", NULL, 16, 0x12c, 150000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
+PERIPH_CLK(sbc1, "spi_tegra.0", NULL, 41, 0x134, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
+PERIPH_CLK(sbc2, "spi_tegra.1", NULL, 44, 0x118, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
+PERIPH_CLK(sbc3, "spi_tegra.2", NULL, 46, 0x11c, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
+PERIPH_CLK(sbc4, "spi_tegra.3", NULL, 68, 0x1b4, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
+PERIPH_CLK(ide, "ide", NULL, 25, 0x144, 100000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(ndflash, "tegra_nand", NULL, 13, 0x160, 164000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(vfir, "vfir", NULL, 7, 0x168, 72000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
+PERIPH_CLK(sdmmc1, "sdhci-tegra.0", NULL, 14, 0x150, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(sdmmc2, "sdhci-tegra.1", NULL, 9, 0x154, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(sdmmc3, "sdhci-tegra.2", NULL, 69, 0x1bc, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(sdmmc4, "sdhci-tegra.3", NULL, 15, 0x164, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(vcp, "tegra-avp", "vcp", 29, 0, 250000000, mux_clk_m, 0);
+PERIPH_CLK(bsea, "tegra-avp", "bsea", 62, 0, 250000000, mux_clk_m, 0);
+PERIPH_CLK(bsev, "tegra-aes", "bsev", 63, 0, 250000000, mux_clk_m, 0);
+PERIPH_CLK(vde, "tegra-avp", "vde", 61, 0x1c8, 250000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage and process_id */
+PERIPH_CLK(csite, "csite", NULL, 73, 0x1d4, 144000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* max rate ??? */
+/* FIXME: what is la? */
+PERIPH_CLK(la, "la", NULL, 76, 0x1f8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
+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", "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);
+PERIPH_CLK(uartd, "tegra-uart.3", NULL, 65, 0x1c0, 600000000, mux_pllp_pllc_pllm_clkm, MUX);
+PERIPH_CLK(uarte, "tegra-uart.4", NULL, 66, 0x1c4, 600000000, mux_pllp_pllc_pllm_clkm, MUX);
+PERIPH_CLK(3d, "3d", NULL, 24, 0x158, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_MANUAL_RESET); /* scales with voltage and process_id */
+PERIPH_CLK(2d, "2d", NULL, 21, 0x15c, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71); /* scales with voltage and process_id */
+PERIPH_CLK(vi, "tegra_camera", "vi", 20, 0x148, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71); /* scales with voltage and process_id */
+PERIPH_CLK(vi_sensor, "tegra_camera", "vi_sensor", 20, 0x1a8, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_NO_RESET); /* scales with voltage and process_id */
+PERIPH_CLK(epp, "epp", NULL, 19, 0x16c, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71); /* scales with voltage and process_id */
+PERIPH_CLK(mpe, "mpe", NULL, 60, 0x170, 250000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71); /* scales with voltage and process_id */
+PERIPH_CLK(host1x, "host1x", NULL, 28, 0x180, 166000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71); /* scales with voltage and process_id */
+PERIPH_CLK(cve, "cve", NULL, 49, 0x140, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(tvo, "tvo", NULL, 49, 0x188, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(hdmi, "hdmi", NULL, 51, 0x18c, 600000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(tvdac, "tvdac", NULL, 53, 0x194, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(disp1, "tegradc.0", NULL, 27, 0x138, 600000000, mux_pllp_plld_pllc_clkm, MUX); /* scales with voltage and process_id */
+PERIPH_CLK(disp2, "tegradc.1", NULL, 26, 0x13c, 600000000, mux_pllp_plld_pllc_clkm, MUX); /* scales with voltage and process_id */
+PERIPH_CLK(usbd, "fsl-tegra-udc", NULL, 22, 0, 480000000, mux_clk_m, 0); /* requires min voltage */
+PERIPH_CLK(usb2, "tegra-ehci.1", NULL, 58, 0, 480000000, mux_clk_m, 0); /* requires min voltage */
+PERIPH_CLK(usb3, "tegra-ehci.2", NULL, 59, 0, 480000000, mux_clk_m, 0); /* requires min voltage */
+PERIPH_CLK(dsi, "dsi", NULL, 48, 0, 500000000, mux_plld, 0); /* scales with voltage */
+PERIPH_CLK(csi, "tegra_camera", "csi", 52, 0, 72000000, mux_pllp_out3, 0);
+PERIPH_CLK(isp, "tegra_camera", "isp", 23, 0, 150000000, mux_clk_m, 0); /* same frequency as VI */
+PERIPH_CLK(csus, "tegra_camera", "csus", 92, 0, 150000000, mux_clk_m, PERIPH_NO_RESET);
+PERIPH_CLK(pex, NULL, "pex", 70, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET);
+PERIPH_CLK(afi, NULL, "afi", 72, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET);
+PERIPH_CLK(pcie_xclk, NULL, "pcie_xclk", 74, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET);
+
+static struct clk *tegra_list_clks[] = {
+ &tegra_apbdma,
+ &tegra_rtc,
+ &tegra_i2s1,
+ &tegra_i2s2,
+ &tegra_spdif_out,
+ &tegra_spdif_in,
+ &tegra_pwm,
+ &tegra_spi,
+ &tegra_xio,
+ &tegra_twc,
+ &tegra_sbc1,
+ &tegra_sbc2,
+ &tegra_sbc3,
+ &tegra_sbc4,
+ &tegra_ide,
+ &tegra_ndflash,
+ &tegra_vfir,
+ &tegra_sdmmc1,
+ &tegra_sdmmc2,
+ &tegra_sdmmc3,
+ &tegra_sdmmc4,
+ &tegra_vcp,
+ &tegra_bsea,
+ &tegra_bsev,
+ &tegra_vde,
+ &tegra_csite,
+ &tegra_la,
+ &tegra_owr,
+ &tegra_nor,
+ &tegra_mipi,
+ &tegra_i2c1,
+ &tegra_i2c2,
+ &tegra_i2c3,
+ &tegra_dvc,
+ &tegra_uarta,
+ &tegra_uartb,
+ &tegra_uartc,
+ &tegra_uartd,
+ &tegra_uarte,
+ &tegra_3d,
+ &tegra_2d,
+ &tegra_vi,
+ &tegra_vi_sensor,
+ &tegra_epp,
+ &tegra_mpe,
+ &tegra_host1x,
+ &tegra_cve,
+ &tegra_tvo,
+ &tegra_hdmi,
+ &tegra_tvdac,
+ &tegra_disp1,
+ &tegra_disp2,
+ &tegra_usbd,
+ &tegra_usb2,
+ &tegra_usb3,
+ &tegra_dsi,
+ &tegra_csi,
+ &tegra_isp,
+ &tegra_csus,
+ &tegra_pex,
+ &tegra_afi,
+ &tegra_pcie_xclk,
+};
+
+#define CLK_DUPLICATE(_name, _dev, _con) \
+ { \
+ .name = _name, \
+ .lookup = { \
+ .dev_id = _dev, \
+ .con_id = _con, \
+ }, \
+ }
+
+/* Some clocks may be used by different drivers depending on the board
+ * configuration. List those here to register them twice in the clock lookup
+ * table under two names.
+ */
+static struct clk_duplicate tegra_clk_duplicates[] = {
+ CLK_DUPLICATE("uarta", "serial8250.0", NULL),
+ CLK_DUPLICATE("uartb", "serial8250.1", NULL),
+ CLK_DUPLICATE("uartc", "serial8250.2", NULL),
+ CLK_DUPLICATE("uartd", "serial8250.3", NULL),
+ CLK_DUPLICATE("uarte", "serial8250.4", NULL),
+ CLK_DUPLICATE("usbd", "utmip-pad", NULL),
+ CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),
+ CLK_DUPLICATE("usbd", "tegra-otg", NULL),
+ CLK_DUPLICATE("hdmi", "tegradc.0", "hdmi"),
+ CLK_DUPLICATE("hdmi", "tegradc.1", "hdmi"),
+ CLK_DUPLICATE("host1x", "tegra_grhost", "host1x"),
+ CLK_DUPLICATE("2d", "tegra_grhost", "gr2d"),
+ CLK_DUPLICATE("3d", "tegra_grhost", "gr3d"),
+ CLK_DUPLICATE("epp", "tegra_grhost", "epp"),
+ CLK_DUPLICATE("mpe", "tegra_grhost", "mpe"),
+ CLK_DUPLICATE("cop", "tegra-avp", "cop"),
+ 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) \
+ { \
+ .dev_id = dev, \
+ .con_id = con, \
+ .clk = ck, \
+ }
+
+static struct clk *tegra_ptr_clks[] = {
+ &tegra_clk_32k,
+ &tegra_pll_s,
+ &tegra_clk_m,
+ &tegra_pll_m,
+ &tegra_pll_m_out1,
+ &tegra_pll_c,
+ &tegra_pll_c_out1,
+ &tegra_pll_p,
+ &tegra_pll_p_out1,
+ &tegra_pll_p_out2,
+ &tegra_pll_p_out3,
+ &tegra_pll_p_out4,
+ &tegra_pll_a,
+ &tegra_pll_a_out0,
+ &tegra_pll_d,
+ &tegra_pll_d_out0,
+ &tegra_pll_u,
+ &tegra_pll_x,
+ &tegra_pll_e,
+ &tegra_cclk,
+ &tegra_clk_twd,
+ &tegra_sclk,
+ &tegra_hclk,
+ &tegra_pclk,
+ &tegra_clk_d,
+ &tegra_cdev1,
+ &tegra_cdev2,
+ &tegra_blink,
+ &tegra_cop,
+ &tegra_emc,
+};
+
+static void tegra2_init_one_clock(struct clk *c)
+{
+ struct clk_tegra *clk = to_clk_tegra(c->hw);
+ int ret;
+
+ ret = __clk_init(NULL, c);
+ if (ret)
+ pr_err("clk init failed %s\n", __clk_get_name(c));
+
+ INIT_LIST_HEAD(&clk->shared_bus_list);
+ if (!clk->lookup.dev_id && !clk->lookup.con_id)
+ clk->lookup.con_id = c->name;
+ clk->lookup.clk = c;
+ clkdev_add(&clk->lookup);
+ tegra_clk_add(c);
+}
+
+void __init tegra2_init_clocks(void)
+{
+ int i;
+ struct clk *c;
+
+ for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++)
+ tegra2_init_one_clock(tegra_ptr_clks[i]);
+
+ for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++)
+ tegra2_init_one_clock(tegra_list_clks[i]);
+
+ for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) {
+ c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name);
+ if (!c) {
+ pr_err("%s: Unknown duplicate clock %s\n", __func__,
+ tegra_clk_duplicates[i].name);
+ continue;
+ }
+
+ tegra_clk_duplicates[i].lookup.clk = c;
+ clkdev_add(&tegra_clk_duplicates[i].lookup);
+ }
+
+ init_audio_sync_clock_mux();
+}
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
deleted file mode 100644
index a703844b2061..000000000000
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ /dev/null
@@ -1,2484 +0,0 @@
-/*
- * arch/arm/mach-tegra/tegra2_clocks.c
- *
- * Copyright (C) 2010 Google, Inc.
- *
- * Author:
- * Colin Cross <ccross@google.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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/kernel.h>
-#include <linux/module.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/clkdev.h>
-#include <linux/clk.h>
-
-#include <mach/iomap.h>
-#include <mach/suspend.h>
-
-#include "clock.h"
-#include "fuse.h"
-#include "tegra2_emc.h"
-
-#define RST_DEVICES 0x004
-#define RST_DEVICES_SET 0x300
-#define RST_DEVICES_CLR 0x304
-#define RST_DEVICES_NUM 3
-
-#define CLK_OUT_ENB 0x010
-#define CLK_OUT_ENB_SET 0x320
-#define CLK_OUT_ENB_CLR 0x324
-#define CLK_OUT_ENB_NUM 3
-
-#define CLK_MASK_ARM 0x44
-#define MISC_CLK_ENB 0x48
-
-#define OSC_CTRL 0x50
-#define OSC_CTRL_OSC_FREQ_MASK (3<<30)
-#define OSC_CTRL_OSC_FREQ_13MHZ (0<<30)
-#define OSC_CTRL_OSC_FREQ_19_2MHZ (1<<30)
-#define OSC_CTRL_OSC_FREQ_12MHZ (2<<30)
-#define OSC_CTRL_OSC_FREQ_26MHZ (3<<30)
-#define OSC_CTRL_MASK (0x3f2 | OSC_CTRL_OSC_FREQ_MASK)
-
-#define OSC_FREQ_DET 0x58
-#define OSC_FREQ_DET_TRIG (1<<31)
-
-#define OSC_FREQ_DET_STATUS 0x5C
-#define OSC_FREQ_DET_BUSY (1<<31)
-#define OSC_FREQ_DET_CNT_MASK 0xFFFF
-
-#define PERIPH_CLK_SOURCE_I2S1 0x100
-#define PERIPH_CLK_SOURCE_EMC 0x19c
-#define PERIPH_CLK_SOURCE_OSC 0x1fc
-#define PERIPH_CLK_SOURCE_NUM \
- ((PERIPH_CLK_SOURCE_OSC - PERIPH_CLK_SOURCE_I2S1) / 4)
-
-#define PERIPH_CLK_SOURCE_MASK (3<<30)
-#define PERIPH_CLK_SOURCE_SHIFT 30
-#define PERIPH_CLK_SOURCE_PWM_MASK (7<<28)
-#define PERIPH_CLK_SOURCE_PWM_SHIFT 28
-#define PERIPH_CLK_SOURCE_ENABLE (1<<28)
-#define PERIPH_CLK_SOURCE_DIVU71_MASK 0xFF
-#define PERIPH_CLK_SOURCE_DIVU16_MASK 0xFFFF
-#define PERIPH_CLK_SOURCE_DIV_SHIFT 0
-
-#define SDMMC_CLK_INT_FB_SEL (1 << 23)
-#define SDMMC_CLK_INT_FB_DLY_SHIFT 16
-#define SDMMC_CLK_INT_FB_DLY_MASK (0xF << SDMMC_CLK_INT_FB_DLY_SHIFT)
-
-#define PLL_BASE 0x0
-#define PLL_BASE_BYPASS (1<<31)
-#define PLL_BASE_ENABLE (1<<30)
-#define PLL_BASE_REF_ENABLE (1<<29)
-#define PLL_BASE_OVERRIDE (1<<28)
-#define PLL_BASE_DIVP_MASK (0x7<<20)
-#define PLL_BASE_DIVP_SHIFT 20
-#define PLL_BASE_DIVN_MASK (0x3FF<<8)
-#define PLL_BASE_DIVN_SHIFT 8
-#define PLL_BASE_DIVM_MASK (0x1F)
-#define PLL_BASE_DIVM_SHIFT 0
-
-#define PLL_OUT_RATIO_MASK (0xFF<<8)
-#define PLL_OUT_RATIO_SHIFT 8
-#define PLL_OUT_OVERRIDE (1<<2)
-#define PLL_OUT_CLKEN (1<<1)
-#define PLL_OUT_RESET_DISABLE (1<<0)
-
-#define PLL_MISC(c) (((c)->flags & PLL_ALT_MISC_REG) ? 0x4 : 0xc)
-
-#define PLL_MISC_DCCON_SHIFT 20
-#define PLL_MISC_CPCON_SHIFT 8
-#define PLL_MISC_CPCON_MASK (0xF<<PLL_MISC_CPCON_SHIFT)
-#define PLL_MISC_LFCON_SHIFT 4
-#define PLL_MISC_LFCON_MASK (0xF<<PLL_MISC_LFCON_SHIFT)
-#define PLL_MISC_VCOCON_SHIFT 0
-#define PLL_MISC_VCOCON_MASK (0xF<<PLL_MISC_VCOCON_SHIFT)
-
-#define PLLU_BASE_POST_DIV (1<<20)
-
-#define PLLD_MISC_CLKENABLE (1<<30)
-#define PLLD_MISC_DIV_RST (1<<23)
-#define PLLD_MISC_DCCON_SHIFT 12
-
-#define PLLE_MISC_READY (1 << 15)
-
-#define PERIPH_CLK_TO_ENB_REG(c) ((c->u.periph.clk_num / 32) * 4)
-#define PERIPH_CLK_TO_ENB_SET_REG(c) ((c->u.periph.clk_num / 32) * 8)
-#define PERIPH_CLK_TO_ENB_BIT(c) (1 << (c->u.periph.clk_num % 32))
-
-#define SUPER_CLK_MUX 0x00
-#define SUPER_STATE_SHIFT 28
-#define SUPER_STATE_MASK (0xF << SUPER_STATE_SHIFT)
-#define SUPER_STATE_STANDBY (0x0 << SUPER_STATE_SHIFT)
-#define SUPER_STATE_IDLE (0x1 << SUPER_STATE_SHIFT)
-#define SUPER_STATE_RUN (0x2 << SUPER_STATE_SHIFT)
-#define SUPER_STATE_IRQ (0x3 << SUPER_STATE_SHIFT)
-#define SUPER_STATE_FIQ (0x4 << SUPER_STATE_SHIFT)
-#define SUPER_SOURCE_MASK 0xF
-#define SUPER_FIQ_SOURCE_SHIFT 12
-#define SUPER_IRQ_SOURCE_SHIFT 8
-#define SUPER_RUN_SOURCE_SHIFT 4
-#define SUPER_IDLE_SOURCE_SHIFT 0
-
-#define SUPER_CLK_DIVIDER 0x04
-
-#define BUS_CLK_DISABLE (1<<3)
-#define BUS_CLK_DIV_MASK 0x3
-
-#define PMC_CTRL 0x0
- #define PMC_CTRL_BLINK_ENB (1 << 7)
-
-#define PMC_DPD_PADS_ORIDE 0x1c
- #define PMC_DPD_PADS_ORIDE_BLINK_ENB (1 << 20)
-
-#define PMC_BLINK_TIMER_DATA_ON_SHIFT 0
-#define PMC_BLINK_TIMER_DATA_ON_MASK 0x7fff
-#define PMC_BLINK_TIMER_ENB (1 << 15)
-#define PMC_BLINK_TIMER_DATA_OFF_SHIFT 16
-#define PMC_BLINK_TIMER_DATA_OFF_MASK 0xffff
-
-static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
-static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
-
-/*
- * Some clocks share a register with other clocks. Any clock op that
- * non-atomically modifies a register used by another clock must lock
- * clock_register_lock first.
- */
-static DEFINE_SPINLOCK(clock_register_lock);
-
-/*
- * Some peripheral clocks share an enable bit, so refcount the enable bits
- * in registers CLK_ENABLE_L, CLK_ENABLE_H, and CLK_ENABLE_U
- */
-static int tegra_periph_clk_enable_refcount[3 * 32];
-
-#define clk_writel(value, reg) \
- __raw_writel(value, reg_clk_base + (reg))
-#define clk_readl(reg) \
- __raw_readl(reg_clk_base + (reg))
-#define pmc_writel(value, reg) \
- __raw_writel(value, reg_pmc_base + (reg))
-#define pmc_readl(reg) \
- __raw_readl(reg_pmc_base + (reg))
-
-static unsigned long clk_measure_input_freq(void)
-{
- u32 clock_autodetect;
- clk_writel(OSC_FREQ_DET_TRIG | 1, OSC_FREQ_DET);
- do {} while (clk_readl(OSC_FREQ_DET_STATUS) & OSC_FREQ_DET_BUSY);
- clock_autodetect = clk_readl(OSC_FREQ_DET_STATUS);
- if (clock_autodetect >= 732 - 3 && clock_autodetect <= 732 + 3) {
- return 12000000;
- } else if (clock_autodetect >= 794 - 3 && clock_autodetect <= 794 + 3) {
- return 13000000;
- } else if (clock_autodetect >= 1172 - 3 && clock_autodetect <= 1172 + 3) {
- return 19200000;
- } else if (clock_autodetect >= 1587 - 3 && clock_autodetect <= 1587 + 3) {
- return 26000000;
- } else {
- pr_err("%s: Unexpected clock autodetect value %d", __func__, clock_autodetect);
- BUG();
- return 0;
- }
-}
-
-static int clk_div71_get_divider(unsigned long parent_rate, unsigned long rate)
-{
- s64 divider_u71 = parent_rate * 2;
- divider_u71 += rate - 1;
- do_div(divider_u71, rate);
-
- if (divider_u71 - 2 < 0)
- return 0;
-
- if (divider_u71 - 2 > 255)
- return -EINVAL;
-
- return divider_u71 - 2;
-}
-
-static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate)
-{
- s64 divider_u16;
-
- divider_u16 = parent_rate;
- divider_u16 += rate - 1;
- do_div(divider_u16, rate);
-
- if (divider_u16 - 1 < 0)
- return 0;
-
- if (divider_u16 - 1 > 255)
- return -EINVAL;
-
- return divider_u16 - 1;
-}
-
-/* clk_m functions */
-static unsigned long tegra2_clk_m_autodetect_rate(struct clk *c)
-{
- u32 auto_clock_control = clk_readl(OSC_CTRL) & ~OSC_CTRL_OSC_FREQ_MASK;
-
- c->rate = clk_measure_input_freq();
- switch (c->rate) {
- case 12000000:
- auto_clock_control |= OSC_CTRL_OSC_FREQ_12MHZ;
- break;
- case 13000000:
- auto_clock_control |= OSC_CTRL_OSC_FREQ_13MHZ;
- break;
- case 19200000:
- auto_clock_control |= OSC_CTRL_OSC_FREQ_19_2MHZ;
- break;
- case 26000000:
- auto_clock_control |= OSC_CTRL_OSC_FREQ_26MHZ;
- break;
- default:
- pr_err("%s: Unexpected clock rate %ld", __func__, c->rate);
- BUG();
- }
- clk_writel(auto_clock_control, OSC_CTRL);
- return c->rate;
-}
-
-static void tegra2_clk_m_init(struct clk *c)
-{
- pr_debug("%s on clock %s\n", __func__, c->name);
- tegra2_clk_m_autodetect_rate(c);
-}
-
-static int tegra2_clk_m_enable(struct clk *c)
-{
- pr_debug("%s on clock %s\n", __func__, c->name);
- return 0;
-}
-
-static void tegra2_clk_m_disable(struct clk *c)
-{
- pr_debug("%s on clock %s\n", __func__, c->name);
- BUG();
-}
-
-static struct clk_ops tegra_clk_m_ops = {
- .init = tegra2_clk_m_init,
- .enable = tegra2_clk_m_enable,
- .disable = tegra2_clk_m_disable,
-};
-
-/* super clock functions */
-/* "super clocks" on tegra have two-stage muxes and a clock skipping
- * super divider. We will ignore the clock skipping divider, since we
- * can't lower the voltage when using the clock skip, but we can if we
- * lower the PLL frequency.
- */
-static void tegra2_super_clk_init(struct clk *c)
-{
- u32 val;
- int source;
- int shift;
- const struct clk_mux_sel *sel;
- val = clk_readl(c->reg + SUPER_CLK_MUX);
- c->state = ON;
- BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
- ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
- shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
- SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
- source = (val >> shift) & SUPER_SOURCE_MASK;
- for (sel = c->inputs; sel->input != NULL; sel++) {
- if (sel->value == source)
- break;
- }
- BUG_ON(sel->input == NULL);
- c->parent = sel->input;
-}
-
-static int tegra2_super_clk_enable(struct clk *c)
-{
- clk_writel(0, c->reg + SUPER_CLK_DIVIDER);
- return 0;
-}
-
-static void tegra2_super_clk_disable(struct clk *c)
-{
- pr_debug("%s on clock %s\n", __func__, c->name);
-
- /* oops - don't disable the CPU clock! */
- BUG();
-}
-
-static int tegra2_super_clk_set_parent(struct clk *c, struct clk *p)
-{
- u32 val;
- const struct clk_mux_sel *sel;
- int shift;
-
- val = clk_readl(c->reg + SUPER_CLK_MUX);
- BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
- ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
- shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
- SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
- for (sel = c->inputs; sel->input != NULL; sel++) {
- if (sel->input == p) {
- val &= ~(SUPER_SOURCE_MASK << shift);
- val |= sel->value << shift;
-
- if (c->refcnt)
- clk_enable(p);
-
- clk_writel(val, c->reg);
-
- if (c->refcnt && c->parent)
- clk_disable(c->parent);
-
- clk_reparent(c, p);
- return 0;
- }
- }
- return -EINVAL;
-}
-
-/*
- * Super clocks have "clock skippers" instead of dividers. Dividing using
- * a clock skipper does not allow the voltage to be scaled down, so instead
- * adjust the rate of the parent clock. This requires that the parent of a
- * super clock have no other children, otherwise the rate will change
- * underneath the other children.
- */
-static int tegra2_super_clk_set_rate(struct clk *c, unsigned long rate)
-{
- return clk_set_rate(c->parent, rate);
-}
-
-static struct clk_ops tegra_super_ops = {
- .init = tegra2_super_clk_init,
- .enable = tegra2_super_clk_enable,
- .disable = tegra2_super_clk_disable,
- .set_parent = tegra2_super_clk_set_parent,
- .set_rate = tegra2_super_clk_set_rate,
-};
-
-/* virtual cpu clock functions */
-/* some clocks can not be stopped (cpu, memory bus) while the SoC is running.
- To change the frequency of these clocks, the parent pll may need to be
- reprogrammed, so the clock must be moved off the pll, the pll reprogrammed,
- and then the clock moved back to the pll. To hide this sequence, a virtual
- clock handles it.
- */
-static void tegra2_cpu_clk_init(struct clk *c)
-{
-}
-
-static int tegra2_cpu_clk_enable(struct clk *c)
-{
- return 0;
-}
-
-static void tegra2_cpu_clk_disable(struct clk *c)
-{
- pr_debug("%s on clock %s\n", __func__, c->name);
-
- /* oops - don't disable the CPU clock! */
- BUG();
-}
-
-static int tegra2_cpu_clk_set_rate(struct clk *c, unsigned long rate)
-{
- int ret;
- /*
- * Take an extra reference to the main pll so it doesn't turn
- * off when we move the cpu off of it
- */
- clk_enable(c->u.cpu.main);
-
- ret = clk_set_parent(c->parent, c->u.cpu.backup);
- if (ret) {
- pr_err("Failed to switch cpu to clock %s\n", c->u.cpu.backup->name);
- goto out;
- }
-
- if (rate == clk_get_rate(c->u.cpu.backup))
- goto out;
-
- ret = clk_set_rate(c->u.cpu.main, rate);
- if (ret) {
- pr_err("Failed to change cpu pll to %lu\n", rate);
- goto out;
- }
-
- ret = clk_set_parent(c->parent, c->u.cpu.main);
- if (ret) {
- pr_err("Failed to switch cpu to clock %s\n", c->u.cpu.main->name);
- goto out;
- }
-
-out:
- clk_disable(c->u.cpu.main);
- return ret;
-}
-
-static struct clk_ops tegra_cpu_ops = {
- .init = tegra2_cpu_clk_init,
- .enable = tegra2_cpu_clk_enable,
- .disable = tegra2_cpu_clk_disable,
- .set_rate = tegra2_cpu_clk_set_rate,
-};
-
-/* virtual cop clock functions. Used to acquire the fake 'cop' clock to
- * reset the COP block (i.e. AVP) */
-static void tegra2_cop_clk_reset(struct clk *c, bool assert)
-{
- unsigned long reg = assert ? RST_DEVICES_SET : RST_DEVICES_CLR;
-
- pr_debug("%s %s\n", __func__, assert ? "assert" : "deassert");
- clk_writel(1 << 1, reg);
-}
-
-static struct clk_ops tegra_cop_ops = {
- .reset = tegra2_cop_clk_reset,
-};
-
-/* bus clock functions */
-static void tegra2_bus_clk_init(struct clk *c)
-{
- u32 val = clk_readl(c->reg);
- c->state = ((val >> c->reg_shift) & BUS_CLK_DISABLE) ? OFF : ON;
- c->div = ((val >> c->reg_shift) & BUS_CLK_DIV_MASK) + 1;
- c->mul = 1;
-}
-
-static int tegra2_bus_clk_enable(struct clk *c)
-{
- u32 val;
- unsigned long flags;
-
- spin_lock_irqsave(&clock_register_lock, flags);
-
- val = clk_readl(c->reg);
- val &= ~(BUS_CLK_DISABLE << c->reg_shift);
- clk_writel(val, c->reg);
-
- spin_unlock_irqrestore(&clock_register_lock, flags);
-
- return 0;
-}
-
-static void tegra2_bus_clk_disable(struct clk *c)
-{
- u32 val;
- unsigned long flags;
-
- spin_lock_irqsave(&clock_register_lock, flags);
-
- val = clk_readl(c->reg);
- val |= BUS_CLK_DISABLE << c->reg_shift;
- clk_writel(val, c->reg);
-
- spin_unlock_irqrestore(&clock_register_lock, flags);
-}
-
-static int tegra2_bus_clk_set_rate(struct clk *c, unsigned long rate)
-{
- u32 val;
- unsigned long parent_rate = clk_get_rate(c->parent);
- unsigned long flags;
- int ret = -EINVAL;
- int i;
-
- spin_lock_irqsave(&clock_register_lock, flags);
-
- val = clk_readl(c->reg);
- for (i = 1; i <= 4; i++) {
- if (rate == parent_rate / i) {
- val &= ~(BUS_CLK_DIV_MASK << c->reg_shift);
- val |= (i - 1) << c->reg_shift;
- clk_writel(val, c->reg);
- c->div = i;
- c->mul = 1;
- ret = 0;
- break;
- }
- }
-
- spin_unlock_irqrestore(&clock_register_lock, flags);
-
- return ret;
-}
-
-static struct clk_ops tegra_bus_ops = {
- .init = tegra2_bus_clk_init,
- .enable = tegra2_bus_clk_enable,
- .disable = tegra2_bus_clk_disable,
- .set_rate = tegra2_bus_clk_set_rate,
-};
-
-/* Blink output functions */
-
-static void tegra2_blink_clk_init(struct clk *c)
-{
- u32 val;
-
- val = pmc_readl(PMC_CTRL);
- c->state = (val & PMC_CTRL_BLINK_ENB) ? ON : OFF;
- c->mul = 1;
- val = pmc_readl(c->reg);
-
- if (val & PMC_BLINK_TIMER_ENB) {
- unsigned int on_off;
-
- on_off = (val >> PMC_BLINK_TIMER_DATA_ON_SHIFT) &
- PMC_BLINK_TIMER_DATA_ON_MASK;
- val >>= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
- val &= PMC_BLINK_TIMER_DATA_OFF_MASK;
- on_off += val;
- /* each tick in the blink timer is 4 32KHz clocks */
- c->div = on_off * 4;
- } else {
- c->div = 1;
- }
-}
-
-static int tegra2_blink_clk_enable(struct clk *c)
-{
- u32 val;
-
- val = pmc_readl(PMC_DPD_PADS_ORIDE);
- pmc_writel(val | PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
-
- val = pmc_readl(PMC_CTRL);
- pmc_writel(val | PMC_CTRL_BLINK_ENB, PMC_CTRL);
-
- return 0;
-}
-
-static void tegra2_blink_clk_disable(struct clk *c)
-{
- u32 val;
-
- val = pmc_readl(PMC_CTRL);
- pmc_writel(val & ~PMC_CTRL_BLINK_ENB, PMC_CTRL);
-
- val = pmc_readl(PMC_DPD_PADS_ORIDE);
- pmc_writel(val & ~PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
-}
-
-static int tegra2_blink_clk_set_rate(struct clk *c, unsigned long rate)
-{
- unsigned long parent_rate = clk_get_rate(c->parent);
- if (rate >= parent_rate) {
- c->div = 1;
- pmc_writel(0, c->reg);
- } else {
- unsigned int on_off;
- u32 val;
-
- on_off = DIV_ROUND_UP(parent_rate / 8, rate);
- c->div = on_off * 8;
-
- val = (on_off & PMC_BLINK_TIMER_DATA_ON_MASK) <<
- PMC_BLINK_TIMER_DATA_ON_SHIFT;
- on_off &= PMC_BLINK_TIMER_DATA_OFF_MASK;
- on_off <<= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
- val |= on_off;
- val |= PMC_BLINK_TIMER_ENB;
- pmc_writel(val, c->reg);
- }
-
- return 0;
-}
-
-static struct clk_ops tegra_blink_clk_ops = {
- .init = &tegra2_blink_clk_init,
- .enable = &tegra2_blink_clk_enable,
- .disable = &tegra2_blink_clk_disable,
- .set_rate = &tegra2_blink_clk_set_rate,
-};
-
-/* PLL Functions */
-static int tegra2_pll_clk_wait_for_lock(struct clk *c)
-{
- udelay(c->u.pll.lock_delay);
-
- return 0;
-}
-
-static void tegra2_pll_clk_init(struct clk *c)
-{
- u32 val = clk_readl(c->reg + PLL_BASE);
-
- c->state = (val & PLL_BASE_ENABLE) ? ON : OFF;
-
- if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) {
- pr_warning("Clock %s has unknown fixed frequency\n", c->name);
- c->mul = 1;
- c->div = 1;
- } else if (val & PLL_BASE_BYPASS) {
- c->mul = 1;
- c->div = 1;
- } else {
- c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT;
- c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT;
- if (c->flags & PLLU)
- c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2;
- else
- c->div *= (val & PLL_BASE_DIVP_MASK) ? 2 : 1;
- }
-}
-
-static int tegra2_pll_clk_enable(struct clk *c)
-{
- u32 val;
- pr_debug("%s on clock %s\n", __func__, c->name);
-
- val = clk_readl(c->reg + PLL_BASE);
- val &= ~PLL_BASE_BYPASS;
- val |= PLL_BASE_ENABLE;
- clk_writel(val, c->reg + PLL_BASE);
-
- tegra2_pll_clk_wait_for_lock(c);
-
- return 0;
-}
-
-static void tegra2_pll_clk_disable(struct clk *c)
-{
- u32 val;
- pr_debug("%s on clock %s\n", __func__, c->name);
-
- val = clk_readl(c->reg);
- val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
- clk_writel(val, c->reg);
-}
-
-static int tegra2_pll_clk_set_rate(struct clk *c, unsigned long rate)
-{
- u32 val;
- unsigned long input_rate;
- const struct clk_pll_freq_table *sel;
-
- pr_debug("%s: %s %lu\n", __func__, c->name, rate);
-
- input_rate = clk_get_rate(c->parent);
- for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
- if (sel->input_rate == input_rate && sel->output_rate == rate) {
- c->mul = sel->n;
- c->div = sel->m * sel->p;
-
- val = clk_readl(c->reg + PLL_BASE);
- if (c->flags & PLL_FIXED)
- val |= PLL_BASE_OVERRIDE;
- val &= ~(PLL_BASE_DIVP_MASK | PLL_BASE_DIVN_MASK |
- PLL_BASE_DIVM_MASK);
- val |= (sel->m << PLL_BASE_DIVM_SHIFT) |
- (sel->n << PLL_BASE_DIVN_SHIFT);
- BUG_ON(sel->p < 1 || sel->p > 2);
- if (c->flags & PLLU) {
- if (sel->p == 1)
- val |= PLLU_BASE_POST_DIV;
- } else {
- if (sel->p == 2)
- val |= 1 << PLL_BASE_DIVP_SHIFT;
- }
- clk_writel(val, c->reg + PLL_BASE);
-
- if (c->flags & PLL_HAS_CPCON) {
- val = clk_readl(c->reg + PLL_MISC(c));
- val &= ~PLL_MISC_CPCON_MASK;
- val |= sel->cpcon << PLL_MISC_CPCON_SHIFT;
- clk_writel(val, c->reg + PLL_MISC(c));
- }
-
- if (c->state == ON)
- tegra2_pll_clk_enable(c);
-
- return 0;
- }
- }
- return -EINVAL;
-}
-
-static struct clk_ops tegra_pll_ops = {
- .init = tegra2_pll_clk_init,
- .enable = tegra2_pll_clk_enable,
- .disable = tegra2_pll_clk_disable,
- .set_rate = tegra2_pll_clk_set_rate,
-};
-
-static void tegra2_pllx_clk_init(struct clk *c)
-{
- tegra2_pll_clk_init(c);
-
- if (tegra_sku_id == 7)
- c->max_rate = 750000000;
-}
-
-static struct clk_ops tegra_pllx_ops = {
- .init = tegra2_pllx_clk_init,
- .enable = tegra2_pll_clk_enable,
- .disable = tegra2_pll_clk_disable,
- .set_rate = tegra2_pll_clk_set_rate,
-};
-
-static int tegra2_plle_clk_enable(struct clk *c)
-{
- u32 val;
-
- pr_debug("%s on clock %s\n", __func__, c->name);
-
- mdelay(1);
-
- val = clk_readl(c->reg + PLL_BASE);
- if (!(val & PLLE_MISC_READY))
- return -EBUSY;
-
- val = clk_readl(c->reg + PLL_BASE);
- val |= PLL_BASE_ENABLE | PLL_BASE_BYPASS;
- clk_writel(val, c->reg + PLL_BASE);
-
- return 0;
-}
-
-static struct clk_ops tegra_plle_ops = {
- .init = tegra2_pll_clk_init,
- .enable = tegra2_plle_clk_enable,
- .set_rate = tegra2_pll_clk_set_rate,
-};
-
-/* Clock divider ops */
-static void tegra2_pll_div_clk_init(struct clk *c)
-{
- u32 val = clk_readl(c->reg);
- u32 divu71;
- val >>= c->reg_shift;
- c->state = (val & PLL_OUT_CLKEN) ? ON : OFF;
- if (!(val & PLL_OUT_RESET_DISABLE))
- c->state = OFF;
-
- if (c->flags & DIV_U71) {
- divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT;
- c->div = (divu71 + 2);
- c->mul = 2;
- } else if (c->flags & DIV_2) {
- c->div = 2;
- c->mul = 1;
- } else {
- c->div = 1;
- c->mul = 1;
- }
-}
-
-static int tegra2_pll_div_clk_enable(struct clk *c)
-{
- u32 val;
- u32 new_val;
- unsigned long flags;
-
- pr_debug("%s: %s\n", __func__, c->name);
- if (c->flags & DIV_U71) {
- spin_lock_irqsave(&clock_register_lock, flags);
- val = clk_readl(c->reg);
- new_val = val >> c->reg_shift;
- new_val &= 0xFFFF;
-
- new_val |= PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE;
-
- val &= ~(0xFFFF << c->reg_shift);
- val |= new_val << c->reg_shift;
- clk_writel(val, c->reg);
- spin_unlock_irqrestore(&clock_register_lock, flags);
- return 0;
- } else if (c->flags & DIV_2) {
- BUG_ON(!(c->flags & PLLD));
- spin_lock_irqsave(&clock_register_lock, flags);
- val = clk_readl(c->reg);
- val &= ~PLLD_MISC_DIV_RST;
- clk_writel(val, c->reg);
- spin_unlock_irqrestore(&clock_register_lock, flags);
- return 0;
- }
- return -EINVAL;
-}
-
-static void tegra2_pll_div_clk_disable(struct clk *c)
-{
- u32 val;
- u32 new_val;
- unsigned long flags;
-
- pr_debug("%s: %s\n", __func__, c->name);
- if (c->flags & DIV_U71) {
- spin_lock_irqsave(&clock_register_lock, flags);
- val = clk_readl(c->reg);
- new_val = val >> c->reg_shift;
- new_val &= 0xFFFF;
-
- new_val &= ~(PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE);
-
- val &= ~(0xFFFF << c->reg_shift);
- val |= new_val << c->reg_shift;
- clk_writel(val, c->reg);
- spin_unlock_irqrestore(&clock_register_lock, flags);
- } else if (c->flags & DIV_2) {
- BUG_ON(!(c->flags & PLLD));
- spin_lock_irqsave(&clock_register_lock, flags);
- val = clk_readl(c->reg);
- val |= PLLD_MISC_DIV_RST;
- clk_writel(val, c->reg);
- spin_unlock_irqrestore(&clock_register_lock, flags);
- }
-}
-
-static int tegra2_pll_div_clk_set_rate(struct clk *c, unsigned long rate)
-{
- u32 val;
- u32 new_val;
- int divider_u71;
- unsigned long parent_rate = clk_get_rate(c->parent);
- unsigned long flags;
-
- pr_debug("%s: %s %lu\n", __func__, c->name, rate);
- if (c->flags & DIV_U71) {
- divider_u71 = clk_div71_get_divider(parent_rate, rate);
- if (divider_u71 >= 0) {
- spin_lock_irqsave(&clock_register_lock, flags);
- val = clk_readl(c->reg);
- new_val = val >> c->reg_shift;
- new_val &= 0xFFFF;
- if (c->flags & DIV_U71_FIXED)
- new_val |= PLL_OUT_OVERRIDE;
- new_val &= ~PLL_OUT_RATIO_MASK;
- new_val |= divider_u71 << PLL_OUT_RATIO_SHIFT;
-
- val &= ~(0xFFFF << c->reg_shift);
- val |= new_val << c->reg_shift;
- clk_writel(val, c->reg);
- c->div = divider_u71 + 2;
- c->mul = 2;
- spin_unlock_irqrestore(&clock_register_lock, flags);
- return 0;
- }
- } else if (c->flags & DIV_2) {
- if (parent_rate == rate * 2)
- return 0;
- }
- return -EINVAL;
-}
-
-static long tegra2_pll_div_clk_round_rate(struct clk *c, unsigned long rate)
-{
- int divider;
- unsigned long parent_rate = clk_get_rate(c->parent);
- pr_debug("%s: %s %lu\n", __func__, c->name, rate);
-
- if (c->flags & DIV_U71) {
- divider = clk_div71_get_divider(parent_rate, rate);
- if (divider < 0)
- return divider;
- return DIV_ROUND_UP(parent_rate * 2, divider + 2);
- } else if (c->flags & DIV_2) {
- return DIV_ROUND_UP(parent_rate, 2);
- }
- return -EINVAL;
-}
-
-static struct clk_ops tegra_pll_div_ops = {
- .init = tegra2_pll_div_clk_init,
- .enable = tegra2_pll_div_clk_enable,
- .disable = tegra2_pll_div_clk_disable,
- .set_rate = tegra2_pll_div_clk_set_rate,
- .round_rate = tegra2_pll_div_clk_round_rate,
-};
-
-/* Periph clk ops */
-
-static void tegra2_periph_clk_init(struct clk *c)
-{
- u32 val = clk_readl(c->reg);
- const struct clk_mux_sel *mux = NULL;
- const struct clk_mux_sel *sel;
- u32 shift;
- u32 mask;
-
- if (c->flags & MUX_PWM) {
- shift = PERIPH_CLK_SOURCE_PWM_SHIFT;
- mask = PERIPH_CLK_SOURCE_PWM_MASK;
- } else {
- shift = PERIPH_CLK_SOURCE_SHIFT;
- mask = PERIPH_CLK_SOURCE_MASK;
- }
-
- if (c->flags & MUX) {
- for (sel = c->inputs; sel->input != NULL; sel++) {
- if ((val & mask) >> shift == sel->value)
- mux = sel;
- }
- BUG_ON(!mux);
-
- c->parent = mux->input;
- } else {
- c->parent = c->inputs[0].input;
- }
-
- if (c->flags & DIV_U71) {
- u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
- c->div = divu71 + 2;
- c->mul = 2;
- } else if (c->flags & DIV_U16) {
- u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK;
- c->div = divu16 + 1;
- c->mul = 1;
- } else {
- c->div = 1;
- c->mul = 1;
- }
-
- c->state = ON;
-
- if (!c->u.periph.clk_num)
- return;
-
- if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
- PERIPH_CLK_TO_ENB_BIT(c)))
- c->state = OFF;
-
- if (!(c->flags & PERIPH_NO_RESET))
- if (clk_readl(RST_DEVICES + PERIPH_CLK_TO_ENB_REG(c)) &
- PERIPH_CLK_TO_ENB_BIT(c))
- c->state = OFF;
-}
-
-static int tegra2_periph_clk_enable(struct clk *c)
-{
- u32 val;
- unsigned long flags;
- int refcount;
- pr_debug("%s on clock %s\n", __func__, c->name);
-
- if (!c->u.periph.clk_num)
- return 0;
-
- spin_lock_irqsave(&clock_register_lock, flags);
-
- refcount = tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++;
-
- if (refcount > 1)
- goto out;
-
- clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
- CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c));
- if (!(c->flags & PERIPH_NO_RESET) && !(c->flags & PERIPH_MANUAL_RESET))
- clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
- RST_DEVICES_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
- if (c->flags & PERIPH_EMC_ENB) {
- /* The EMC peripheral clock has 2 extra enable bits */
- /* FIXME: Do they need to be disabled? */
- val = clk_readl(c->reg);
- val |= 0x3 << 24;
- clk_writel(val, c->reg);
- }
-
-out:
- spin_unlock_irqrestore(&clock_register_lock, flags);
-
- return 0;
-}
-
-static void tegra2_periph_clk_disable(struct clk *c)
-{
- unsigned long flags;
-
- pr_debug("%s on clock %s\n", __func__, c->name);
-
- if (!c->u.periph.clk_num)
- return;
-
- spin_lock_irqsave(&clock_register_lock, flags);
-
- if (c->refcnt)
- tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--;
-
- if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] == 0)
- clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
- CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
-
- spin_unlock_irqrestore(&clock_register_lock, flags);
-}
-
-static void tegra2_periph_clk_reset(struct clk *c, bool assert)
-{
- unsigned long base = assert ? RST_DEVICES_SET : RST_DEVICES_CLR;
-
- pr_debug("%s %s on clock %s\n", __func__,
- assert ? "assert" : "deassert", c->name);
-
- BUG_ON(!c->u.periph.clk_num);
-
- if (!(c->flags & PERIPH_NO_RESET))
- clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
- base + PERIPH_CLK_TO_ENB_SET_REG(c));
-}
-
-static int tegra2_periph_clk_set_parent(struct clk *c, struct clk *p)
-{
- u32 val;
- const struct clk_mux_sel *sel;
- u32 mask, shift;
-
- pr_debug("%s: %s %s\n", __func__, c->name, p->name);
-
- if (c->flags & MUX_PWM) {
- shift = PERIPH_CLK_SOURCE_PWM_SHIFT;
- mask = PERIPH_CLK_SOURCE_PWM_MASK;
- } else {
- shift = PERIPH_CLK_SOURCE_SHIFT;
- mask = PERIPH_CLK_SOURCE_MASK;
- }
-
- for (sel = c->inputs; sel->input != NULL; sel++) {
- if (sel->input == p) {
- val = clk_readl(c->reg);
- val &= ~mask;
- val |= (sel->value) << shift;
-
- if (c->refcnt)
- clk_enable(p);
-
- clk_writel(val, c->reg);
-
- if (c->refcnt && c->parent)
- clk_disable(c->parent);
-
- clk_reparent(c, p);
- return 0;
- }
- }
-
- return -EINVAL;
-}
-
-static int tegra2_periph_clk_set_rate(struct clk *c, unsigned long rate)
-{
- u32 val;
- int divider;
- unsigned long parent_rate = clk_get_rate(c->parent);
-
- if (c->flags & DIV_U71) {
- divider = clk_div71_get_divider(parent_rate, rate);
- if (divider >= 0) {
- val = clk_readl(c->reg);
- val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK;
- val |= divider;
- clk_writel(val, c->reg);
- c->div = divider + 2;
- c->mul = 2;
- return 0;
- }
- } else if (c->flags & DIV_U16) {
- divider = clk_div16_get_divider(parent_rate, rate);
- if (divider >= 0) {
- val = clk_readl(c->reg);
- val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK;
- val |= divider;
- clk_writel(val, c->reg);
- c->div = divider + 1;
- c->mul = 1;
- return 0;
- }
- } else if (parent_rate <= rate) {
- c->div = 1;
- c->mul = 1;
- return 0;
- }
- return -EINVAL;
-}
-
-static long tegra2_periph_clk_round_rate(struct clk *c,
- unsigned long rate)
-{
- int divider;
- unsigned long parent_rate = clk_get_rate(c->parent);
- pr_debug("%s: %s %lu\n", __func__, c->name, rate);
-
- if (c->flags & DIV_U71) {
- divider = clk_div71_get_divider(parent_rate, rate);
- if (divider < 0)
- return divider;
-
- return DIV_ROUND_UP(parent_rate * 2, divider + 2);
- } else if (c->flags & DIV_U16) {
- divider = clk_div16_get_divider(parent_rate, rate);
- if (divider < 0)
- return divider;
- return DIV_ROUND_UP(parent_rate, divider + 1);
- }
- return -EINVAL;
-}
-
-static struct clk_ops tegra_periph_clk_ops = {
- .init = &tegra2_periph_clk_init,
- .enable = &tegra2_periph_clk_enable,
- .disable = &tegra2_periph_clk_disable,
- .set_parent = &tegra2_periph_clk_set_parent,
- .set_rate = &tegra2_periph_clk_set_rate,
- .round_rate = &tegra2_periph_clk_round_rate,
- .reset = &tegra2_periph_clk_reset,
-};
-
-/* The SDMMC controllers have extra bits in the clock source register that
- * adjust the delay between the clock and data to compenstate for delays
- * on the PCB. */
-void tegra2_sdmmc_tap_delay(struct clk *c, int delay)
-{
- u32 reg;
- unsigned long flags;
-
- spin_lock_irqsave(&c->spinlock, flags);
-
- delay = clamp(delay, 0, 15);
- reg = clk_readl(c->reg);
- reg &= ~SDMMC_CLK_INT_FB_DLY_MASK;
- reg |= SDMMC_CLK_INT_FB_SEL;
- reg |= delay << SDMMC_CLK_INT_FB_DLY_SHIFT;
- clk_writel(reg, c->reg);
-
- spin_unlock_irqrestore(&c->spinlock, flags);
-}
-
-/* External memory controller clock ops */
-static void tegra2_emc_clk_init(struct clk *c)
-{
- tegra2_periph_clk_init(c);
- c->max_rate = clk_get_rate_locked(c);
-}
-
-static long tegra2_emc_clk_round_rate(struct clk *c, unsigned long rate)
-{
- long emc_rate;
- long clk_rate;
-
- /*
- * The slowest entry in the EMC clock table that is at least as
- * fast as rate.
- */
- emc_rate = tegra_emc_round_rate(rate);
- if (emc_rate < 0)
- return c->max_rate;
-
- /*
- * The fastest rate the PLL will generate that is at most the
- * requested rate.
- */
- clk_rate = tegra2_periph_clk_round_rate(c, emc_rate);
-
- /*
- * If this fails, and emc_rate > clk_rate, it's because the maximum
- * rate in the EMC tables is larger than the maximum rate of the EMC
- * clock. The EMC clock's max rate is the rate it was running when the
- * kernel booted. Such a mismatch is probably due to using the wrong
- * BCT, i.e. using a Tegra20 BCT with an EMC table written for Tegra25.
- */
- WARN_ONCE(emc_rate != clk_rate,
- "emc_rate %ld != clk_rate %ld",
- emc_rate, clk_rate);
-
- return emc_rate;
-}
-
-static int tegra2_emc_clk_set_rate(struct clk *c, unsigned long rate)
-{
- int ret;
- /*
- * The Tegra2 memory controller has an interlock with the clock
- * block that allows memory shadowed registers to be updated,
- * and then transfer them to the main registers at the same
- * time as the clock update without glitches.
- */
- ret = tegra_emc_set_rate(rate);
- if (ret < 0)
- return ret;
-
- ret = tegra2_periph_clk_set_rate(c, rate);
- udelay(1);
-
- return ret;
-}
-
-static struct clk_ops tegra_emc_clk_ops = {
- .init = &tegra2_emc_clk_init,
- .enable = &tegra2_periph_clk_enable,
- .disable = &tegra2_periph_clk_disable,
- .set_parent = &tegra2_periph_clk_set_parent,
- .set_rate = &tegra2_emc_clk_set_rate,
- .round_rate = &tegra2_emc_clk_round_rate,
- .reset = &tegra2_periph_clk_reset,
-};
-
-/* Clock doubler ops */
-static void tegra2_clk_double_init(struct clk *c)
-{
- c->mul = 2;
- c->div = 1;
- c->state = ON;
-
- if (!c->u.periph.clk_num)
- return;
-
- if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
- PERIPH_CLK_TO_ENB_BIT(c)))
- c->state = OFF;
-};
-
-static int tegra2_clk_double_set_rate(struct clk *c, unsigned long rate)
-{
- if (rate != 2 * clk_get_rate(c->parent))
- return -EINVAL;
- c->mul = 2;
- c->div = 1;
- return 0;
-}
-
-static struct clk_ops tegra_clk_double_ops = {
- .init = &tegra2_clk_double_init,
- .enable = &tegra2_periph_clk_enable,
- .disable = &tegra2_periph_clk_disable,
- .set_rate = &tegra2_clk_double_set_rate,
-};
-
-/* Audio sync clock ops */
-static void tegra2_audio_sync_clk_init(struct clk *c)
-{
- int source;
- const struct clk_mux_sel *sel;
- u32 val = clk_readl(c->reg);
- c->state = (val & (1<<4)) ? OFF : ON;
- source = val & 0xf;
- for (sel = c->inputs; sel->input != NULL; sel++)
- if (sel->value == source)
- break;
- BUG_ON(sel->input == NULL);
- c->parent = sel->input;
-}
-
-static int tegra2_audio_sync_clk_enable(struct clk *c)
-{
- clk_writel(0, c->reg);
- return 0;
-}
-
-static void tegra2_audio_sync_clk_disable(struct clk *c)
-{
- clk_writel(1, c->reg);
-}
-
-static int tegra2_audio_sync_clk_set_parent(struct clk *c, struct clk *p)
-{
- u32 val;
- const struct clk_mux_sel *sel;
- for (sel = c->inputs; sel->input != NULL; sel++) {
- if (sel->input == p) {
- val = clk_readl(c->reg);
- val &= ~0xf;
- val |= sel->value;
-
- if (c->refcnt)
- clk_enable(p);
-
- clk_writel(val, c->reg);
-
- if (c->refcnt && c->parent)
- clk_disable(c->parent);
-
- clk_reparent(c, p);
- return 0;
- }
- }
-
- return -EINVAL;
-}
-
-static struct clk_ops tegra_audio_sync_clk_ops = {
- .init = tegra2_audio_sync_clk_init,
- .enable = tegra2_audio_sync_clk_enable,
- .disable = tegra2_audio_sync_clk_disable,
- .set_parent = tegra2_audio_sync_clk_set_parent,
-};
-
-/* cdev1 and cdev2 (dap_mclk1 and dap_mclk2) ops */
-
-static void tegra2_cdev_clk_init(struct clk *c)
-{
- /* We could un-tristate the cdev1 or cdev2 pingroup here; this is
- * currently done in the pinmux code. */
- c->state = ON;
-
- BUG_ON(!c->u.periph.clk_num);
-
- if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
- PERIPH_CLK_TO_ENB_BIT(c)))
- c->state = OFF;
-}
-
-static int tegra2_cdev_clk_enable(struct clk *c)
-{
- BUG_ON(!c->u.periph.clk_num);
-
- clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
- CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c));
- return 0;
-}
-
-static void tegra2_cdev_clk_disable(struct clk *c)
-{
- BUG_ON(!c->u.periph.clk_num);
-
- clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
- CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
-}
-
-static struct clk_ops tegra_cdev_clk_ops = {
- .init = &tegra2_cdev_clk_init,
- .enable = &tegra2_cdev_clk_enable,
- .disable = &tegra2_cdev_clk_disable,
-};
-
-/* shared bus ops */
-/*
- * Some clocks may have multiple downstream users that need to request a
- * higher clock rate. Shared bus clocks provide a unique shared_bus_user
- * clock to each user. The frequency of the bus is set to the highest
- * enabled shared_bus_user clock, with a minimum value set by the
- * shared bus.
- */
-static int tegra_clk_shared_bus_update(struct clk *bus)
-{
- struct clk *c;
- unsigned long rate = bus->min_rate;
-
- list_for_each_entry(c, &bus->shared_bus_list, u.shared_bus_user.node)
- if (c->u.shared_bus_user.enabled)
- rate = max(c->u.shared_bus_user.rate, rate);
-
- if (rate == clk_get_rate_locked(bus))
- return 0;
-
- return clk_set_rate_locked(bus, rate);
-};
-
-static void tegra_clk_shared_bus_init(struct clk *c)
-{
- unsigned long flags;
-
- c->max_rate = c->parent->max_rate;
- c->u.shared_bus_user.rate = c->parent->max_rate;
- c->state = OFF;
- c->set = true;
-
- spin_lock_irqsave(&c->parent->spinlock, flags);
-
- list_add_tail(&c->u.shared_bus_user.node,
- &c->parent->shared_bus_list);
-
- spin_unlock_irqrestore(&c->parent->spinlock, flags);
-}
-
-static int tegra_clk_shared_bus_set_rate(struct clk *c, unsigned long rate)
-{
- unsigned long flags;
- int ret;
- long new_rate = rate;
-
- new_rate = clk_round_rate(c->parent, new_rate);
- if (new_rate < 0)
- return new_rate;
-
- spin_lock_irqsave(&c->parent->spinlock, flags);
-
- c->u.shared_bus_user.rate = new_rate;
- ret = tegra_clk_shared_bus_update(c->parent);
-
- spin_unlock_irqrestore(&c->parent->spinlock, flags);
-
- return ret;
-}
-
-static long tegra_clk_shared_bus_round_rate(struct clk *c, unsigned long rate)
-{
- return clk_round_rate(c->parent, rate);
-}
-
-static int tegra_clk_shared_bus_enable(struct clk *c)
-{
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(&c->parent->spinlock, flags);
-
- c->u.shared_bus_user.enabled = true;
- ret = tegra_clk_shared_bus_update(c->parent);
-
- spin_unlock_irqrestore(&c->parent->spinlock, flags);
-
- return ret;
-}
-
-static void tegra_clk_shared_bus_disable(struct clk *c)
-{
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(&c->parent->spinlock, flags);
-
- c->u.shared_bus_user.enabled = false;
- ret = tegra_clk_shared_bus_update(c->parent);
- WARN_ON_ONCE(ret);
-
- spin_unlock_irqrestore(&c->parent->spinlock, flags);
-}
-
-static struct clk_ops tegra_clk_shared_bus_ops = {
- .init = tegra_clk_shared_bus_init,
- .enable = tegra_clk_shared_bus_enable,
- .disable = tegra_clk_shared_bus_disable,
- .set_rate = tegra_clk_shared_bus_set_rate,
- .round_rate = tegra_clk_shared_bus_round_rate,
-};
-
-
-/* Clock definitions */
-static struct clk tegra_clk_32k = {
- .name = "clk_32k",
- .rate = 32768,
- .ops = NULL,
- .max_rate = 32768,
-};
-
-static struct clk_pll_freq_table tegra_pll_s_freq_table[] = {
- {32768, 12000000, 366, 1, 1, 0},
- {32768, 13000000, 397, 1, 1, 0},
- {32768, 19200000, 586, 1, 1, 0},
- {32768, 26000000, 793, 1, 1, 0},
- {0, 0, 0, 0, 0, 0},
-};
-
-static struct clk tegra_pll_s = {
- .name = "pll_s",
- .flags = PLL_ALT_MISC_REG,
- .ops = &tegra_pll_ops,
- .parent = &tegra_clk_32k,
- .max_rate = 26000000,
- .reg = 0xf0,
- .u.pll = {
- .input_min = 32768,
- .input_max = 32768,
- .cf_min = 0, /* FIXME */
- .cf_max = 0, /* FIXME */
- .vco_min = 12000000,
- .vco_max = 26000000,
- .freq_table = tegra_pll_s_freq_table,
- .lock_delay = 300,
- },
-};
-
-static struct clk_mux_sel tegra_clk_m_sel[] = {
- { .input = &tegra_clk_32k, .value = 0},
- { .input = &tegra_pll_s, .value = 1},
- { NULL , 0},
-};
-
-static struct clk tegra_clk_m = {
- .name = "clk_m",
- .flags = ENABLE_ON_INIT,
- .ops = &tegra_clk_m_ops,
- .inputs = tegra_clk_m_sel,
- .reg = 0x1fc,
- .reg_shift = 28,
- .max_rate = 26000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_c_freq_table[] = {
- { 12000000, 600000000, 600, 12, 1, 8 },
- { 13000000, 600000000, 600, 13, 1, 8 },
- { 19200000, 600000000, 500, 16, 1, 6 },
- { 26000000, 600000000, 600, 26, 1, 8 },
- { 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_c = {
- .name = "pll_c",
- .flags = PLL_HAS_CPCON,
- .ops = &tegra_pll_ops,
- .reg = 0x80,
- .parent = &tegra_clk_m,
- .max_rate = 600000000,
- .u.pll = {
- .input_min = 2000000,
- .input_max = 31000000,
- .cf_min = 1000000,
- .cf_max = 6000000,
- .vco_min = 20000000,
- .vco_max = 1400000000,
- .freq_table = tegra_pll_c_freq_table,
- .lock_delay = 300,
- },
-};
-
-static struct clk tegra_pll_c_out1 = {
- .name = "pll_c_out1",
- .ops = &tegra_pll_div_ops,
- .flags = DIV_U71,
- .parent = &tegra_pll_c,
- .reg = 0x84,
- .reg_shift = 0,
- .max_rate = 600000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_m_freq_table[] = {
- { 12000000, 666000000, 666, 12, 1, 8},
- { 13000000, 666000000, 666, 13, 1, 8},
- { 19200000, 666000000, 555, 16, 1, 8},
- { 26000000, 666000000, 666, 26, 1, 8},
- { 12000000, 600000000, 600, 12, 1, 8},
- { 13000000, 600000000, 600, 13, 1, 8},
- { 19200000, 600000000, 375, 12, 1, 6},
- { 26000000, 600000000, 600, 26, 1, 8},
- { 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_m = {
- .name = "pll_m",
- .flags = PLL_HAS_CPCON,
- .ops = &tegra_pll_ops,
- .reg = 0x90,
- .parent = &tegra_clk_m,
- .max_rate = 800000000,
- .u.pll = {
- .input_min = 2000000,
- .input_max = 31000000,
- .cf_min = 1000000,
- .cf_max = 6000000,
- .vco_min = 20000000,
- .vco_max = 1200000000,
- .freq_table = tegra_pll_m_freq_table,
- .lock_delay = 300,
- },
-};
-
-static struct clk tegra_pll_m_out1 = {
- .name = "pll_m_out1",
- .ops = &tegra_pll_div_ops,
- .flags = DIV_U71,
- .parent = &tegra_pll_m,
- .reg = 0x94,
- .reg_shift = 0,
- .max_rate = 600000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_p_freq_table[] = {
- { 12000000, 216000000, 432, 12, 2, 8},
- { 13000000, 216000000, 432, 13, 2, 8},
- { 19200000, 216000000, 90, 4, 2, 1},
- { 26000000, 216000000, 432, 26, 2, 8},
- { 12000000, 432000000, 432, 12, 1, 8},
- { 13000000, 432000000, 432, 13, 1, 8},
- { 19200000, 432000000, 90, 4, 1, 1},
- { 26000000, 432000000, 432, 26, 1, 8},
- { 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_p = {
- .name = "pll_p",
- .flags = ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON,
- .ops = &tegra_pll_ops,
- .reg = 0xa0,
- .parent = &tegra_clk_m,
- .max_rate = 432000000,
- .u.pll = {
- .input_min = 2000000,
- .input_max = 31000000,
- .cf_min = 1000000,
- .cf_max = 6000000,
- .vco_min = 20000000,
- .vco_max = 1400000000,
- .freq_table = tegra_pll_p_freq_table,
- .lock_delay = 300,
- },
-};
-
-static struct clk tegra_pll_p_out1 = {
- .name = "pll_p_out1",
- .ops = &tegra_pll_div_ops,
- .flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
- .parent = &tegra_pll_p,
- .reg = 0xa4,
- .reg_shift = 0,
- .max_rate = 432000000,
-};
-
-static struct clk tegra_pll_p_out2 = {
- .name = "pll_p_out2",
- .ops = &tegra_pll_div_ops,
- .flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
- .parent = &tegra_pll_p,
- .reg = 0xa4,
- .reg_shift = 16,
- .max_rate = 432000000,
-};
-
-static struct clk tegra_pll_p_out3 = {
- .name = "pll_p_out3",
- .ops = &tegra_pll_div_ops,
- .flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
- .parent = &tegra_pll_p,
- .reg = 0xa8,
- .reg_shift = 0,
- .max_rate = 432000000,
-};
-
-static struct clk tegra_pll_p_out4 = {
- .name = "pll_p_out4",
- .ops = &tegra_pll_div_ops,
- .flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
- .parent = &tegra_pll_p,
- .reg = 0xa8,
- .reg_shift = 16,
- .max_rate = 432000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_a_freq_table[] = {
- { 28800000, 56448000, 49, 25, 1, 1},
- { 28800000, 73728000, 64, 25, 1, 1},
- { 28800000, 24000000, 5, 6, 1, 1},
- { 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_a = {
- .name = "pll_a",
- .flags = PLL_HAS_CPCON,
- .ops = &tegra_pll_ops,
- .reg = 0xb0,
- .parent = &tegra_pll_p_out1,
- .max_rate = 73728000,
- .u.pll = {
- .input_min = 2000000,
- .input_max = 31000000,
- .cf_min = 1000000,
- .cf_max = 6000000,
- .vco_min = 20000000,
- .vco_max = 1400000000,
- .freq_table = tegra_pll_a_freq_table,
- .lock_delay = 300,
- },
-};
-
-static struct clk tegra_pll_a_out0 = {
- .name = "pll_a_out0",
- .ops = &tegra_pll_div_ops,
- .flags = DIV_U71,
- .parent = &tegra_pll_a,
- .reg = 0xb4,
- .reg_shift = 0,
- .max_rate = 73728000,
-};
-
-static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
- { 12000000, 216000000, 216, 12, 1, 4},
- { 13000000, 216000000, 216, 13, 1, 4},
- { 19200000, 216000000, 135, 12, 1, 3},
- { 26000000, 216000000, 216, 26, 1, 4},
-
- { 12000000, 594000000, 594, 12, 1, 8},
- { 13000000, 594000000, 594, 13, 1, 8},
- { 19200000, 594000000, 495, 16, 1, 8},
- { 26000000, 594000000, 594, 26, 1, 8},
-
- { 12000000, 1000000000, 1000, 12, 1, 12},
- { 13000000, 1000000000, 1000, 13, 1, 12},
- { 19200000, 1000000000, 625, 12, 1, 8},
- { 26000000, 1000000000, 1000, 26, 1, 12},
-
- { 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_d = {
- .name = "pll_d",
- .flags = PLL_HAS_CPCON | PLLD,
- .ops = &tegra_pll_ops,
- .reg = 0xd0,
- .parent = &tegra_clk_m,
- .max_rate = 1000000000,
- .u.pll = {
- .input_min = 2000000,
- .input_max = 40000000,
- .cf_min = 1000000,
- .cf_max = 6000000,
- .vco_min = 40000000,
- .vco_max = 1000000000,
- .freq_table = tegra_pll_d_freq_table,
- .lock_delay = 1000,
- },
-};
-
-static struct clk tegra_pll_d_out0 = {
- .name = "pll_d_out0",
- .ops = &tegra_pll_div_ops,
- .flags = DIV_2 | PLLD,
- .parent = &tegra_pll_d,
- .max_rate = 500000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_u_freq_table[] = {
- { 12000000, 480000000, 960, 12, 2, 0},
- { 13000000, 480000000, 960, 13, 2, 0},
- { 19200000, 480000000, 200, 4, 2, 0},
- { 26000000, 480000000, 960, 26, 2, 0},
- { 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_u = {
- .name = "pll_u",
- .flags = PLLU,
- .ops = &tegra_pll_ops,
- .reg = 0xc0,
- .parent = &tegra_clk_m,
- .max_rate = 480000000,
- .u.pll = {
- .input_min = 2000000,
- .input_max = 40000000,
- .cf_min = 1000000,
- .cf_max = 6000000,
- .vco_min = 480000000,
- .vco_max = 960000000,
- .freq_table = tegra_pll_u_freq_table,
- .lock_delay = 1000,
- },
-};
-
-static struct clk_pll_freq_table tegra_pll_x_freq_table[] = {
- /* 1 GHz */
- { 12000000, 1000000000, 1000, 12, 1, 12},
- { 13000000, 1000000000, 1000, 13, 1, 12},
- { 19200000, 1000000000, 625, 12, 1, 8},
- { 26000000, 1000000000, 1000, 26, 1, 12},
-
- /* 912 MHz */
- { 12000000, 912000000, 912, 12, 1, 12},
- { 13000000, 912000000, 912, 13, 1, 12},
- { 19200000, 912000000, 760, 16, 1, 8},
- { 26000000, 912000000, 912, 26, 1, 12},
-
- /* 816 MHz */
- { 12000000, 816000000, 816, 12, 1, 12},
- { 13000000, 816000000, 816, 13, 1, 12},
- { 19200000, 816000000, 680, 16, 1, 8},
- { 26000000, 816000000, 816, 26, 1, 12},
-
- /* 760 MHz */
- { 12000000, 760000000, 760, 12, 1, 12},
- { 13000000, 760000000, 760, 13, 1, 12},
- { 19200000, 760000000, 950, 24, 1, 8},
- { 26000000, 760000000, 760, 26, 1, 12},
-
- /* 750 MHz */
- { 12000000, 750000000, 750, 12, 1, 12},
- { 13000000, 750000000, 750, 13, 1, 12},
- { 19200000, 750000000, 625, 16, 1, 8},
- { 26000000, 750000000, 750, 26, 1, 12},
-
- /* 608 MHz */
- { 12000000, 608000000, 608, 12, 1, 12},
- { 13000000, 608000000, 608, 13, 1, 12},
- { 19200000, 608000000, 380, 12, 1, 8},
- { 26000000, 608000000, 608, 26, 1, 12},
-
- /* 456 MHz */
- { 12000000, 456000000, 456, 12, 1, 12},
- { 13000000, 456000000, 456, 13, 1, 12},
- { 19200000, 456000000, 380, 16, 1, 8},
- { 26000000, 456000000, 456, 26, 1, 12},
-
- /* 312 MHz */
- { 12000000, 312000000, 312, 12, 1, 12},
- { 13000000, 312000000, 312, 13, 1, 12},
- { 19200000, 312000000, 260, 16, 1, 8},
- { 26000000, 312000000, 312, 26, 1, 12},
-
- { 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_x = {
- .name = "pll_x",
- .flags = PLL_HAS_CPCON | PLL_ALT_MISC_REG,
- .ops = &tegra_pllx_ops,
- .reg = 0xe0,
- .parent = &tegra_clk_m,
- .max_rate = 1000000000,
- .u.pll = {
- .input_min = 2000000,
- .input_max = 31000000,
- .cf_min = 1000000,
- .cf_max = 6000000,
- .vco_min = 20000000,
- .vco_max = 1200000000,
- .freq_table = tegra_pll_x_freq_table,
- .lock_delay = 300,
- },
-};
-
-static struct clk_pll_freq_table tegra_pll_e_freq_table[] = {
- { 12000000, 100000000, 200, 24, 1, 0 },
- { 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_e = {
- .name = "pll_e",
- .flags = PLL_ALT_MISC_REG,
- .ops = &tegra_plle_ops,
- .parent = &tegra_clk_m,
- .reg = 0xe8,
- .max_rate = 100000000,
- .u.pll = {
- .input_min = 12000000,
- .input_max = 12000000,
- .freq_table = tegra_pll_e_freq_table,
- },
-};
-
-static struct clk tegra_clk_d = {
- .name = "clk_d",
- .flags = PERIPH_NO_RESET,
- .ops = &tegra_clk_double_ops,
- .reg = 0x34,
- .reg_shift = 12,
- .parent = &tegra_clk_m,
- .max_rate = 52000000,
- .u.periph = {
- .clk_num = 90,
- },
-};
-
-/* dap_mclk1, belongs to the cdev1 pingroup. */
-static struct clk tegra_clk_cdev1 = {
- .name = "cdev1",
- .ops = &tegra_cdev_clk_ops,
- .rate = 26000000,
- .max_rate = 26000000,
- .u.periph = {
- .clk_num = 94,
- },
-};
-
-/* dap_mclk2, belongs to the cdev2 pingroup. */
-static struct clk tegra_clk_cdev2 = {
- .name = "cdev2",
- .ops = &tegra_cdev_clk_ops,
- .rate = 26000000,
- .max_rate = 26000000,
- .u.periph = {
- .clk_num = 93,
- },
-};
-
-/* initialized before peripheral clocks */
-static struct clk_mux_sel mux_audio_sync_clk[8+1];
-static const struct audio_sources {
- const char *name;
- int value;
-} mux_audio_sync_clk_sources[] = {
- { .name = "spdif_in", .value = 0 },
- { .name = "i2s1", .value = 1 },
- { .name = "i2s2", .value = 2 },
- { .name = "pll_a_out0", .value = 4 },
-#if 0 /* FIXME: not implemented */
- { .name = "ac97", .value = 3 },
- { .name = "ext_audio_clk2", .value = 5 },
- { .name = "ext_audio_clk1", .value = 6 },
- { .name = "ext_vimclk", .value = 7 },
-#endif
- { NULL, 0 }
-};
-
-static struct clk tegra_clk_audio = {
- .name = "audio",
- .inputs = mux_audio_sync_clk,
- .reg = 0x38,
- .max_rate = 73728000,
- .ops = &tegra_audio_sync_clk_ops
-};
-
-static struct clk tegra_clk_audio_2x = {
- .name = "audio_2x",
- .flags = PERIPH_NO_RESET,
- .max_rate = 48000000,
- .ops = &tegra_clk_double_ops,
- .reg = 0x34,
- .reg_shift = 8,
- .parent = &tegra_clk_audio,
- .u.periph = {
- .clk_num = 89,
- },
-};
-
-static struct clk_lookup tegra_audio_clk_lookups[] = {
- { .con_id = "audio", .clk = &tegra_clk_audio },
- { .con_id = "audio_2x", .clk = &tegra_clk_audio_2x }
-};
-
-/* This is called after peripheral clocks are initialized, as the
- * audio_sync clock depends on some of the peripheral clocks.
- */
-
-static void init_audio_sync_clock_mux(void)
-{
- int i;
- struct clk_mux_sel *sel = mux_audio_sync_clk;
- const struct audio_sources *src = mux_audio_sync_clk_sources;
- struct clk_lookup *lookup;
-
- for (i = 0; src->name; i++, sel++, src++) {
- sel->input = tegra_get_clock_by_name(src->name);
- if (!sel->input)
- pr_err("%s: could not find clk %s\n", __func__,
- src->name);
- sel->value = src->value;
- }
-
- lookup = tegra_audio_clk_lookups;
- for (i = 0; i < ARRAY_SIZE(tegra_audio_clk_lookups); i++, lookup++) {
- clk_init(lookup->clk);
- clkdev_add(lookup);
- }
-}
-
-static struct clk_mux_sel mux_cclk[] = {
- { .input = &tegra_clk_m, .value = 0},
- { .input = &tegra_pll_c, .value = 1},
- { .input = &tegra_clk_32k, .value = 2},
- { .input = &tegra_pll_m, .value = 3},
- { .input = &tegra_pll_p, .value = 4},
- { .input = &tegra_pll_p_out4, .value = 5},
- { .input = &tegra_pll_p_out3, .value = 6},
- { .input = &tegra_clk_d, .value = 7},
- { .input = &tegra_pll_x, .value = 8},
- { NULL, 0},
-};
-
-static struct clk_mux_sel mux_sclk[] = {
- { .input = &tegra_clk_m, .value = 0},
- { .input = &tegra_pll_c_out1, .value = 1},
- { .input = &tegra_pll_p_out4, .value = 2},
- { .input = &tegra_pll_p_out3, .value = 3},
- { .input = &tegra_pll_p_out2, .value = 4},
- { .input = &tegra_clk_d, .value = 5},
- { .input = &tegra_clk_32k, .value = 6},
- { .input = &tegra_pll_m_out1, .value = 7},
- { NULL, 0},
-};
-
-static struct clk tegra_clk_cclk = {
- .name = "cclk",
- .inputs = mux_cclk,
- .reg = 0x20,
- .ops = &tegra_super_ops,
- .max_rate = 1000000000,
-};
-
-static struct clk tegra_clk_sclk = {
- .name = "sclk",
- .inputs = mux_sclk,
- .reg = 0x28,
- .ops = &tegra_super_ops,
- .max_rate = 240000000,
- .min_rate = 120000000,
-};
-
-static struct clk tegra_clk_virtual_cpu = {
- .name = "cpu",
- .parent = &tegra_clk_cclk,
- .ops = &tegra_cpu_ops,
- .max_rate = 1000000000,
- .u.cpu = {
- .main = &tegra_pll_x,
- .backup = &tegra_pll_p,
- },
-};
-
-static struct clk tegra_clk_cop = {
- .name = "cop",
- .parent = &tegra_clk_sclk,
- .ops = &tegra_cop_ops,
- .max_rate = 240000000,
-};
-
-static struct clk tegra_clk_hclk = {
- .name = "hclk",
- .flags = DIV_BUS,
- .parent = &tegra_clk_sclk,
- .reg = 0x30,
- .reg_shift = 4,
- .ops = &tegra_bus_ops,
- .max_rate = 240000000,
-};
-
-static struct clk tegra_clk_pclk = {
- .name = "pclk",
- .flags = DIV_BUS,
- .parent = &tegra_clk_hclk,
- .reg = 0x30,
- .reg_shift = 0,
- .ops = &tegra_bus_ops,
- .max_rate = 120000000,
-};
-
-static struct clk tegra_clk_blink = {
- .name = "blink",
- .parent = &tegra_clk_32k,
- .reg = 0x40,
- .ops = &tegra_blink_clk_ops,
- .max_rate = 32768,
-};
-
-static struct clk_mux_sel mux_pllm_pllc_pllp_plla[] = {
- { .input = &tegra_pll_m, .value = 0},
- { .input = &tegra_pll_c, .value = 1},
- { .input = &tegra_pll_p, .value = 2},
- { .input = &tegra_pll_a_out0, .value = 3},
- { NULL, 0},
-};
-
-static struct clk_mux_sel mux_pllm_pllc_pllp_clkm[] = {
- { .input = &tegra_pll_m, .value = 0},
- { .input = &tegra_pll_c, .value = 1},
- { .input = &tegra_pll_p, .value = 2},
- { .input = &tegra_clk_m, .value = 3},
- { NULL, 0},
-};
-
-static struct clk_mux_sel mux_pllp_pllc_pllm_clkm[] = {
- { .input = &tegra_pll_p, .value = 0},
- { .input = &tegra_pll_c, .value = 1},
- { .input = &tegra_pll_m, .value = 2},
- { .input = &tegra_clk_m, .value = 3},
- { NULL, 0},
-};
-
-static struct clk_mux_sel mux_pllaout0_audio2x_pllp_clkm[] = {
- {.input = &tegra_pll_a_out0, .value = 0},
- {.input = &tegra_clk_audio_2x, .value = 1},
- {.input = &tegra_pll_p, .value = 2},
- {.input = &tegra_clk_m, .value = 3},
- { NULL, 0},
-};
-
-static struct clk_mux_sel mux_pllp_plld_pllc_clkm[] = {
- {.input = &tegra_pll_p, .value = 0},
- {.input = &tegra_pll_d_out0, .value = 1},
- {.input = &tegra_pll_c, .value = 2},
- {.input = &tegra_clk_m, .value = 3},
- { NULL, 0},
-};
-
-static struct clk_mux_sel mux_pllp_pllc_audio_clkm_clk32[] = {
- {.input = &tegra_pll_p, .value = 0},
- {.input = &tegra_pll_c, .value = 1},
- {.input = &tegra_clk_audio, .value = 2},
- {.input = &tegra_clk_m, .value = 3},
- {.input = &tegra_clk_32k, .value = 4},
- { NULL, 0},
-};
-
-static struct clk_mux_sel mux_pllp_pllc_pllm[] = {
- {.input = &tegra_pll_p, .value = 0},
- {.input = &tegra_pll_c, .value = 1},
- {.input = &tegra_pll_m, .value = 2},
- { NULL, 0},
-};
-
-static struct clk_mux_sel mux_clk_m[] = {
- { .input = &tegra_clk_m, .value = 0},
- { NULL, 0},
-};
-
-static struct clk_mux_sel mux_pllp_out3[] = {
- { .input = &tegra_pll_p_out3, .value = 0},
- { NULL, 0},
-};
-
-static struct clk_mux_sel mux_plld[] = {
- { .input = &tegra_pll_d, .value = 0},
- { NULL, 0},
-};
-
-static struct clk_mux_sel mux_clk_32k[] = {
- { .input = &tegra_clk_32k, .value = 0},
- { NULL, 0},
-};
-
-static struct clk_mux_sel mux_pclk[] = {
- { .input = &tegra_clk_pclk, .value = 0},
- { NULL, 0},
-};
-
-static struct clk tegra_clk_emc = {
- .name = "emc",
- .ops = &tegra_emc_clk_ops,
- .reg = 0x19c,
- .max_rate = 800000000,
- .inputs = mux_pllm_pllc_pllp_clkm,
- .flags = MUX | DIV_U71 | PERIPH_EMC_ENB,
- .u.periph = {
- .clk_num = 57,
- },
-};
-
-#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, _max, _inputs, _flags) \
- { \
- .name = _name, \
- .lookup = { \
- .dev_id = _dev, \
- .con_id = _con, \
- }, \
- .ops = &tegra_periph_clk_ops, \
- .reg = _reg, \
- .inputs = _inputs, \
- .flags = _flags, \
- .max_rate = _max, \
- .u.periph = { \
- .clk_num = _clk_num, \
- }, \
- }
-
-#define SHARED_CLK(_name, _dev, _con, _parent) \
- { \
- .name = _name, \
- .lookup = { \
- .dev_id = _dev, \
- .con_id = _con, \
- }, \
- .ops = &tegra_clk_shared_bus_ops, \
- .parent = _parent, \
- }
-
-static struct clk tegra_list_clks[] = {
- PERIPH_CLK("apbdma", "tegra-apbdma", NULL, 34, 0, 108000000, mux_pclk, 0),
- PERIPH_CLK("rtc", "rtc-tegra", NULL, 4, 0, 32768, mux_clk_32k, PERIPH_NO_RESET),
- PERIPH_CLK("timer", "timer", NULL, 5, 0, 26000000, mux_clk_m, 0),
- PERIPH_CLK("i2s1", "tegra20-i2s.0", NULL, 11, 0x100, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71),
- PERIPH_CLK("i2s2", "tegra20-i2s.1", NULL, 18, 0x104, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71),
- PERIPH_CLK("spdif_out", "spdif_out", NULL, 10, 0x108, 100000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71),
- PERIPH_CLK("spdif_in", "spdif_in", NULL, 10, 0x10c, 100000000, mux_pllp_pllc_pllm, MUX | DIV_U71),
- PERIPH_CLK("pwm", "tegra-pwm", NULL, 17, 0x110, 432000000, mux_pllp_pllc_audio_clkm_clk32, MUX | DIV_U71 | MUX_PWM),
- PERIPH_CLK("spi", "spi", NULL, 43, 0x114, 40000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("xio", "xio", NULL, 45, 0x120, 150000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("twc", "twc", NULL, 16, 0x12c, 150000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("sbc1", "spi_tegra.0", NULL, 41, 0x134, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("sbc2", "spi_tegra.1", NULL, 44, 0x118, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("sbc3", "spi_tegra.2", NULL, 46, 0x11c, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("sbc4", "spi_tegra.3", NULL, 68, 0x1b4, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("ide", "ide", NULL, 25, 0x144, 100000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* requires min voltage */
- PERIPH_CLK("ndflash", "tegra_nand", NULL, 13, 0x160, 164000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
- PERIPH_CLK("vfir", "vfir", NULL, 7, 0x168, 72000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("sdmmc1", "sdhci-tegra.0", NULL, 14, 0x150, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
- PERIPH_CLK("sdmmc2", "sdhci-tegra.1", NULL, 9, 0x154, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
- PERIPH_CLK("sdmmc3", "sdhci-tegra.2", NULL, 69, 0x1bc, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
- PERIPH_CLK("sdmmc4", "sdhci-tegra.3", NULL, 15, 0x164, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
- PERIPH_CLK("vcp", "tegra-avp", "vcp", 29, 0, 250000000, mux_clk_m, 0),
- PERIPH_CLK("bsea", "tegra-avp", "bsea", 62, 0, 250000000, mux_clk_m, 0),
- PERIPH_CLK("bsev", "tegra-aes", "bsev", 63, 0, 250000000, mux_clk_m, 0),
- PERIPH_CLK("vde", "tegra-avp", "vde", 61, 0x1c8, 250000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage and process_id */
- PERIPH_CLK("csite", "csite", NULL, 73, 0x1d4, 144000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* max rate ??? */
- /* FIXME: what is la? */
- PERIPH_CLK("la", "la", NULL, 76, 0x1f8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- 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("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),
- PERIPH_CLK("uartd", "tegra-uart.3", NULL, 65, 0x1c0, 600000000, mux_pllp_pllc_pllm_clkm, MUX),
- PERIPH_CLK("uarte", "tegra-uart.4", NULL, 66, 0x1c4, 600000000, mux_pllp_pllc_pllm_clkm, MUX),
- PERIPH_CLK("3d", "3d", NULL, 24, 0x158, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_MANUAL_RESET), /* scales with voltage and process_id */
- PERIPH_CLK("2d", "2d", NULL, 21, 0x15c, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */
- PERIPH_CLK("vi", "tegra_camera", "vi", 20, 0x148, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */
- PERIPH_CLK("vi_sensor", "tegra_camera", "vi_sensor", 20, 0x1a8, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_NO_RESET), /* scales with voltage and process_id */
- PERIPH_CLK("epp", "epp", NULL, 19, 0x16c, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */
- PERIPH_CLK("mpe", "mpe", NULL, 60, 0x170, 250000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */
- PERIPH_CLK("host1x", "host1x", NULL, 28, 0x180, 166000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */
- PERIPH_CLK("cve", "cve", NULL, 49, 0x140, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
- PERIPH_CLK("tvo", "tvo", NULL, 49, 0x188, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
- PERIPH_CLK("hdmi", "hdmi", NULL, 51, 0x18c, 600000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
- PERIPH_CLK("tvdac", "tvdac", NULL, 53, 0x194, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
- PERIPH_CLK("disp1", "tegradc.0", NULL, 27, 0x138, 600000000, mux_pllp_plld_pllc_clkm, MUX), /* scales with voltage and process_id */
- PERIPH_CLK("disp2", "tegradc.1", NULL, 26, 0x13c, 600000000, mux_pllp_plld_pllc_clkm, MUX), /* scales with voltage and process_id */
- PERIPH_CLK("usbd", "fsl-tegra-udc", NULL, 22, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
- PERIPH_CLK("usb2", "tegra-ehci.1", NULL, 58, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
- PERIPH_CLK("usb3", "tegra-ehci.2", NULL, 59, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
- PERIPH_CLK("dsi", "dsi", NULL, 48, 0, 500000000, mux_plld, 0), /* scales with voltage */
- PERIPH_CLK("csi", "tegra_camera", "csi", 52, 0, 72000000, mux_pllp_out3, 0),
- PERIPH_CLK("isp", "tegra_camera", "isp", 23, 0, 150000000, mux_clk_m, 0), /* same frequency as VI */
- PERIPH_CLK("csus", "tegra_camera", "csus", 92, 0, 150000000, mux_clk_m, PERIPH_NO_RESET),
- PERIPH_CLK("pex", NULL, "pex", 70, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET),
- PERIPH_CLK("afi", NULL, "afi", 72, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET),
- PERIPH_CLK("pcie_xclk", NULL, "pcie_xclk", 74, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET),
-
- SHARED_CLK("avp.sclk", "tegra-avp", "sclk", &tegra_clk_sclk),
- SHARED_CLK("avp.emc", "tegra-avp", "emc", &tegra_clk_emc),
- SHARED_CLK("cpu.emc", "cpu", "emc", &tegra_clk_emc),
- SHARED_CLK("disp1.emc", "tegradc.0", "emc", &tegra_clk_emc),
- SHARED_CLK("disp2.emc", "tegradc.1", "emc", &tegra_clk_emc),
- SHARED_CLK("hdmi.emc", "hdmi", "emc", &tegra_clk_emc),
- SHARED_CLK("host.emc", "tegra_grhost", "emc", &tegra_clk_emc),
- SHARED_CLK("usbd.emc", "fsl-tegra-udc", "emc", &tegra_clk_emc),
- SHARED_CLK("usb1.emc", "tegra-ehci.0", "emc", &tegra_clk_emc),
- SHARED_CLK("usb2.emc", "tegra-ehci.1", "emc", &tegra_clk_emc),
- SHARED_CLK("usb3.emc", "tegra-ehci.2", "emc", &tegra_clk_emc),
-};
-
-#define CLK_DUPLICATE(_name, _dev, _con) \
- { \
- .name = _name, \
- .lookup = { \
- .dev_id = _dev, \
- .con_id = _con, \
- }, \
- }
-
-/* Some clocks may be used by different drivers depending on the board
- * configuration. List those here to register them twice in the clock lookup
- * table under two names.
- */
-static struct clk_duplicate tegra_clk_duplicates[] = {
- CLK_DUPLICATE("uarta", "serial8250.0", NULL),
- CLK_DUPLICATE("uartb", "serial8250.1", NULL),
- CLK_DUPLICATE("uartc", "serial8250.2", NULL),
- CLK_DUPLICATE("uartd", "serial8250.3", NULL),
- CLK_DUPLICATE("uarte", "serial8250.4", NULL),
- CLK_DUPLICATE("usbd", "utmip-pad", NULL),
- CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),
- CLK_DUPLICATE("usbd", "tegra-otg", NULL),
- CLK_DUPLICATE("hdmi", "tegradc.0", "hdmi"),
- CLK_DUPLICATE("hdmi", "tegradc.1", "hdmi"),
- CLK_DUPLICATE("host1x", "tegra_grhost", "host1x"),
- CLK_DUPLICATE("2d", "tegra_grhost", "gr2d"),
- CLK_DUPLICATE("3d", "tegra_grhost", "gr3d"),
- CLK_DUPLICATE("epp", "tegra_grhost", "epp"),
- CLK_DUPLICATE("mpe", "tegra_grhost", "mpe"),
- CLK_DUPLICATE("cop", "tegra-avp", "cop"),
- CLK_DUPLICATE("vde", "tegra-aes", "vde"),
-};
-
-#define CLK(dev, con, ck) \
- { \
- .dev_id = dev, \
- .con_id = con, \
- .clk = ck, \
- }
-
-static struct clk *tegra_ptr_clks[] = {
- &tegra_clk_32k,
- &tegra_pll_s,
- &tegra_clk_m,
- &tegra_pll_m,
- &tegra_pll_m_out1,
- &tegra_pll_c,
- &tegra_pll_c_out1,
- &tegra_pll_p,
- &tegra_pll_p_out1,
- &tegra_pll_p_out2,
- &tegra_pll_p_out3,
- &tegra_pll_p_out4,
- &tegra_pll_a,
- &tegra_pll_a_out0,
- &tegra_pll_d,
- &tegra_pll_d_out0,
- &tegra_pll_u,
- &tegra_pll_x,
- &tegra_pll_e,
- &tegra_clk_cclk,
- &tegra_clk_sclk,
- &tegra_clk_hclk,
- &tegra_clk_pclk,
- &tegra_clk_d,
- &tegra_clk_cdev1,
- &tegra_clk_cdev2,
- &tegra_clk_virtual_cpu,
- &tegra_clk_blink,
- &tegra_clk_cop,
- &tegra_clk_emc,
-};
-
-static void tegra2_init_one_clock(struct clk *c)
-{
- clk_init(c);
- INIT_LIST_HEAD(&c->shared_bus_list);
- if (!c->lookup.dev_id && !c->lookup.con_id)
- c->lookup.con_id = c->name;
- c->lookup.clk = c;
- clkdev_add(&c->lookup);
-}
-
-void __init tegra2_init_clocks(void)
-{
- int i;
- struct clk *c;
-
- for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++)
- tegra2_init_one_clock(tegra_ptr_clks[i]);
-
- for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++)
- tegra2_init_one_clock(&tegra_list_clks[i]);
-
- for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) {
- c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name);
- if (!c) {
- pr_err("%s: Unknown duplicate clock %s\n", __func__,
- tegra_clk_duplicates[i].name);
- continue;
- }
-
- tegra_clk_duplicates[i].lookup.clk = c;
- clkdev_add(&tegra_clk_duplicates[i].lookup);
- }
-
- init_audio_sync_clock_mux();
-}
-
-#ifdef CONFIG_PM
-static u32 clk_rst_suspend[RST_DEVICES_NUM + CLK_OUT_ENB_NUM +
- PERIPH_CLK_SOURCE_NUM + 22];
-
-void tegra_clk_suspend(void)
-{
- unsigned long off, i;
- u32 *ctx = clk_rst_suspend;
-
- *ctx++ = clk_readl(OSC_CTRL) & OSC_CTRL_MASK;
- *ctx++ = clk_readl(tegra_pll_c.reg + PLL_BASE);
- *ctx++ = clk_readl(tegra_pll_c.reg + PLL_MISC(&tegra_pll_c));
- *ctx++ = clk_readl(tegra_pll_a.reg + PLL_BASE);
- *ctx++ = clk_readl(tegra_pll_a.reg + PLL_MISC(&tegra_pll_a));
- *ctx++ = clk_readl(tegra_pll_s.reg + PLL_BASE);
- *ctx++ = clk_readl(tegra_pll_s.reg + PLL_MISC(&tegra_pll_s));
- *ctx++ = clk_readl(tegra_pll_d.reg + PLL_BASE);
- *ctx++ = clk_readl(tegra_pll_d.reg + PLL_MISC(&tegra_pll_d));
- *ctx++ = clk_readl(tegra_pll_u.reg + PLL_BASE);
- *ctx++ = clk_readl(tegra_pll_u.reg + PLL_MISC(&tegra_pll_u));
-
- *ctx++ = clk_readl(tegra_pll_m_out1.reg);
- *ctx++ = clk_readl(tegra_pll_a_out0.reg);
- *ctx++ = clk_readl(tegra_pll_c_out1.reg);
-
- *ctx++ = clk_readl(tegra_clk_cclk.reg);
- *ctx++ = clk_readl(tegra_clk_cclk.reg + SUPER_CLK_DIVIDER);
-
- *ctx++ = clk_readl(tegra_clk_sclk.reg);
- *ctx++ = clk_readl(tegra_clk_sclk.reg + SUPER_CLK_DIVIDER);
- *ctx++ = clk_readl(tegra_clk_pclk.reg);
-
- *ctx++ = clk_readl(tegra_clk_audio.reg);
-
- for (off = PERIPH_CLK_SOURCE_I2S1; off <= PERIPH_CLK_SOURCE_OSC;
- off += 4) {
- if (off == PERIPH_CLK_SOURCE_EMC)
- continue;
- *ctx++ = clk_readl(off);
- }
-
- off = RST_DEVICES;
- for (i = 0; i < RST_DEVICES_NUM; i++, off += 4)
- *ctx++ = clk_readl(off);
-
- off = CLK_OUT_ENB;
- for (i = 0; i < CLK_OUT_ENB_NUM; i++, off += 4)
- *ctx++ = clk_readl(off);
-
- *ctx++ = clk_readl(MISC_CLK_ENB);
- *ctx++ = clk_readl(CLK_MASK_ARM);
-
- BUG_ON(ctx - clk_rst_suspend != ARRAY_SIZE(clk_rst_suspend));
-}
-
-void tegra_clk_resume(void)
-{
- unsigned long off, i;
- const u32 *ctx = clk_rst_suspend;
- u32 val;
-
- val = clk_readl(OSC_CTRL) & ~OSC_CTRL_MASK;
- val |= *ctx++;
- clk_writel(val, OSC_CTRL);
-
- clk_writel(*ctx++, tegra_pll_c.reg + PLL_BASE);
- clk_writel(*ctx++, tegra_pll_c.reg + PLL_MISC(&tegra_pll_c));
- clk_writel(*ctx++, tegra_pll_a.reg + PLL_BASE);
- clk_writel(*ctx++, tegra_pll_a.reg + PLL_MISC(&tegra_pll_a));
- clk_writel(*ctx++, tegra_pll_s.reg + PLL_BASE);
- clk_writel(*ctx++, tegra_pll_s.reg + PLL_MISC(&tegra_pll_s));
- clk_writel(*ctx++, tegra_pll_d.reg + PLL_BASE);
- clk_writel(*ctx++, tegra_pll_d.reg + PLL_MISC(&tegra_pll_d));
- clk_writel(*ctx++, tegra_pll_u.reg + PLL_BASE);
- clk_writel(*ctx++, tegra_pll_u.reg + PLL_MISC(&tegra_pll_u));
- udelay(1000);
-
- clk_writel(*ctx++, tegra_pll_m_out1.reg);
- clk_writel(*ctx++, tegra_pll_a_out0.reg);
- clk_writel(*ctx++, tegra_pll_c_out1.reg);
-
- clk_writel(*ctx++, tegra_clk_cclk.reg);
- clk_writel(*ctx++, tegra_clk_cclk.reg + SUPER_CLK_DIVIDER);
-
- clk_writel(*ctx++, tegra_clk_sclk.reg);
- clk_writel(*ctx++, tegra_clk_sclk.reg + SUPER_CLK_DIVIDER);
- clk_writel(*ctx++, tegra_clk_pclk.reg);
-
- clk_writel(*ctx++, tegra_clk_audio.reg);
-
- /* enable all clocks before configuring clock sources */
- clk_writel(0xbffffff9ul, CLK_OUT_ENB);
- clk_writel(0xfefffff7ul, CLK_OUT_ENB + 4);
- clk_writel(0x77f01bfful, CLK_OUT_ENB + 8);
- wmb();
-
- for (off = PERIPH_CLK_SOURCE_I2S1; off <= PERIPH_CLK_SOURCE_OSC;
- off += 4) {
- if (off == PERIPH_CLK_SOURCE_EMC)
- continue;
- clk_writel(*ctx++, off);
- }
- wmb();
-
- off = RST_DEVICES;
- for (i = 0; i < RST_DEVICES_NUM; i++, off += 4)
- clk_writel(*ctx++, off);
- wmb();
-
- off = CLK_OUT_ENB;
- for (i = 0; i < CLK_OUT_ENB_NUM; i++, off += 4)
- clk_writel(*ctx++, off);
- wmb();
-
- clk_writel(*ctx++, MISC_CLK_ENB);
- clk_writel(*ctx++, CLK_MASK_ARM);
-}
-#endif
diff --git a/arch/arm/mach-tegra/tegra30_clocks.c b/arch/arm/mach-tegra/tegra30_clocks.c
index 6674f100e16f..63615dadfbb2 100644
--- a/arch/arm/mach-tegra/tegra30_clocks.c
+++ b/arch/arm/mach-tegra/tegra30_clocks.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/tegra30_clocks.c
*
- * Copyright (c) 2010-2011 NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2010-2012 NVIDIA CORPORATION. All rights reserved.
*
* 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
@@ -365,30 +365,32 @@ static void __iomem *misc_gp_hidrev_base = IO_ADDRESS(TEGRA_APB_MISC_BASE);
static int tegra_periph_clk_enable_refcount[CLK_OUT_ENB_NUM * 32];
#define clk_writel(value, reg) \
- __raw_writel(value, (u32)reg_clk_base + (reg))
+ __raw_writel(value, reg_clk_base + (reg))
#define clk_readl(reg) \
- __raw_readl((u32)reg_clk_base + (reg))
+ __raw_readl(reg_clk_base + (reg))
#define pmc_writel(value, reg) \
- __raw_writel(value, (u32)reg_pmc_base + (reg))
+ __raw_writel(value, reg_pmc_base + (reg))
#define pmc_readl(reg) \
- __raw_readl((u32)reg_pmc_base + (reg))
+ __raw_readl(reg_pmc_base + (reg))
#define chipid_readl() \
- __raw_readl((u32)misc_gp_hidrev_base + MISC_GP_HIDREV)
+ __raw_readl(misc_gp_hidrev_base + MISC_GP_HIDREV)
#define clk_writel_delay(value, reg) \
do { \
- __raw_writel((value), (u32)reg_clk_base + (reg)); \
+ __raw_writel((value), reg_clk_base + (reg)); \
udelay(2); \
} while (0)
-
-static inline int clk_set_div(struct clk *c, u32 n)
+static inline int clk_set_div(struct clk_tegra *c, u32 n)
{
- return clk_set_rate(c, (clk_get_rate(c->parent) + n-1) / n);
+ struct clk *clk = c->hw.clk;
+
+ return clk_set_rate(clk,
+ (__clk_get_rate(__clk_get_parent(clk)) + n - 1) / n);
}
static inline u32 periph_clk_to_reg(
- struct clk *c, u32 reg_L, u32 reg_V, int offs)
+ struct clk_tegra *c, u32 reg_L, u32 reg_V, int offs)
{
u32 reg = c->u.periph.clk_num / 32;
BUG_ON(reg >= RST_DEVICES_NUM);
@@ -470,15 +472,32 @@ static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate)
return divider_u16 - 1;
}
+static unsigned long tegra30_clk_fixed_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return to_clk_tegra(hw)->fixed_rate;
+}
+
+struct clk_ops tegra30_clk_32k_ops = {
+ .recalc_rate = tegra30_clk_fixed_recalc_rate,
+};
+
/* clk_m functions */
-static unsigned long tegra30_clk_m_autodetect_rate(struct clk *c)
+static unsigned long tegra30_clk_m_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ if (!to_clk_tegra(hw)->fixed_rate)
+ to_clk_tegra(hw)->fixed_rate = clk_measure_input_freq();
+ return to_clk_tegra(hw)->fixed_rate;
+}
+
+static void tegra30_clk_m_init(struct clk_hw *hw)
{
u32 osc_ctrl = clk_readl(OSC_CTRL);
u32 auto_clock_control = osc_ctrl & ~OSC_CTRL_OSC_FREQ_MASK;
u32 pll_ref_div = osc_ctrl & OSC_CTRL_PLL_REF_DIV_MASK;
- c->rate = clk_measure_input_freq();
- switch (c->rate) {
+ switch (to_clk_tegra(hw)->fixed_rate) {
case 12000000:
auto_clock_control |= OSC_CTRL_OSC_FREQ_12MHZ;
BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
@@ -508,46 +527,44 @@ static unsigned long tegra30_clk_m_autodetect_rate(struct clk *c)
BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_4);
break;
default:
- pr_err("%s: Unexpected clock rate %ld", __func__, c->rate);
+ pr_err("%s: Unexpected clock rate %ld", __func__,
+ to_clk_tegra(hw)->fixed_rate);
BUG();
}
clk_writel(auto_clock_control, OSC_CTRL);
- return c->rate;
}
-static void tegra30_clk_m_init(struct clk *c)
-{
- pr_debug("%s on clock %s\n", __func__, c->name);
- tegra30_clk_m_autodetect_rate(c);
-}
+struct clk_ops tegra30_clk_m_ops = {
+ .init = tegra30_clk_m_init,
+ .recalc_rate = tegra30_clk_m_recalc_rate,
+};
-static int tegra30_clk_m_enable(struct clk *c)
+static unsigned long tegra30_clk_m_div_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
{
- pr_debug("%s on clock %s\n", __func__, c->name);
- return 0;
-}
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u64 rate = parent_rate;
-static void tegra30_clk_m_disable(struct clk *c)
-{
- pr_debug("%s on clock %s\n", __func__, c->name);
- WARN(1, "Attempting to disable main SoC clock\n");
-}
+ if (c->mul != 0 && c->div != 0) {
+ rate *= c->mul;
+ rate += c->div - 1; /* round up */
+ do_div(rate, c->div);
+ }
-static struct clk_ops tegra_clk_m_ops = {
- .init = tegra30_clk_m_init,
- .enable = tegra30_clk_m_enable,
- .disable = tegra30_clk_m_disable,
-};
+ return rate;
+}
-static struct clk_ops tegra_clk_m_div_ops = {
- .enable = tegra30_clk_m_enable,
+struct clk_ops tegra_clk_m_div_ops = {
+ .recalc_rate = tegra30_clk_m_div_recalc_rate,
};
/* PLL reference divider functions */
-static void tegra30_pll_ref_init(struct clk *c)
+static unsigned long tegra30_pll_ref_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ unsigned long rate = parent_rate;
u32 pll_ref_div = clk_readl(OSC_CTRL) & OSC_CTRL_PLL_REF_DIV_MASK;
- pr_debug("%s on clock %s\n", __func__, c->name);
switch (pll_ref_div) {
case OSC_CTRL_PLL_REF_DIV_1:
@@ -564,13 +581,18 @@ static void tegra30_pll_ref_init(struct clk *c)
BUG();
}
c->mul = 1;
- c->state = ON;
+
+ if (c->mul != 0 && c->div != 0) {
+ rate *= c->mul;
+ rate += c->div - 1; /* round up */
+ do_div(rate, c->div);
+ }
+
+ return rate;
}
-static struct clk_ops tegra_pll_ref_ops = {
- .init = tegra30_pll_ref_init,
- .enable = tegra30_clk_m_enable,
- .disable = tegra30_clk_m_disable,
+struct clk_ops tegra_pll_ref_ops = {
+ .recalc_rate = tegra30_pll_ref_recalc_rate,
};
/* super clock functions */
@@ -581,56 +603,50 @@ static struct clk_ops tegra_pll_ref_ops = {
* only when its parent is a fixed rate PLL, since we can't change PLL rate
* in this case.
*/
-static void tegra30_super_clk_init(struct clk *c)
+static void tegra30_super_clk_init(struct clk_hw *hw)
{
- u32 val;
- int source;
- int shift;
- const struct clk_mux_sel *sel;
- val = clk_readl(c->reg + SUPER_CLK_MUX);
- c->state = ON;
- BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
- ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
- shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
- SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
- source = (val >> shift) & SUPER_SOURCE_MASK;
- if (c->flags & DIV_2)
- source |= val & SUPER_LP_DIV2_BYPASS;
- for (sel = c->inputs; sel->input != NULL; sel++) {
- if (sel->value == source)
- break;
- }
- BUG_ON(sel->input == NULL);
- c->parent = sel->input;
+ struct clk_tegra *c = to_clk_tegra(hw);
+ struct clk_tegra *p =
+ to_clk_tegra(__clk_get_hw(__clk_get_parent(hw->clk)));
+ c->state = ON;
if (c->flags & DIV_U71) {
/* Init safe 7.1 divider value (does not affect PLLX path) */
clk_writel(SUPER_CLOCK_DIV_U71_MIN << SUPER_CLOCK_DIV_U71_SHIFT,
c->reg + SUPER_CLK_DIVIDER);
c->mul = 2;
c->div = 2;
- if (!(c->parent->flags & PLLX))
+ if (!(p->flags & PLLX))
c->div += SUPER_CLOCK_DIV_U71_MIN;
} else
clk_writel(0, c->reg + SUPER_CLK_DIVIDER);
}
-static int tegra30_super_clk_enable(struct clk *c)
+static u8 tegra30_super_clk_get_parent(struct clk_hw *hw)
{
- return 0;
-}
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u32 val;
+ int source;
+ int shift;
-static void tegra30_super_clk_disable(struct clk *c)
-{
- /* since tegra 3 has 2 CPU super clocks - low power lp-mode clock and
- geared up g-mode super clock - mode switch may request to disable
- either of them; accept request with no affect on h/w */
+ val = clk_readl(c->reg + SUPER_CLK_MUX);
+ BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
+ ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
+ shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
+ SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
+ source = (val >> shift) & SUPER_SOURCE_MASK;
+ if (c->flags & DIV_2)
+ source |= val & SUPER_LP_DIV2_BYPASS;
+
+ return source;
}
-static int tegra30_super_clk_set_parent(struct clk *c, struct clk *p)
+static int tegra30_super_clk_set_parent(struct clk_hw *hw, u8 index)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ struct clk_tegra *p =
+ to_clk_tegra(__clk_get_hw(clk_get_parent(hw->clk)));
u32 val;
- const struct clk_mux_sel *sel;
int shift;
val = clk_readl(c->reg + SUPER_CLK_MUX);
@@ -638,48 +654,36 @@ static int tegra30_super_clk_set_parent(struct clk *c, struct clk *p)
((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
- for (sel = c->inputs; sel->input != NULL; sel++) {
- if (sel->input == p) {
- /* For LP mode super-clock switch between PLLX direct
- and divided-by-2 outputs is allowed only when other
- than PLLX clock source is current parent */
- if ((c->flags & DIV_2) && (p->flags & PLLX) &&
- ((sel->value ^ val) & SUPER_LP_DIV2_BYPASS)) {
- if (c->parent->flags & PLLX)
- return -EINVAL;
- val ^= SUPER_LP_DIV2_BYPASS;
- clk_writel_delay(val, c->reg);
- }
- val &= ~(SUPER_SOURCE_MASK << shift);
- val |= (sel->value & SUPER_SOURCE_MASK) << shift;
-
- /* 7.1 divider for CPU super-clock does not affect
- PLLX path */
- if (c->flags & DIV_U71) {
- u32 div = 0;
- if (!(p->flags & PLLX)) {
- div = clk_readl(c->reg +
- SUPER_CLK_DIVIDER);
- div &= SUPER_CLOCK_DIV_U71_MASK;
- div >>= SUPER_CLOCK_DIV_U71_SHIFT;
- }
- c->div = div + 2;
- c->mul = 2;
- }
- if (c->refcnt)
- clk_enable(p);
-
- clk_writel_delay(val, c->reg);
-
- if (c->refcnt && c->parent)
- clk_disable(c->parent);
+ /* For LP mode super-clock switch between PLLX direct
+ and divided-by-2 outputs is allowed only when other
+ than PLLX clock source is current parent */
+ if ((c->flags & DIV_2) && (p->flags & PLLX) &&
+ ((index ^ val) & SUPER_LP_DIV2_BYPASS)) {
+ if (p->flags & PLLX)
+ return -EINVAL;
+ val ^= SUPER_LP_DIV2_BYPASS;
+ clk_writel_delay(val, c->reg);
+ }
+ val &= ~(SUPER_SOURCE_MASK << shift);
+ val |= (index & SUPER_SOURCE_MASK) << shift;
- clk_reparent(c, p);
- return 0;
+ /* 7.1 divider for CPU super-clock does not affect
+ PLLX path */
+ if (c->flags & DIV_U71) {
+ u32 div = 0;
+ if (!(p->flags & PLLX)) {
+ div = clk_readl(c->reg +
+ SUPER_CLK_DIVIDER);
+ div &= SUPER_CLOCK_DIV_U71_MASK;
+ div >>= SUPER_CLOCK_DIV_U71_SHIFT;
}
+ c->div = div + 2;
+ c->mul = 2;
}
- return -EINVAL;
+ clk_writel_delay(val, c->reg);
+
+ return 0;
}
/*
@@ -691,10 +695,15 @@ static int tegra30_super_clk_set_parent(struct clk *c, struct clk *p)
* rate of this PLL can't be changed, and it has many other children. In
* this case use 7.1 fractional divider to adjust the super clock rate.
*/
-static int tegra30_super_clk_set_rate(struct clk *c, unsigned long rate)
+static int tegra30_super_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
{
- if ((c->flags & DIV_U71) && (c->parent->flags & PLL_FIXED)) {
- int div = clk_div71_get_divider(c->parent->u.pll.fixed_rate,
+ struct clk_tegra *c = to_clk_tegra(hw);
+ struct clk *parent = __clk_get_parent(hw->clk);
+ struct clk_tegra *cparent = to_clk_tegra(__clk_get_hw(parent));
+
+ if ((c->flags & DIV_U71) && (cparent->flags & PLL_FIXED)) {
+ int div = clk_div71_get_divider(parent_rate,
rate, c->flags, ROUND_DIVIDER_DOWN);
div = max(div, SUPER_CLOCK_DIV_U71_MIN);
@@ -704,55 +713,86 @@ static int tegra30_super_clk_set_rate(struct clk *c, unsigned long rate)
c->mul = 2;
return 0;
}
- return clk_set_rate(c->parent, rate);
+ return 0;
+}
+
+static unsigned long tegra30_super_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u64 rate = parent_rate;
+
+ if (c->mul != 0 && c->div != 0) {
+ rate *= c->mul;
+ rate += c->div - 1; /* round up */
+ do_div(rate, c->div);
+ }
+
+ return rate;
+}
+
+static long tegra30_super_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ struct clk *parent = __clk_get_parent(hw->clk);
+ struct clk_tegra *cparent = to_clk_tegra(__clk_get_hw(parent));
+ int mul = 2;
+ int div;
+
+ if ((c->flags & DIV_U71) && (cparent->flags & PLL_FIXED)) {
+ div = clk_div71_get_divider(*prate,
+ rate, c->flags, ROUND_DIVIDER_DOWN);
+ div = max(div, SUPER_CLOCK_DIV_U71_MIN) + 2;
+ rate = *prate * mul;
+ rate += div - 1; /* round up */
+ do_div(rate, c->div);
+
+ return rate;
+ }
+ return *prate;
}
-static struct clk_ops tegra_super_ops = {
- .init = tegra30_super_clk_init,
- .enable = tegra30_super_clk_enable,
- .disable = tegra30_super_clk_disable,
- .set_parent = tegra30_super_clk_set_parent,
- .set_rate = tegra30_super_clk_set_rate,
+struct clk_ops tegra30_super_ops = {
+ .init = tegra30_super_clk_init,
+ .set_parent = tegra30_super_clk_set_parent,
+ .get_parent = tegra30_super_clk_get_parent,
+ .recalc_rate = tegra30_super_clk_recalc_rate,
+ .round_rate = tegra30_super_clk_round_rate,
+ .set_rate = tegra30_super_clk_set_rate,
};
-static int tegra30_twd_clk_set_rate(struct clk *c, unsigned long rate)
+static unsigned long tegra30_twd_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
{
- /* The input value 'rate' is the clock rate of the CPU complex. */
- c->rate = (rate * c->mul) / c->div;
- return 0;
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u64 rate = parent_rate;
+
+ if (c->mul != 0 && c->div != 0) {
+ rate *= c->mul;
+ rate += c->div - 1; /* round up */
+ do_div(rate, c->div);
+ }
+
+ return rate;
}
-static struct clk_ops tegra30_twd_ops = {
- .set_rate = tegra30_twd_clk_set_rate,
+struct clk_ops tegra30_twd_ops = {
+ .recalc_rate = tegra30_twd_clk_recalc_rate,
};
/* Blink output functions */
-
-static void tegra30_blink_clk_init(struct clk *c)
+static int tegra30_blink_clk_is_enabled(struct clk_hw *hw)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
val = pmc_readl(PMC_CTRL);
c->state = (val & PMC_CTRL_BLINK_ENB) ? ON : OFF;
- c->mul = 1;
- val = pmc_readl(c->reg);
-
- if (val & PMC_BLINK_TIMER_ENB) {
- unsigned int on_off;
-
- on_off = (val >> PMC_BLINK_TIMER_DATA_ON_SHIFT) &
- PMC_BLINK_TIMER_DATA_ON_MASK;
- val >>= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
- val &= PMC_BLINK_TIMER_DATA_OFF_MASK;
- on_off += val;
- /* each tick in the blink timer is 4 32KHz clocks */
- c->div = on_off * 4;
- } else {
- c->div = 1;
- }
+ return c->state;
}
-static int tegra30_blink_clk_enable(struct clk *c)
+static int tegra30_blink_clk_enable(struct clk_hw *hw)
{
u32 val;
@@ -765,7 +805,7 @@ static int tegra30_blink_clk_enable(struct clk *c)
return 0;
}
-static void tegra30_blink_clk_disable(struct clk *c)
+static void tegra30_blink_clk_disable(struct clk_hw *hw)
{
u32 val;
@@ -776,9 +816,11 @@ static void tegra30_blink_clk_disable(struct clk *c)
pmc_writel(val & ~PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
}
-static int tegra30_blink_clk_set_rate(struct clk *c, unsigned long rate)
+static int tegra30_blink_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
{
- unsigned long parent_rate = clk_get_rate(c->parent);
+ struct clk_tegra *c = to_clk_tegra(hw);
+
if (rate >= parent_rate) {
c->div = 1;
pmc_writel(0, c->reg);
@@ -801,41 +843,77 @@ static int tegra30_blink_clk_set_rate(struct clk *c, unsigned long rate)
return 0;
}
-static struct clk_ops tegra_blink_clk_ops = {
- .init = &tegra30_blink_clk_init,
- .enable = &tegra30_blink_clk_enable,
- .disable = &tegra30_blink_clk_disable,
- .set_rate = &tegra30_blink_clk_set_rate,
-};
+static unsigned long tegra30_blink_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u64 rate = parent_rate;
+ u32 val;
+ u32 mul;
+ u32 div;
+ u32 on_off;
-/* PLL Functions */
-static int tegra30_pll_clk_wait_for_lock(struct clk *c, u32 lock_reg,
- u32 lock_bit)
+ mul = 1;
+ val = pmc_readl(c->reg);
+
+ if (val & PMC_BLINK_TIMER_ENB) {
+ on_off = (val >> PMC_BLINK_TIMER_DATA_ON_SHIFT) &
+ PMC_BLINK_TIMER_DATA_ON_MASK;
+ val >>= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
+ val &= PMC_BLINK_TIMER_DATA_OFF_MASK;
+ on_off += val;
+ /* each tick in the blink timer is 4 32KHz clocks */
+ div = on_off * 4;
+ } else {
+ div = 1;
+ }
+
+ if (mul != 0 && div != 0) {
+ rate *= mul;
+ rate += div - 1; /* round up */
+ do_div(rate, div);
+ }
+ return rate;
+}
+
+static long tegra30_blink_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
{
-#if USE_PLL_LOCK_BITS
- int i;
- for (i = 0; i < c->u.pll.lock_delay; i++) {
- if (clk_readl(lock_reg) & lock_bit) {
- udelay(PLL_POST_LOCK_DELAY);
- return 0;
- }
- udelay(2); /* timeout = 2 * lock time */
+ int div;
+ int mul;
+ long round_rate = *prate;
+
+ mul = 1;
+
+ if (rate >= *prate) {
+ div = 1;
+ } else {
+ div = DIV_ROUND_UP(*prate / 8, rate);
+ div *= 8;
}
- pr_err("Timed out waiting for lock bit on pll %s", c->name);
- return -1;
-#endif
- udelay(c->u.pll.lock_delay);
- return 0;
+ round_rate *= mul;
+ round_rate += div - 1;
+ do_div(round_rate, div);
+
+ return round_rate;
}
+struct clk_ops tegra30_blink_clk_ops = {
+ .is_enabled = tegra30_blink_clk_is_enabled,
+ .enable = tegra30_blink_clk_enable,
+ .disable = tegra30_blink_clk_disable,
+ .recalc_rate = tegra30_blink_clk_recalc_rate,
+ .round_rate = tegra30_blink_clk_round_rate,
+ .set_rate = tegra30_blink_clk_set_rate,
+};
-static void tegra30_utmi_param_configure(struct clk *c)
+static void tegra30_utmi_param_configure(struct clk_hw *hw)
{
+ unsigned long main_rate =
+ __clk_get_rate(__clk_get_parent(__clk_get_parent(hw->clk)));
u32 reg;
int i;
- unsigned long main_rate =
- clk_get_rate(c->parent->parent);
for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
if (main_rate == utmi_parameters[i].osc_frequency)
@@ -886,50 +964,52 @@ static void tegra30_utmi_param_configure(struct clk *c)
clk_writel(reg, UTMIP_PLL_CFG1);
}
-static void tegra30_pll_clk_init(struct clk *c)
+/* PLL Functions */
+static int tegra30_pll_clk_wait_for_lock(struct clk_tegra *c, u32 lock_reg,
+ u32 lock_bit)
+{
+ int ret = 0;
+
+#if USE_PLL_LOCK_BITS
+ int i;
+ for (i = 0; i < c->u.pll.lock_delay; i++) {
+ if (clk_readl(lock_reg) & lock_bit) {
+ udelay(PLL_POST_LOCK_DELAY);
+ return 0;
+ }
+ udelay(2); /* timeout = 2 * lock time */
+ }
+ pr_err("Timed out waiting for lock bit on pll %s",
+ __clk_get_name(hw->clk));
+ ret = -1;
+#else
+ udelay(c->u.pll.lock_delay);
+#endif
+ return ret;
+}
+
+static int tegra30_pll_clk_is_enabled(struct clk_hw *hw)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
u32 val = clk_readl(c->reg + PLL_BASE);
c->state = (val & PLL_BASE_ENABLE) ? ON : OFF;
+ return c->state;
+}
- if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) {
- const struct clk_pll_freq_table *sel;
- unsigned long input_rate = clk_get_rate(c->parent);
- for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
- if (sel->input_rate == input_rate &&
- sel->output_rate == c->u.pll.fixed_rate) {
- c->mul = sel->n;
- c->div = sel->m * sel->p;
- return;
- }
- }
- pr_err("Clock %s has unknown fixed frequency\n", c->name);
- BUG();
- } else if (val & PLL_BASE_BYPASS) {
- c->mul = 1;
- c->div = 1;
- } else {
- c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT;
- c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT;
- if (c->flags & PLLU)
- c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2;
- else
- c->div *= (0x1 << ((val & PLL_BASE_DIVP_MASK) >>
- PLL_BASE_DIVP_SHIFT));
- if (c->flags & PLL_FIXED) {
- unsigned long rate = clk_get_rate_locked(c);
- BUG_ON(rate != c->u.pll.fixed_rate);
- }
- }
+static void tegra30_pll_clk_init(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
if (c->flags & PLLU)
- tegra30_utmi_param_configure(c);
+ tegra30_utmi_param_configure(hw);
}
-static int tegra30_pll_clk_enable(struct clk *c)
+static int tegra30_pll_clk_enable(struct clk_hw *hw)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
- pr_debug("%s on clock %s\n", __func__, c->name);
+ pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
#if USE_PLL_LOCK_BITS
val = clk_readl(c->reg + PLL_MISC(c));
@@ -952,10 +1032,11 @@ static int tegra30_pll_clk_enable(struct clk *c)
return 0;
}
-static void tegra30_pll_clk_disable(struct clk *c)
+static void tegra30_pll_clk_disable(struct clk_hw *hw)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
- pr_debug("%s on clock %s\n", __func__, c->name);
+ pr_debug("%s on clock %s\n", __func__, __clk_get_name(hw->clk));
val = clk_readl(c->reg);
val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
@@ -968,36 +1049,36 @@ static void tegra30_pll_clk_disable(struct clk *c)
}
}
-static int tegra30_pll_clk_set_rate(struct clk *c, unsigned long rate)
+static int tegra30_pll_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
u32 val, p_div, old_base;
unsigned long input_rate;
const struct clk_pll_freq_table *sel;
struct clk_pll_freq_table cfg;
- pr_debug("%s: %s %lu\n", __func__, c->name, rate);
-
if (c->flags & PLL_FIXED) {
int ret = 0;
if (rate != c->u.pll.fixed_rate) {
pr_err("%s: Can not change %s fixed rate %lu to %lu\n",
- __func__, c->name, c->u.pll.fixed_rate, rate);
+ __func__, __clk_get_name(hw->clk),
+ c->u.pll.fixed_rate, rate);
ret = -EINVAL;
}
return ret;
}
if (c->flags & PLLM) {
- if (rate != clk_get_rate_locked(c)) {
+ if (rate != __clk_get_rate(hw->clk)) {
pr_err("%s: Can not change memory %s rate in flight\n",
- __func__, c->name);
+ __func__, __clk_get_name(hw->clk));
return -EINVAL;
}
- return 0;
}
p_div = 0;
- input_rate = clk_get_rate(c->parent);
+ input_rate = parent_rate;
/* Check if the target rate is tabulated */
for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
@@ -1055,7 +1136,7 @@ static int tegra30_pll_clk_set_rate(struct clk *c, unsigned long rate)
(p_div > (PLL_BASE_DIVP_MASK >> PLL_BASE_DIVP_SHIFT)) ||
(cfg.output_rate > c->u.pll.vco_max)) {
pr_err("%s: Failed to set %s out-of-table rate %lu\n",
- __func__, c->name, rate);
+ __func__, __clk_get_name(hw->clk), rate);
return -EINVAL;
}
p_div <<= PLL_BASE_DIVP_SHIFT;
@@ -1073,7 +1154,7 @@ static int tegra30_pll_clk_set_rate(struct clk *c, unsigned long rate)
return 0;
if (c->state == ON) {
- tegra30_pll_clk_disable(c);
+ tegra30_pll_clk_disable(hw);
val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
}
clk_writel(val, c->reg + PLL_BASE);
@@ -1095,21 +1176,149 @@ static int tegra30_pll_clk_set_rate(struct clk *c, unsigned long rate)
}
if (c->state == ON)
- tegra30_pll_clk_enable(c);
+ tegra30_pll_clk_enable(hw);
+
+ c->u.pll.fixed_rate = rate;
return 0;
}
-static struct clk_ops tegra_pll_ops = {
- .init = tegra30_pll_clk_init,
- .enable = tegra30_pll_clk_enable,
- .disable = tegra30_pll_clk_disable,
- .set_rate = tegra30_pll_clk_set_rate,
+static long tegra30_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ unsigned long input_rate = *prate;
+ unsigned long output_rate = *prate;
+ const struct clk_pll_freq_table *sel;
+ struct clk_pll_freq_table cfg;
+ int mul;
+ int div;
+ u32 p_div;
+ u32 val;
+
+ if (c->flags & PLL_FIXED)
+ return c->u.pll.fixed_rate;
+
+ if (c->flags & PLLM)
+ return __clk_get_rate(hw->clk);
+
+ p_div = 0;
+ /* Check if the target rate is tabulated */
+ for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
+ if (sel->input_rate == input_rate && sel->output_rate == rate) {
+ if (c->flags & PLLU) {
+ BUG_ON(sel->p < 1 || sel->p > 2);
+ if (sel->p == 1)
+ p_div = PLLU_BASE_POST_DIV;
+ } else {
+ BUG_ON(sel->p < 1);
+ for (val = sel->p; val > 1; val >>= 1)
+ p_div++;
+ p_div <<= PLL_BASE_DIVP_SHIFT;
+ }
+ break;
+ }
+ }
+
+ if (sel->input_rate == 0) {
+ unsigned long cfreq;
+ BUG_ON(c->flags & PLLU);
+ sel = &cfg;
+
+ switch (input_rate) {
+ case 12000000:
+ case 26000000:
+ cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2000000;
+ break;
+ case 13000000:
+ cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2600000;
+ break;
+ case 16800000:
+ case 19200000:
+ cfreq = (rate <= 1200000 * 1000) ? 1200000 : 2400000;
+ break;
+ default:
+ pr_err("%s: Unexpected reference rate %lu\n",
+ __func__, input_rate);
+ BUG();
+ }
+
+ /* Raise VCO to guarantee 0.5% accuracy */
+ for (cfg.output_rate = rate; cfg.output_rate < 200 * cfreq;
+ cfg.output_rate <<= 1)
+ p_div++;
+
+ cfg.p = 0x1 << p_div;
+ cfg.m = input_rate / cfreq;
+ cfg.n = cfg.output_rate / cfreq;
+ }
+
+ mul = sel->n;
+ div = sel->m * sel->p;
+
+ output_rate *= mul;
+ output_rate += div - 1; /* round up */
+ do_div(output_rate, div);
+
+ return output_rate;
+}
+
+static unsigned long tegra30_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u64 rate = parent_rate;
+ u32 val = clk_readl(c->reg + PLL_BASE);
+
+ if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) {
+ const struct clk_pll_freq_table *sel;
+ for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
+ if (sel->input_rate == parent_rate &&
+ sel->output_rate == c->u.pll.fixed_rate) {
+ c->mul = sel->n;
+ c->div = sel->m * sel->p;
+ break;
+ }
+ }
+ pr_err("Clock %s has unknown fixed frequency\n",
+ __clk_get_name(hw->clk));
+ BUG();
+ } else if (val & PLL_BASE_BYPASS) {
+ c->mul = 1;
+ c->div = 1;
+ } else {
+ c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT;
+ c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT;
+ if (c->flags & PLLU)
+ c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2;
+ else
+ c->div *= (0x1 << ((val & PLL_BASE_DIVP_MASK) >>
+ PLL_BASE_DIVP_SHIFT));
+ }
+
+ if (c->mul != 0 && c->div != 0) {
+ rate *= c->mul;
+ rate += c->div - 1; /* round up */
+ do_div(rate, c->div);
+ }
+
+ return rate;
+}
+
+struct clk_ops tegra30_pll_ops = {
+ .is_enabled = tegra30_pll_clk_is_enabled,
+ .init = tegra30_pll_clk_init,
+ .enable = tegra30_pll_clk_enable,
+ .disable = tegra30_pll_clk_disable,
+ .recalc_rate = tegra30_pll_recalc_rate,
+ .round_rate = tegra30_pll_round_rate,
+ .set_rate = tegra30_pll_clk_set_rate,
};
-static int
-tegra30_plld_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+int tegra30_plld_clk_cfg_ex(struct clk_hw *hw,
+ enum tegra_clk_ex_param p, u32 setting)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
u32 val, mask, reg;
switch (p) {
@@ -1141,41 +1350,27 @@ tegra30_plld_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
return 0;
}
-static struct clk_ops tegra_plld_ops = {
- .init = tegra30_pll_clk_init,
- .enable = tegra30_pll_clk_enable,
- .disable = tegra30_pll_clk_disable,
- .set_rate = tegra30_pll_clk_set_rate,
- .clk_cfg_ex = tegra30_plld_clk_cfg_ex,
-};
-
-static void tegra30_plle_clk_init(struct clk *c)
+static int tegra30_plle_clk_is_enabled(struct clk_hw *hw)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
- val = clk_readl(PLLE_AUX);
- c->parent = (val & PLLE_AUX_PLLP_SEL) ?
- tegra_get_clock_by_name("pll_p") :
- tegra_get_clock_by_name("pll_ref");
-
val = clk_readl(c->reg + PLL_BASE);
c->state = (val & PLLE_BASE_ENABLE) ? ON : OFF;
- c->mul = (val & PLLE_BASE_DIVN_MASK) >> PLLE_BASE_DIVN_SHIFT;
- c->div = (val & PLLE_BASE_DIVM_MASK) >> PLLE_BASE_DIVM_SHIFT;
- c->div *= (val & PLLE_BASE_DIVP_MASK) >> PLLE_BASE_DIVP_SHIFT;
+ return c->state;
}
-static void tegra30_plle_clk_disable(struct clk *c)
+static void tegra30_plle_clk_disable(struct clk_hw *hw)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
- pr_debug("%s on clock %s\n", __func__, c->name);
val = clk_readl(c->reg + PLL_BASE);
val &= ~(PLLE_BASE_CML_ENABLE | PLLE_BASE_ENABLE);
clk_writel(val, c->reg + PLL_BASE);
}
-static void tegra30_plle_training(struct clk *c)
+static void tegra30_plle_training(struct clk_tegra *c)
{
u32 val;
@@ -1198,12 +1393,15 @@ static void tegra30_plle_training(struct clk *c)
} while (!(val & PLLE_MISC_READY));
}
-static int tegra30_plle_configure(struct clk *c, bool force_training)
+static int tegra30_plle_configure(struct clk_hw *hw, bool force_training)
{
- u32 val;
+ struct clk_tegra *c = to_clk_tegra(hw);
+ struct clk *parent = __clk_get_parent(hw->clk);
const struct clk_pll_freq_table *sel;
+ u32 val;
+
unsigned long rate = c->u.pll.fixed_rate;
- unsigned long input_rate = clk_get_rate(c->parent);
+ unsigned long input_rate = __clk_get_rate(parent);
for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
if (sel->input_rate == input_rate && sel->output_rate == rate)
@@ -1214,7 +1412,7 @@ static int tegra30_plle_configure(struct clk *c, bool force_training)
return -ENOSYS;
/* disable PLLE, clear setup fiels */
- tegra30_plle_clk_disable(c);
+ tegra30_plle_clk_disable(hw);
val = clk_readl(c->reg + PLL_MISC(c));
val &= ~(PLLE_MISC_LOCK_ENABLE | PLLE_MISC_SETUP_MASK);
@@ -1252,52 +1450,64 @@ static int tegra30_plle_configure(struct clk *c, bool force_training)
return 0;
}
-static int tegra30_plle_clk_enable(struct clk *c)
+static int tegra30_plle_clk_enable(struct clk_hw *hw)
{
- pr_debug("%s on clock %s\n", __func__, c->name);
- return tegra30_plle_configure(c, !c->set);
+ struct clk_tegra *c = to_clk_tegra(hw);
+
+ return tegra30_plle_configure(hw, !c->set);
}
-static struct clk_ops tegra_plle_ops = {
- .init = tegra30_plle_clk_init,
- .enable = tegra30_plle_clk_enable,
- .disable = tegra30_plle_clk_disable,
+static unsigned long tegra30_plle_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ unsigned long rate = parent_rate;
+ u32 val;
+
+ val = clk_readl(c->reg + PLL_BASE);
+ c->mul = (val & PLLE_BASE_DIVN_MASK) >> PLLE_BASE_DIVN_SHIFT;
+ c->div = (val & PLLE_BASE_DIVM_MASK) >> PLLE_BASE_DIVM_SHIFT;
+ c->div *= (val & PLLE_BASE_DIVP_MASK) >> PLLE_BASE_DIVP_SHIFT;
+
+ if (c->mul != 0 && c->div != 0) {
+ rate *= c->mul;
+ rate += c->div - 1; /* round up */
+ do_div(rate, c->div);
+ }
+ return rate;
+}
+
+struct clk_ops tegra30_plle_ops = {
+ .is_enabled = tegra30_plle_clk_is_enabled,
+ .enable = tegra30_plle_clk_enable,
+ .disable = tegra30_plle_clk_disable,
+ .recalc_rate = tegra30_plle_clk_recalc_rate,
};
/* Clock divider ops */
-static void tegra30_pll_div_clk_init(struct clk *c)
+static int tegra30_pll_div_clk_is_enabled(struct clk_hw *hw)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
+
if (c->flags & DIV_U71) {
- u32 divu71;
u32 val = clk_readl(c->reg);
val >>= c->reg_shift;
c->state = (val & PLL_OUT_CLKEN) ? ON : OFF;
if (!(val & PLL_OUT_RESET_DISABLE))
c->state = OFF;
-
- divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT;
- c->div = (divu71 + 2);
- c->mul = 2;
- } else if (c->flags & DIV_2) {
- c->state = ON;
- if (c->flags & (PLLD | PLLX)) {
- c->div = 2;
- c->mul = 1;
- } else
- BUG();
} else {
c->state = ON;
- c->div = 1;
- c->mul = 1;
}
+ return c->state;
}
-static int tegra30_pll_div_clk_enable(struct clk *c)
+static int tegra30_pll_div_clk_enable(struct clk_hw *hw)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
u32 new_val;
- pr_debug("%s: %s\n", __func__, c->name);
+ pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk));
if (c->flags & DIV_U71) {
val = clk_readl(c->reg);
new_val = val >> c->reg_shift;
@@ -1315,12 +1525,13 @@ static int tegra30_pll_div_clk_enable(struct clk *c)
return -EINVAL;
}
-static void tegra30_pll_div_clk_disable(struct clk *c)
+static void tegra30_pll_div_clk_disable(struct clk_hw *hw)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
u32 new_val;
- pr_debug("%s: %s\n", __func__, c->name);
+ pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk));
if (c->flags & DIV_U71) {
val = clk_readl(c->reg);
new_val = val >> c->reg_shift;
@@ -1334,14 +1545,14 @@ static void tegra30_pll_div_clk_disable(struct clk *c)
}
}
-static int tegra30_pll_div_clk_set_rate(struct clk *c, unsigned long rate)
+static int tegra30_pll_div_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
u32 new_val;
int divider_u71;
- unsigned long parent_rate = clk_get_rate(c->parent);
- pr_debug("%s: %s %lu\n", __func__, c->name, rate);
if (c->flags & DIV_U71) {
divider_u71 = clk_div71_get_divider(
parent_rate, rate, c->flags, ROUND_DIVIDER_UP);
@@ -1359,19 +1570,59 @@ static int tegra30_pll_div_clk_set_rate(struct clk *c, unsigned long rate)
clk_writel_delay(val, c->reg);
c->div = divider_u71 + 2;
c->mul = 2;
+ c->fixed_rate = rate;
return 0;
}
- } else if (c->flags & DIV_2)
- return clk_set_rate(c->parent, rate * 2);
+ } else if (c->flags & DIV_2) {
+ c->fixed_rate = rate;
+ return 0;
+ }
return -EINVAL;
}
-static long tegra30_pll_div_clk_round_rate(struct clk *c, unsigned long rate)
+static unsigned long tegra30_pll_div_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u64 rate = parent_rate;
+
+ if (c->flags & DIV_U71) {
+ u32 divu71;
+ u32 val = clk_readl(c->reg);
+ val >>= c->reg_shift;
+
+ divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT;
+ c->div = (divu71 + 2);
+ c->mul = 2;
+ } else if (c->flags & DIV_2) {
+ if (c->flags & (PLLD | PLLX)) {
+ c->div = 2;
+ c->mul = 1;
+ } else
+ BUG();
+ } else {
+ c->div = 1;
+ c->mul = 1;
+ }
+ if (c->mul != 0 && c->div != 0) {
+ rate *= c->mul;
+ rate += c->div - 1; /* round up */
+ do_div(rate, c->div);
+ }
+
+ return rate;
+}
+
+static long tegra30_pll_div_clk_round_rate(struct clk_hw *hw,
+ unsigned long rate, unsigned long *prate)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ unsigned long parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
int divider;
- unsigned long parent_rate = clk_get_rate(c->parent);
- pr_debug("%s: %s %lu\n", __func__, c->name, rate);
+
+ if (prate)
+ parent_rate = *prate;
if (c->flags & DIV_U71) {
divider = clk_div71_get_divider(
@@ -1379,23 +1630,25 @@ static long tegra30_pll_div_clk_round_rate(struct clk *c, unsigned long rate)
if (divider < 0)
return divider;
return DIV_ROUND_UP(parent_rate * 2, divider + 2);
- } else if (c->flags & DIV_2)
- /* no rounding - fixed DIV_2 dividers pass rate to parent PLL */
+ } else if (c->flags & DIV_2) {
+ *prate = rate * 2;
return rate;
+ }
return -EINVAL;
}
-static struct clk_ops tegra_pll_div_ops = {
- .init = tegra30_pll_div_clk_init,
- .enable = tegra30_pll_div_clk_enable,
- .disable = tegra30_pll_div_clk_disable,
- .set_rate = tegra30_pll_div_clk_set_rate,
- .round_rate = tegra30_pll_div_clk_round_rate,
+struct clk_ops tegra30_pll_div_ops = {
+ .is_enabled = tegra30_pll_div_clk_is_enabled,
+ .enable = tegra30_pll_div_clk_enable,
+ .disable = tegra30_pll_div_clk_disable,
+ .set_rate = tegra30_pll_div_clk_set_rate,
+ .recalc_rate = tegra30_pll_div_clk_recalc_rate,
+ .round_rate = tegra30_pll_div_clk_round_rate,
};
/* Periph clk ops */
-static inline u32 periph_clk_source_mask(struct clk *c)
+static inline u32 periph_clk_source_mask(struct clk_tegra *c)
{
if (c->flags & MUX8)
return 7 << 29;
@@ -1409,7 +1662,7 @@ static inline u32 periph_clk_source_mask(struct clk *c)
return 3 << 30;
}
-static inline u32 periph_clk_source_shift(struct clk *c)
+static inline u32 periph_clk_source_shift(struct clk_tegra *c)
{
if (c->flags & MUX8)
return 29;
@@ -1423,47 +1676,9 @@ static inline u32 periph_clk_source_shift(struct clk *c)
return 30;
}
-static void tegra30_periph_clk_init(struct clk *c)
+static int tegra30_periph_clk_is_enabled(struct clk_hw *hw)
{
- u32 val = clk_readl(c->reg);
- const struct clk_mux_sel *mux = 0;
- const struct clk_mux_sel *sel;
- if (c->flags & MUX) {
- for (sel = c->inputs; sel->input != NULL; sel++) {
- if (((val & periph_clk_source_mask(c)) >>
- periph_clk_source_shift(c)) == sel->value)
- mux = sel;
- }
- BUG_ON(!mux);
-
- c->parent = mux->input;
- } else {
- c->parent = c->inputs[0].input;
- }
-
- if (c->flags & DIV_U71) {
- u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
- if ((c->flags & DIV_U71_UART) &&
- (!(val & PERIPH_CLK_UART_DIV_ENB))) {
- divu71 = 0;
- }
- if (c->flags & DIV_U71_IDLE) {
- val &= ~(PERIPH_CLK_SOURCE_DIVU71_MASK <<
- PERIPH_CLK_SOURCE_DIVIDLE_SHIFT);
- val |= (PERIPH_CLK_SOURCE_DIVIDLE_VAL <<
- PERIPH_CLK_SOURCE_DIVIDLE_SHIFT);
- clk_writel(val, c->reg);
- }
- c->div = divu71 + 2;
- c->mul = 2;
- } else if (c->flags & DIV_U16) {
- u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK;
- c->div = divu16 + 1;
- c->mul = 1;
- } else {
- c->div = 1;
- c->mul = 1;
- }
+ struct clk_tegra *c = to_clk_tegra(hw);
c->state = ON;
if (!(clk_readl(PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_BIT(c)))
@@ -1471,11 +1686,12 @@ static void tegra30_periph_clk_init(struct clk *c)
if (!(c->flags & PERIPH_NO_RESET))
if (clk_readl(PERIPH_CLK_TO_RST_REG(c)) & PERIPH_CLK_TO_BIT(c))
c->state = OFF;
+ return c->state;
}
-static int tegra30_periph_clk_enable(struct clk *c)
+static int tegra30_periph_clk_enable(struct clk_hw *hw)
{
- pr_debug("%s on clock %s\n", __func__, c->name);
+ struct clk_tegra *c = to_clk_tegra(hw);
tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++;
if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 1)
@@ -1494,31 +1710,29 @@ static int tegra30_periph_clk_enable(struct clk *c)
return 0;
}
-static void tegra30_periph_clk_disable(struct clk *c)
+static void tegra30_periph_clk_disable(struct clk_hw *hw)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
unsigned long val;
- pr_debug("%s on clock %s\n", __func__, c->name);
- if (c->refcnt)
- tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--;
+ tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--;
- if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] == 0) {
- /* If peripheral is in the APB bus then read the APB bus to
- * flush the write operation in apb bus. This will avoid the
- * peripheral access after disabling clock*/
- if (c->flags & PERIPH_ON_APB)
- val = chipid_readl();
+ if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 0)
+ return;
- clk_writel_delay(
- PERIPH_CLK_TO_BIT(c), PERIPH_CLK_TO_ENB_CLR_REG(c));
- }
+ /* If peripheral is in the APB bus then read the APB bus to
+ * flush the write operation in apb bus. This will avoid the
+ * peripheral access after disabling clock*/
+ if (c->flags & PERIPH_ON_APB)
+ val = chipid_readl();
+
+ clk_writel_delay(PERIPH_CLK_TO_BIT(c), PERIPH_CLK_TO_ENB_CLR_REG(c));
}
-static void tegra30_periph_clk_reset(struct clk *c, bool assert)
+void tegra30_periph_clk_reset(struct clk_hw *hw, bool assert)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
unsigned long val;
- pr_debug("%s %s on clock %s\n", __func__,
- assert ? "assert" : "deassert", c->name);
if (!(c->flags & PERIPH_NO_RESET)) {
if (assert) {
@@ -1537,42 +1751,40 @@ static void tegra30_periph_clk_reset(struct clk *c, bool assert)
}
}
-static int tegra30_periph_clk_set_parent(struct clk *c, struct clk *p)
+static int tegra30_periph_clk_set_parent(struct clk_hw *hw, u8 index)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
- const struct clk_mux_sel *sel;
- pr_debug("%s: %s %s\n", __func__, c->name, p->name);
if (!(c->flags & MUX))
- return (p == c->parent) ? 0 : (-EINVAL);
+ return (index == 0) ? 0 : (-EINVAL);
- for (sel = c->inputs; sel->input != NULL; sel++) {
- if (sel->input == p) {
- val = clk_readl(c->reg);
- val &= ~periph_clk_source_mask(c);
- val |= (sel->value << periph_clk_source_shift(c));
-
- if (c->refcnt)
- clk_enable(p);
-
- clk_writel_delay(val, c->reg);
+ val = clk_readl(c->reg);
+ val &= ~periph_clk_source_mask(c);
+ val |= (index << periph_clk_source_shift(c));
+ clk_writel_delay(val, c->reg);
+ return 0;
+}
- if (c->refcnt && c->parent)
- clk_disable(c->parent);
+static u8 tegra30_periph_clk_get_parent(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u32 val = clk_readl(c->reg);
+ int source = (val & periph_clk_source_mask(c)) >>
+ periph_clk_source_shift(c);
- clk_reparent(c, p);
- return 0;
- }
- }
+ if (!(c->flags & MUX))
+ return 0;
- return -EINVAL;
+ return source;
}
-static int tegra30_periph_clk_set_rate(struct clk *c, unsigned long rate)
+static int tegra30_periph_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
int divider;
- unsigned long parent_rate = clk_get_rate(c->parent);
if (c->flags & DIV_U71) {
divider = clk_div71_get_divider(
@@ -1611,12 +1823,15 @@ static int tegra30_periph_clk_set_rate(struct clk *c, unsigned long rate)
return -EINVAL;
}
-static long tegra30_periph_clk_round_rate(struct clk *c,
- unsigned long rate)
+static long tegra30_periph_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ unsigned long parent_rate = __clk_get_rate(__clk_get_parent(hw->clk));
int divider;
- unsigned long parent_rate = clk_get_rate(c->parent);
- pr_debug("%s: %s %lu\n", __func__, c->name, rate);
+
+ if (prate)
+ parent_rate = *prate;
if (c->flags & DIV_U71) {
divider = clk_div71_get_divider(
@@ -1634,21 +1849,85 @@ static long tegra30_periph_clk_round_rate(struct clk *c,
return -EINVAL;
}
-static struct clk_ops tegra_periph_clk_ops = {
- .init = &tegra30_periph_clk_init,
+static unsigned long tegra30_periph_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u64 rate = parent_rate;
+ u32 val = clk_readl(c->reg);
+
+ if (c->flags & DIV_U71) {
+ u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
+ if ((c->flags & DIV_U71_UART) &&
+ (!(val & PERIPH_CLK_UART_DIV_ENB))) {
+ divu71 = 0;
+ }
+ if (c->flags & DIV_U71_IDLE) {
+ val &= ~(PERIPH_CLK_SOURCE_DIVU71_MASK <<
+ PERIPH_CLK_SOURCE_DIVIDLE_SHIFT);
+ val |= (PERIPH_CLK_SOURCE_DIVIDLE_VAL <<
+ PERIPH_CLK_SOURCE_DIVIDLE_SHIFT);
+ clk_writel(val, c->reg);
+ }
+ c->div = divu71 + 2;
+ c->mul = 2;
+ } else if (c->flags & DIV_U16) {
+ u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK;
+ c->div = divu16 + 1;
+ c->mul = 1;
+ } else {
+ c->div = 1;
+ c->mul = 1;
+ }
+
+ if (c->mul != 0 && c->div != 0) {
+ rate *= c->mul;
+ rate += c->div - 1; /* round up */
+ do_div(rate, c->div);
+ }
+ return rate;
+}
+
+struct clk_ops tegra30_periph_clk_ops = {
+ .is_enabled = tegra30_periph_clk_is_enabled,
+ .enable = tegra30_periph_clk_enable,
+ .disable = tegra30_periph_clk_disable,
+ .set_parent = tegra30_periph_clk_set_parent,
+ .get_parent = tegra30_periph_clk_get_parent,
+ .set_rate = tegra30_periph_clk_set_rate,
+ .round_rate = tegra30_periph_clk_round_rate,
+ .recalc_rate = tegra30_periph_clk_recalc_rate,
+};
+
+static int tegra30_dsib_clk_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk *d = clk_get_sys(NULL, "pll_d");
+ /* The DSIB parent selection bit is in PLLD base
+ register - can not do direct r-m-w, must be
+ protected by PLLD lock */
+ tegra_clk_cfg_ex(
+ d, TEGRA_CLK_PLLD_MIPI_MUX_SEL, index);
+
+ return 0;
+}
+
+struct clk_ops tegra30_dsib_clk_ops = {
+ .is_enabled = tegra30_periph_clk_is_enabled,
.enable = &tegra30_periph_clk_enable,
.disable = &tegra30_periph_clk_disable,
- .set_parent = &tegra30_periph_clk_set_parent,
+ .set_parent = &tegra30_dsib_clk_set_parent,
+ .get_parent = &tegra30_periph_clk_get_parent,
.set_rate = &tegra30_periph_clk_set_rate,
.round_rate = &tegra30_periph_clk_round_rate,
- .reset = &tegra30_periph_clk_reset,
+ .recalc_rate = &tegra30_periph_clk_recalc_rate,
};
-
/* Periph extended clock configuration ops */
-static int
-tegra30_vi_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+int tegra30_vi_clk_cfg_ex(struct clk_hw *hw,
+ enum tegra_clk_ex_param p, u32 setting)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
+
if (p == TEGRA_CLK_VI_INP_SEL) {
u32 val = clk_readl(c->reg);
val &= ~PERIPH_CLK_VI_SEL_EX_MASK;
@@ -1660,20 +1939,11 @@ tegra30_vi_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
return -EINVAL;
}
-static struct clk_ops tegra_vi_clk_ops = {
- .init = &tegra30_periph_clk_init,
- .enable = &tegra30_periph_clk_enable,
- .disable = &tegra30_periph_clk_disable,
- .set_parent = &tegra30_periph_clk_set_parent,
- .set_rate = &tegra30_periph_clk_set_rate,
- .round_rate = &tegra30_periph_clk_round_rate,
- .clk_cfg_ex = &tegra30_vi_clk_cfg_ex,
- .reset = &tegra30_periph_clk_reset,
-};
-
-static int
-tegra30_nand_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+int tegra30_nand_clk_cfg_ex(struct clk_hw *hw,
+ enum tegra_clk_ex_param p, u32 setting)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
+
if (p == TEGRA_CLK_NAND_PAD_DIV2_ENB) {
u32 val = clk_readl(c->reg);
if (setting)
@@ -1686,21 +1956,11 @@ tegra30_nand_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
return -EINVAL;
}
-static struct clk_ops tegra_nand_clk_ops = {
- .init = &tegra30_periph_clk_init,
- .enable = &tegra30_periph_clk_enable,
- .disable = &tegra30_periph_clk_disable,
- .set_parent = &tegra30_periph_clk_set_parent,
- .set_rate = &tegra30_periph_clk_set_rate,
- .round_rate = &tegra30_periph_clk_round_rate,
- .clk_cfg_ex = &tegra30_nand_clk_cfg_ex,
- .reset = &tegra30_periph_clk_reset,
-};
-
-
-static int
-tegra30_dtv_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+int tegra30_dtv_clk_cfg_ex(struct clk_hw *hw,
+ enum tegra_clk_ex_param p, u32 setting)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
+
if (p == TEGRA_CLK_DTV_INVERT) {
u32 val = clk_readl(c->reg);
if (setting)
@@ -1713,91 +1973,27 @@ tegra30_dtv_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
return -EINVAL;
}
-static struct clk_ops tegra_dtv_clk_ops = {
- .init = &tegra30_periph_clk_init,
- .enable = &tegra30_periph_clk_enable,
- .disable = &tegra30_periph_clk_disable,
- .set_parent = &tegra30_periph_clk_set_parent,
- .set_rate = &tegra30_periph_clk_set_rate,
- .round_rate = &tegra30_periph_clk_round_rate,
- .clk_cfg_ex = &tegra30_dtv_clk_cfg_ex,
- .reset = &tegra30_periph_clk_reset,
-};
-
-static int tegra30_dsib_clk_set_parent(struct clk *c, struct clk *p)
-{
- const struct clk_mux_sel *sel;
- struct clk *d = tegra_get_clock_by_name("pll_d");
-
- pr_debug("%s: %s %s\n", __func__, c->name, p->name);
-
- for (sel = c->inputs; sel->input != NULL; sel++) {
- if (sel->input == p) {
- if (c->refcnt)
- clk_enable(p);
-
- /* The DSIB parent selection bit is in PLLD base
- register - can not do direct r-m-w, must be
- protected by PLLD lock */
- tegra_clk_cfg_ex(
- d, TEGRA_CLK_PLLD_MIPI_MUX_SEL, sel->value);
-
- if (c->refcnt && c->parent)
- clk_disable(c->parent);
-
- clk_reparent(c, p);
- return 0;
- }
- }
-
- return -EINVAL;
-}
-
-static struct clk_ops tegra_dsib_clk_ops = {
- .init = &tegra30_periph_clk_init,
- .enable = &tegra30_periph_clk_enable,
- .disable = &tegra30_periph_clk_disable,
- .set_parent = &tegra30_dsib_clk_set_parent,
- .set_rate = &tegra30_periph_clk_set_rate,
- .round_rate = &tegra30_periph_clk_round_rate,
- .reset = &tegra30_periph_clk_reset,
-};
-
-/* pciex clock support only reset function */
-static struct clk_ops tegra_pciex_clk_ops = {
- .reset = tegra30_periph_clk_reset,
-};
-
/* Output clock ops */
static DEFINE_SPINLOCK(clk_out_lock);
-static void tegra30_clk_out_init(struct clk *c)
+static int tegra30_clk_out_is_enabled(struct clk_hw *hw)
{
- const struct clk_mux_sel *mux = 0;
- const struct clk_mux_sel *sel;
+ struct clk_tegra *c = to_clk_tegra(hw);
u32 val = pmc_readl(c->reg);
c->state = (val & (0x1 << c->u.periph.clk_num)) ? ON : OFF;
c->mul = 1;
c->div = 1;
-
- for (sel = c->inputs; sel->input != NULL; sel++) {
- if (((val & periph_clk_source_mask(c)) >>
- periph_clk_source_shift(c)) == sel->value)
- mux = sel;
- }
- BUG_ON(!mux);
- c->parent = mux->input;
+ return c->state;
}
-static int tegra30_clk_out_enable(struct clk *c)
+static int tegra30_clk_out_enable(struct clk_hw *hw)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
unsigned long flags;
- pr_debug("%s on clock %s\n", __func__, c->name);
-
spin_lock_irqsave(&clk_out_lock, flags);
val = pmc_readl(c->reg);
val |= (0x1 << c->u.periph.clk_num);
@@ -1807,13 +2003,12 @@ static int tegra30_clk_out_enable(struct clk *c)
return 0;
}
-static void tegra30_clk_out_disable(struct clk *c)
+static void tegra30_clk_out_disable(struct clk_hw *hw)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
unsigned long flags;
- pr_debug("%s on clock %s\n", __func__, c->name);
-
spin_lock_irqsave(&clk_out_lock, flags);
val = pmc_readl(c->reg);
val &= ~(0x1 << c->u.periph.clk_num);
@@ -1821,59 +2016,59 @@ static void tegra30_clk_out_disable(struct clk *c)
spin_unlock_irqrestore(&clk_out_lock, flags);
}
-static int tegra30_clk_out_set_parent(struct clk *c, struct clk *p)
+static int tegra30_clk_out_set_parent(struct clk_hw *hw, u8 index)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
unsigned long flags;
- const struct clk_mux_sel *sel;
- pr_debug("%s: %s %s\n", __func__, c->name, p->name);
-
- for (sel = c->inputs; sel->input != NULL; sel++) {
- if (sel->input == p) {
- if (c->refcnt)
- clk_enable(p);
+ spin_lock_irqsave(&clk_out_lock, flags);
+ val = pmc_readl(c->reg);
+ val &= ~periph_clk_source_mask(c);
+ val |= (index << periph_clk_source_shift(c));
+ pmc_writel(val, c->reg);
+ spin_unlock_irqrestore(&clk_out_lock, flags);
- spin_lock_irqsave(&clk_out_lock, flags);
- val = pmc_readl(c->reg);
- val &= ~periph_clk_source_mask(c);
- val |= (sel->value << periph_clk_source_shift(c));
- pmc_writel(val, c->reg);
- spin_unlock_irqrestore(&clk_out_lock, flags);
+ return 0;
+}
- if (c->refcnt && c->parent)
- clk_disable(c->parent);
+static u8 tegra30_clk_out_get_parent(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u32 val = pmc_readl(c->reg);
+ int source;
- clk_reparent(c, p);
- return 0;
- }
- }
- return -EINVAL;
+ source = (val & periph_clk_source_mask(c)) >>
+ periph_clk_source_shift(c);
+ return source;
}
-static struct clk_ops tegra_clk_out_ops = {
- .init = &tegra30_clk_out_init,
- .enable = &tegra30_clk_out_enable,
- .disable = &tegra30_clk_out_disable,
- .set_parent = &tegra30_clk_out_set_parent,
+struct clk_ops tegra_clk_out_ops = {
+ .is_enabled = tegra30_clk_out_is_enabled,
+ .enable = tegra30_clk_out_enable,
+ .disable = tegra30_clk_out_disable,
+ .set_parent = tegra30_clk_out_set_parent,
+ .get_parent = tegra30_clk_out_get_parent,
+ .recalc_rate = tegra30_clk_fixed_recalc_rate,
};
-
/* Clock doubler ops */
-static void tegra30_clk_double_init(struct clk *c)
+static int tegra30_clk_double_is_enabled(struct clk_hw *hw)
{
- u32 val = clk_readl(c->reg);
- c->mul = val & (0x1 << c->reg_shift) ? 1 : 2;
- c->div = 1;
+ struct clk_tegra *c = to_clk_tegra(hw);
+
c->state = ON;
if (!(clk_readl(PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_BIT(c)))
c->state = OFF;
+ return c->state;
};
-static int tegra30_clk_double_set_rate(struct clk *c, unsigned long rate)
+static int tegra30_clk_double_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
- unsigned long parent_rate = clk_get_rate(c->parent);
+
if (rate == parent_rate) {
val = clk_readl(c->reg) | (0x1 << c->reg_shift);
clk_writel(val, c->reg);
@@ -1890,1215 +2085,139 @@ static int tegra30_clk_double_set_rate(struct clk *c, unsigned long rate)
return -EINVAL;
}
-static struct clk_ops tegra_clk_double_ops = {
- .init = &tegra30_clk_double_init,
- .enable = &tegra30_periph_clk_enable,
- .disable = &tegra30_periph_clk_disable,
- .set_rate = &tegra30_clk_double_set_rate,
-};
+static unsigned long tegra30_clk_double_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u64 rate = parent_rate;
-/* Audio sync clock ops */
-static int tegra30_sync_source_set_rate(struct clk *c, unsigned long rate)
+ u32 val = clk_readl(c->reg);
+ c->mul = val & (0x1 << c->reg_shift) ? 1 : 2;
+ c->div = 1;
+
+ if (c->mul != 0 && c->div != 0) {
+ rate *= c->mul;
+ rate += c->div - 1; /* round up */
+ do_div(rate, c->div);
+ }
+
+ return rate;
+}
+
+static long tegra30_clk_double_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
{
- c->rate = rate;
- return 0;
+ unsigned long output_rate = *prate;
+
+ do_div(output_rate, 2);
+ return output_rate;
}
-static struct clk_ops tegra_sync_source_ops = {
- .set_rate = &tegra30_sync_source_set_rate,
+struct clk_ops tegra30_clk_double_ops = {
+ .is_enabled = tegra30_clk_double_is_enabled,
+ .enable = tegra30_periph_clk_enable,
+ .disable = tegra30_periph_clk_disable,
+ .recalc_rate = tegra30_clk_double_recalc_rate,
+ .round_rate = tegra30_clk_double_round_rate,
+ .set_rate = tegra30_clk_double_set_rate,
};
-static void tegra30_audio_sync_clk_init(struct clk *c)
+/* Audio sync clock ops */
+struct clk_ops tegra_sync_source_ops = {
+ .recalc_rate = tegra30_clk_fixed_recalc_rate,
+};
+
+static int tegra30_audio_sync_clk_is_enabled(struct clk_hw *hw)
{
- int source;
- const struct clk_mux_sel *sel;
+ struct clk_tegra *c = to_clk_tegra(hw);
u32 val = clk_readl(c->reg);
c->state = (val & AUDIO_SYNC_DISABLE_BIT) ? OFF : ON;
- source = val & AUDIO_SYNC_SOURCE_MASK;
- for (sel = c->inputs; sel->input != NULL; sel++)
- if (sel->value == source)
- break;
- BUG_ON(sel->input == NULL);
- c->parent = sel->input;
+ return c->state;
}
-static int tegra30_audio_sync_clk_enable(struct clk *c)
+static int tegra30_audio_sync_clk_enable(struct clk_hw *hw)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
u32 val = clk_readl(c->reg);
clk_writel((val & (~AUDIO_SYNC_DISABLE_BIT)), c->reg);
return 0;
}
-static void tegra30_audio_sync_clk_disable(struct clk *c)
+static void tegra30_audio_sync_clk_disable(struct clk_hw *hw)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
u32 val = clk_readl(c->reg);
clk_writel((val | AUDIO_SYNC_DISABLE_BIT), c->reg);
}
-static int tegra30_audio_sync_clk_set_parent(struct clk *c, struct clk *p)
+static int tegra30_audio_sync_clk_set_parent(struct clk_hw *hw, u8 index)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
u32 val;
- const struct clk_mux_sel *sel;
- for (sel = c->inputs; sel->input != NULL; sel++) {
- if (sel->input == p) {
- val = clk_readl(c->reg);
- val &= ~AUDIO_SYNC_SOURCE_MASK;
- val |= sel->value;
-
- if (c->refcnt)
- clk_enable(p);
- clk_writel(val, c->reg);
+ val = clk_readl(c->reg);
+ val &= ~AUDIO_SYNC_SOURCE_MASK;
+ val |= index;
- if (c->refcnt && c->parent)
- clk_disable(c->parent);
+ clk_writel(val, c->reg);
+ return 0;
+}
- clk_reparent(c, p);
- return 0;
- }
- }
+static u8 tegra30_audio_sync_clk_get_parent(struct clk_hw *hw)
+{
+ struct clk_tegra *c = to_clk_tegra(hw);
+ u32 val = clk_readl(c->reg);
+ int source;
- return -EINVAL;
+ source = val & AUDIO_SYNC_SOURCE_MASK;
+ return source;
}
-static struct clk_ops tegra_audio_sync_clk_ops = {
- .init = tegra30_audio_sync_clk_init,
- .enable = tegra30_audio_sync_clk_enable,
- .disable = tegra30_audio_sync_clk_disable,
+struct clk_ops tegra30_audio_sync_clk_ops = {
+ .is_enabled = tegra30_audio_sync_clk_is_enabled,
+ .enable = tegra30_audio_sync_clk_enable,
+ .disable = tegra30_audio_sync_clk_disable,
.set_parent = tegra30_audio_sync_clk_set_parent,
+ .get_parent = tegra30_audio_sync_clk_get_parent,
+ .recalc_rate = tegra30_clk_fixed_recalc_rate,
};
/* cml0 (pcie), and cml1 (sata) clock ops */
-static void tegra30_cml_clk_init(struct clk *c)
+static int tegra30_cml_clk_is_enabled(struct clk_hw *hw)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
u32 val = clk_readl(c->reg);
c->state = val & (0x1 << c->u.periph.clk_num) ? ON : OFF;
+ return c->state;
}
-static int tegra30_cml_clk_enable(struct clk *c)
+static int tegra30_cml_clk_enable(struct clk_hw *hw)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
+
u32 val = clk_readl(c->reg);
val |= (0x1 << c->u.periph.clk_num);
clk_writel(val, c->reg);
+
return 0;
}
-static void tegra30_cml_clk_disable(struct clk *c)
+static void tegra30_cml_clk_disable(struct clk_hw *hw)
{
+ struct clk_tegra *c = to_clk_tegra(hw);
+
u32 val = clk_readl(c->reg);
val &= ~(0x1 << c->u.periph.clk_num);
clk_writel(val, c->reg);
}
-static struct clk_ops tegra_cml_clk_ops = {
- .init = &tegra30_cml_clk_init,
- .enable = &tegra30_cml_clk_enable,
- .disable = &tegra30_cml_clk_disable,
-};
-
-/* Clock definitions */
-static struct clk tegra_clk_32k = {
- .name = "clk_32k",
- .rate = 32768,
- .ops = NULL,
- .max_rate = 32768,
-};
-
-static struct clk tegra_clk_m = {
- .name = "clk_m",
- .flags = ENABLE_ON_INIT,
- .ops = &tegra_clk_m_ops,
- .reg = 0x1fc,
- .reg_shift = 28,
- .max_rate = 48000000,
-};
-
-static struct clk tegra_clk_m_div2 = {
- .name = "clk_m_div2",
- .ops = &tegra_clk_m_div_ops,
- .parent = &tegra_clk_m,
- .mul = 1,
- .div = 2,
- .state = ON,
- .max_rate = 24000000,
-};
-
-static struct clk tegra_clk_m_div4 = {
- .name = "clk_m_div4",
- .ops = &tegra_clk_m_div_ops,
- .parent = &tegra_clk_m,
- .mul = 1,
- .div = 4,
- .state = ON,
- .max_rate = 12000000,
-};
-
-static struct clk tegra_pll_ref = {
- .name = "pll_ref",
- .flags = ENABLE_ON_INIT,
- .ops = &tegra_pll_ref_ops,
- .parent = &tegra_clk_m,
- .max_rate = 26000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_c_freq_table[] = {
- { 12000000, 1040000000, 520, 6, 1, 8},
- { 13000000, 1040000000, 480, 6, 1, 8},
- { 16800000, 1040000000, 495, 8, 1, 8}, /* actual: 1039.5 MHz */
- { 19200000, 1040000000, 325, 6, 1, 6},
- { 26000000, 1040000000, 520, 13, 1, 8},
-
- { 12000000, 832000000, 416, 6, 1, 8},
- { 13000000, 832000000, 832, 13, 1, 8},
- { 16800000, 832000000, 396, 8, 1, 8}, /* actual: 831.6 MHz */
- { 19200000, 832000000, 260, 6, 1, 8},
- { 26000000, 832000000, 416, 13, 1, 8},
-
- { 12000000, 624000000, 624, 12, 1, 8},
- { 13000000, 624000000, 624, 13, 1, 8},
- { 16800000, 600000000, 520, 14, 1, 8},
- { 19200000, 624000000, 520, 16, 1, 8},
- { 26000000, 624000000, 624, 26, 1, 8},
-
- { 12000000, 600000000, 600, 12, 1, 8},
- { 13000000, 600000000, 600, 13, 1, 8},
- { 16800000, 600000000, 500, 14, 1, 8},
- { 19200000, 600000000, 375, 12, 1, 6},
- { 26000000, 600000000, 600, 26, 1, 8},
-
- { 12000000, 520000000, 520, 12, 1, 8},
- { 13000000, 520000000, 520, 13, 1, 8},
- { 16800000, 520000000, 495, 16, 1, 8}, /* actual: 519.75 MHz */
- { 19200000, 520000000, 325, 12, 1, 6},
- { 26000000, 520000000, 520, 26, 1, 8},
-
- { 12000000, 416000000, 416, 12, 1, 8},
- { 13000000, 416000000, 416, 13, 1, 8},
- { 16800000, 416000000, 396, 16, 1, 8}, /* actual: 415.8 MHz */
- { 19200000, 416000000, 260, 12, 1, 6},
- { 26000000, 416000000, 416, 26, 1, 8},
- { 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_c = {
- .name = "pll_c",
- .flags = PLL_HAS_CPCON,
- .ops = &tegra_pll_ops,
- .reg = 0x80,
- .parent = &tegra_pll_ref,
- .max_rate = 1400000000,
- .u.pll = {
- .input_min = 2000000,
- .input_max = 31000000,
- .cf_min = 1000000,
- .cf_max = 6000000,
- .vco_min = 20000000,
- .vco_max = 1400000000,
- .freq_table = tegra_pll_c_freq_table,
- .lock_delay = 300,
- },
-};
-
-static struct clk tegra_pll_c_out1 = {
- .name = "pll_c_out1",
- .ops = &tegra_pll_div_ops,
- .flags = DIV_U71,
- .parent = &tegra_pll_c,
- .reg = 0x84,
- .reg_shift = 0,
- .max_rate = 700000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_m_freq_table[] = {
- { 12000000, 666000000, 666, 12, 1, 8},
- { 13000000, 666000000, 666, 13, 1, 8},
- { 16800000, 666000000, 555, 14, 1, 8},
- { 19200000, 666000000, 555, 16, 1, 8},
- { 26000000, 666000000, 666, 26, 1, 8},
- { 12000000, 600000000, 600, 12, 1, 8},
- { 13000000, 600000000, 600, 13, 1, 8},
- { 16800000, 600000000, 500, 14, 1, 8},
- { 19200000, 600000000, 375, 12, 1, 6},
- { 26000000, 600000000, 600, 26, 1, 8},
- { 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_m = {
- .name = "pll_m",
- .flags = PLL_HAS_CPCON | PLLM,
- .ops = &tegra_pll_ops,
- .reg = 0x90,
- .parent = &tegra_pll_ref,
- .max_rate = 800000000,
- .u.pll = {
- .input_min = 2000000,
- .input_max = 31000000,
- .cf_min = 1000000,
- .cf_max = 6000000,
- .vco_min = 20000000,
- .vco_max = 1200000000,
- .freq_table = tegra_pll_m_freq_table,
- .lock_delay = 300,
- },
-};
-
-static struct clk tegra_pll_m_out1 = {
- .name = "pll_m_out1",
- .ops = &tegra_pll_div_ops,
- .flags = DIV_U71,
- .parent = &tegra_pll_m,
- .reg = 0x94,
- .reg_shift = 0,
- .max_rate = 600000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_p_freq_table[] = {
- { 12000000, 216000000, 432, 12, 2, 8},
- { 13000000, 216000000, 432, 13, 2, 8},
- { 16800000, 216000000, 360, 14, 2, 8},
- { 19200000, 216000000, 360, 16, 2, 8},
- { 26000000, 216000000, 432, 26, 2, 8},
- { 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_p = {
- .name = "pll_p",
- .flags = ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON,
- .ops = &tegra_pll_ops,
- .reg = 0xa0,
- .parent = &tegra_pll_ref,
- .max_rate = 432000000,
- .u.pll = {
- .input_min = 2000000,
- .input_max = 31000000,
- .cf_min = 1000000,
- .cf_max = 6000000,
- .vco_min = 20000000,
- .vco_max = 1400000000,
- .freq_table = tegra_pll_p_freq_table,
- .lock_delay = 300,
- .fixed_rate = 408000000,
- },
-};
-
-static struct clk tegra_pll_p_out1 = {
- .name = "pll_p_out1",
- .ops = &tegra_pll_div_ops,
- .flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
- .parent = &tegra_pll_p,
- .reg = 0xa4,
- .reg_shift = 0,
- .max_rate = 432000000,
-};
-
-static struct clk tegra_pll_p_out2 = {
- .name = "pll_p_out2",
- .ops = &tegra_pll_div_ops,
- .flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
- .parent = &tegra_pll_p,
- .reg = 0xa4,
- .reg_shift = 16,
- .max_rate = 432000000,
-};
-
-static struct clk tegra_pll_p_out3 = {
- .name = "pll_p_out3",
- .ops = &tegra_pll_div_ops,
- .flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
- .parent = &tegra_pll_p,
- .reg = 0xa8,
- .reg_shift = 0,
- .max_rate = 432000000,
-};
-
-static struct clk tegra_pll_p_out4 = {
- .name = "pll_p_out4",
- .ops = &tegra_pll_div_ops,
- .flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
- .parent = &tegra_pll_p,
- .reg = 0xa8,
- .reg_shift = 16,
- .max_rate = 432000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_a_freq_table[] = {
- { 9600000, 564480000, 294, 5, 1, 4},
- { 9600000, 552960000, 288, 5, 1, 4},
- { 9600000, 24000000, 5, 2, 1, 1},
-
- { 28800000, 56448000, 49, 25, 1, 1},
- { 28800000, 73728000, 64, 25, 1, 1},
- { 28800000, 24000000, 5, 6, 1, 1},
- { 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_a = {
- .name = "pll_a",
- .flags = PLL_HAS_CPCON,
- .ops = &tegra_pll_ops,
- .reg = 0xb0,
- .parent = &tegra_pll_p_out1,
- .max_rate = 700000000,
- .u.pll = {
- .input_min = 2000000,
- .input_max = 31000000,
- .cf_min = 1000000,
- .cf_max = 6000000,
- .vco_min = 20000000,
- .vco_max = 1400000000,
- .freq_table = tegra_pll_a_freq_table,
- .lock_delay = 300,
- },
-};
-
-static struct clk tegra_pll_a_out0 = {
- .name = "pll_a_out0",
- .ops = &tegra_pll_div_ops,
- .flags = DIV_U71,
- .parent = &tegra_pll_a,
- .reg = 0xb4,
- .reg_shift = 0,
- .max_rate = 100000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
- { 12000000, 216000000, 216, 12, 1, 4},
- { 13000000, 216000000, 216, 13, 1, 4},
- { 16800000, 216000000, 180, 14, 1, 4},
- { 19200000, 216000000, 180, 16, 1, 4},
- { 26000000, 216000000, 216, 26, 1, 4},
-
- { 12000000, 594000000, 594, 12, 1, 8},
- { 13000000, 594000000, 594, 13, 1, 8},
- { 16800000, 594000000, 495, 14, 1, 8},
- { 19200000, 594000000, 495, 16, 1, 8},
- { 26000000, 594000000, 594, 26, 1, 8},
-
- { 12000000, 1000000000, 1000, 12, 1, 12},
- { 13000000, 1000000000, 1000, 13, 1, 12},
- { 19200000, 1000000000, 625, 12, 1, 8},
- { 26000000, 1000000000, 1000, 26, 1, 12},
-
- { 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_d = {
- .name = "pll_d",
- .flags = PLL_HAS_CPCON | PLLD,
- .ops = &tegra_plld_ops,
- .reg = 0xd0,
- .parent = &tegra_pll_ref,
- .max_rate = 1000000000,
- .u.pll = {
- .input_min = 2000000,
- .input_max = 40000000,
- .cf_min = 1000000,
- .cf_max = 6000000,
- .vco_min = 40000000,
- .vco_max = 1000000000,
- .freq_table = tegra_pll_d_freq_table,
- .lock_delay = 1000,
- },
-};
-
-static struct clk tegra_pll_d_out0 = {
- .name = "pll_d_out0",
- .ops = &tegra_pll_div_ops,
- .flags = DIV_2 | PLLD,
- .parent = &tegra_pll_d,
- .max_rate = 500000000,
-};
-
-static struct clk tegra_pll_d2 = {
- .name = "pll_d2",
- .flags = PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLD,
- .ops = &tegra_plld_ops,
- .reg = 0x4b8,
- .parent = &tegra_pll_ref,
- .max_rate = 1000000000,
- .u.pll = {
- .input_min = 2000000,
- .input_max = 40000000,
- .cf_min = 1000000,
- .cf_max = 6000000,
- .vco_min = 40000000,
- .vco_max = 1000000000,
- .freq_table = tegra_pll_d_freq_table,
- .lock_delay = 1000,
- },
-};
-
-static struct clk tegra_pll_d2_out0 = {
- .name = "pll_d2_out0",
- .ops = &tegra_pll_div_ops,
- .flags = DIV_2 | PLLD,
- .parent = &tegra_pll_d2,
- .max_rate = 500000000,
-};
-
-static struct clk_pll_freq_table tegra_pll_u_freq_table[] = {
- { 12000000, 480000000, 960, 12, 2, 12},
- { 13000000, 480000000, 960, 13, 2, 12},
- { 16800000, 480000000, 400, 7, 2, 5},
- { 19200000, 480000000, 200, 4, 2, 3},
- { 26000000, 480000000, 960, 26, 2, 12},
- { 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_u = {
- .name = "pll_u",
- .flags = PLL_HAS_CPCON | PLLU,
- .ops = &tegra_pll_ops,
- .reg = 0xc0,
- .parent = &tegra_pll_ref,
- .max_rate = 480000000,
- .u.pll = {
- .input_min = 2000000,
- .input_max = 40000000,
- .cf_min = 1000000,
- .cf_max = 6000000,
- .vco_min = 480000000,
- .vco_max = 960000000,
- .freq_table = tegra_pll_u_freq_table,
- .lock_delay = 1000,
- },
-};
-
-static struct clk_pll_freq_table tegra_pll_x_freq_table[] = {
- /* 1.7 GHz */
- { 12000000, 1700000000, 850, 6, 1, 8},
- { 13000000, 1700000000, 915, 7, 1, 8}, /* actual: 1699.2 MHz */
- { 16800000, 1700000000, 708, 7, 1, 8}, /* actual: 1699.2 MHz */
- { 19200000, 1700000000, 885, 10, 1, 8}, /* actual: 1699.2 MHz */
- { 26000000, 1700000000, 850, 13, 1, 8},
-
- /* 1.6 GHz */
- { 12000000, 1600000000, 800, 6, 1, 8},
- { 13000000, 1600000000, 738, 6, 1, 8}, /* actual: 1599.0 MHz */
- { 16800000, 1600000000, 857, 9, 1, 8}, /* actual: 1599.7 MHz */
- { 19200000, 1600000000, 500, 6, 1, 8},
- { 26000000, 1600000000, 800, 13, 1, 8},
-
- /* 1.5 GHz */
- { 12000000, 1500000000, 750, 6, 1, 8},
- { 13000000, 1500000000, 923, 8, 1, 8}, /* actual: 1499.8 MHz */
- { 16800000, 1500000000, 625, 7, 1, 8},
- { 19200000, 1500000000, 625, 8, 1, 8},
- { 26000000, 1500000000, 750, 13, 1, 8},
-
- /* 1.4 GHz */
- { 12000000, 1400000000, 700, 6, 1, 8},
- { 13000000, 1400000000, 969, 9, 1, 8}, /* actual: 1399.7 MHz */
- { 16800000, 1400000000, 1000, 12, 1, 8},
- { 19200000, 1400000000, 875, 12, 1, 8},
- { 26000000, 1400000000, 700, 13, 1, 8},
-
- /* 1.3 GHz */
- { 12000000, 1300000000, 975, 9, 1, 8},
- { 13000000, 1300000000, 1000, 10, 1, 8},
- { 16800000, 1300000000, 928, 12, 1, 8}, /* actual: 1299.2 MHz */
- { 19200000, 1300000000, 812, 12, 1, 8}, /* actual: 1299.2 MHz */
- { 26000000, 1300000000, 650, 13, 1, 8},
-
- /* 1.2 GHz */
- { 12000000, 1200000000, 1000, 10, 1, 8},
- { 13000000, 1200000000, 923, 10, 1, 8}, /* actual: 1199.9 MHz */
- { 16800000, 1200000000, 1000, 14, 1, 8},
- { 19200000, 1200000000, 1000, 16, 1, 8},
- { 26000000, 1200000000, 600, 13, 1, 8},
-
- /* 1.1 GHz */
- { 12000000, 1100000000, 825, 9, 1, 8},
- { 13000000, 1100000000, 846, 10, 1, 8}, /* actual: 1099.8 MHz */
- { 16800000, 1100000000, 982, 15, 1, 8}, /* actual: 1099.8 MHz */
- { 19200000, 1100000000, 859, 15, 1, 8}, /* actual: 1099.5 MHz */
- { 26000000, 1100000000, 550, 13, 1, 8},
-
- /* 1 GHz */
- { 12000000, 1000000000, 1000, 12, 1, 8},
- { 13000000, 1000000000, 1000, 13, 1, 8},
- { 16800000, 1000000000, 833, 14, 1, 8}, /* actual: 999.6 MHz */
- { 19200000, 1000000000, 625, 12, 1, 8},
- { 26000000, 1000000000, 1000, 26, 1, 8},
-
- { 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_x = {
- .name = "pll_x",
- .flags = PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLX,
- .ops = &tegra_pll_ops,
- .reg = 0xe0,
- .parent = &tegra_pll_ref,
- .max_rate = 1700000000,
- .u.pll = {
- .input_min = 2000000,
- .input_max = 31000000,
- .cf_min = 1000000,
- .cf_max = 6000000,
- .vco_min = 20000000,
- .vco_max = 1700000000,
- .freq_table = tegra_pll_x_freq_table,
- .lock_delay = 300,
- },
-};
-
-static struct clk tegra_pll_x_out0 = {
- .name = "pll_x_out0",
- .ops = &tegra_pll_div_ops,
- .flags = DIV_2 | PLLX,
- .parent = &tegra_pll_x,
- .max_rate = 850000000,
-};
-
-
-static struct clk_pll_freq_table tegra_pll_e_freq_table[] = {
- /* PLLE special case: use cpcon field to store cml divider value */
- { 12000000, 100000000, 150, 1, 18, 11},
- { 216000000, 100000000, 200, 18, 24, 13},
- { 0, 0, 0, 0, 0, 0 },
-};
-
-static struct clk tegra_pll_e = {
- .name = "pll_e",
- .flags = PLL_ALT_MISC_REG,
- .ops = &tegra_plle_ops,
- .reg = 0xe8,
- .max_rate = 100000000,
- .u.pll = {
- .input_min = 12000000,
- .input_max = 216000000,
- .cf_min = 12000000,
- .cf_max = 12000000,
- .vco_min = 1200000000,
- .vco_max = 2400000000U,
- .freq_table = tegra_pll_e_freq_table,
- .lock_delay = 300,
- .fixed_rate = 100000000,
- },
-};
-
-static struct clk tegra_cml0_clk = {
- .name = "cml0",
- .parent = &tegra_pll_e,
- .ops = &tegra_cml_clk_ops,
- .reg = PLLE_AUX,
- .max_rate = 100000000,
- .u.periph = {
- .clk_num = 0,
- },
-};
-
-static struct clk tegra_cml1_clk = {
- .name = "cml1",
- .parent = &tegra_pll_e,
- .ops = &tegra_cml_clk_ops,
- .reg = PLLE_AUX,
- .max_rate = 100000000,
- .u.periph = {
- .clk_num = 1,
- },
-};
-
-static struct clk tegra_pciex_clk = {
- .name = "pciex",
- .parent = &tegra_pll_e,
- .ops = &tegra_pciex_clk_ops,
- .max_rate = 100000000,
- .u.periph = {
- .clk_num = 74,
- },
-};
-
-/* Audio sync clocks */
-#define SYNC_SOURCE(_id) \
- { \
- .name = #_id "_sync", \
- .rate = 24000000, \
- .max_rate = 24000000, \
- .ops = &tegra_sync_source_ops \
- }
-static struct clk tegra_sync_source_list[] = {
- SYNC_SOURCE(spdif_in),
- SYNC_SOURCE(i2s0),
- SYNC_SOURCE(i2s1),
- SYNC_SOURCE(i2s2),
- SYNC_SOURCE(i2s3),
- SYNC_SOURCE(i2s4),
- SYNC_SOURCE(vimclk),
-};
-
-static struct clk_mux_sel mux_audio_sync_clk[] = {
- { .input = &tegra_sync_source_list[0], .value = 0},
- { .input = &tegra_sync_source_list[1], .value = 1},
- { .input = &tegra_sync_source_list[2], .value = 2},
- { .input = &tegra_sync_source_list[3], .value = 3},
- { .input = &tegra_sync_source_list[4], .value = 4},
- { .input = &tegra_sync_source_list[5], .value = 5},
- { .input = &tegra_pll_a_out0, .value = 6},
- { .input = &tegra_sync_source_list[6], .value = 7},
- { 0, 0 }
-};
-
-#define AUDIO_SYNC_CLK(_id, _index) \
- { \
- .name = #_id, \
- .inputs = mux_audio_sync_clk, \
- .reg = 0x4A0 + (_index) * 4, \
- .max_rate = 24000000, \
- .ops = &tegra_audio_sync_clk_ops \
- }
-static struct clk tegra_clk_audio_list[] = {
- AUDIO_SYNC_CLK(audio0, 0),
- AUDIO_SYNC_CLK(audio1, 1),
- AUDIO_SYNC_CLK(audio2, 2),
- AUDIO_SYNC_CLK(audio3, 3),
- AUDIO_SYNC_CLK(audio4, 4),
- AUDIO_SYNC_CLK(audio, 5), /* SPDIF */
-};
-
-#define AUDIO_SYNC_2X_CLK(_id, _index) \
- { \
- .name = #_id "_2x", \
- .flags = PERIPH_NO_RESET, \
- .max_rate = 48000000, \
- .ops = &tegra_clk_double_ops, \
- .reg = 0x49C, \
- .reg_shift = 24 + (_index), \
- .parent = &tegra_clk_audio_list[(_index)], \
- .u.periph = { \
- .clk_num = 113 + (_index), \
- }, \
- }
-static struct clk tegra_clk_audio_2x_list[] = {
- AUDIO_SYNC_2X_CLK(audio0, 0),
- AUDIO_SYNC_2X_CLK(audio1, 1),
- AUDIO_SYNC_2X_CLK(audio2, 2),
- AUDIO_SYNC_2X_CLK(audio3, 3),
- AUDIO_SYNC_2X_CLK(audio4, 4),
- AUDIO_SYNC_2X_CLK(audio, 5), /* SPDIF */
-};
-
-#define MUX_I2S_SPDIF(_id, _index) \
-static struct clk_mux_sel mux_pllaout0_##_id##_2x_pllp_clkm[] = { \
- {.input = &tegra_pll_a_out0, .value = 0}, \
- {.input = &tegra_clk_audio_2x_list[(_index)], .value = 1}, \
- {.input = &tegra_pll_p, .value = 2}, \
- {.input = &tegra_clk_m, .value = 3}, \
- { 0, 0}, \
-}
-MUX_I2S_SPDIF(audio0, 0);
-MUX_I2S_SPDIF(audio1, 1);
-MUX_I2S_SPDIF(audio2, 2);
-MUX_I2S_SPDIF(audio3, 3);
-MUX_I2S_SPDIF(audio4, 4);
-MUX_I2S_SPDIF(audio, 5); /* SPDIF */
-
-/* External clock outputs (through PMC) */
-#define MUX_EXTERN_OUT(_id) \
-static struct clk_mux_sel mux_clkm_clkm2_clkm4_extern##_id[] = { \
- {.input = &tegra_clk_m, .value = 0}, \
- {.input = &tegra_clk_m_div2, .value = 1}, \
- {.input = &tegra_clk_m_div4, .value = 2}, \
- {.input = NULL, .value = 3}, /* placeholder */ \
- { 0, 0}, \
-}
-MUX_EXTERN_OUT(1);
-MUX_EXTERN_OUT(2);
-MUX_EXTERN_OUT(3);
-
-static struct clk_mux_sel *mux_extern_out_list[] = {
- mux_clkm_clkm2_clkm4_extern1,
- mux_clkm_clkm2_clkm4_extern2,
- mux_clkm_clkm2_clkm4_extern3,
-};
-
-#define CLK_OUT_CLK(_id) \
- { \
- .name = "clk_out_" #_id, \
- .lookup = { \
- .dev_id = "clk_out_" #_id, \
- .con_id = "extern" #_id, \
- }, \
- .ops = &tegra_clk_out_ops, \
- .reg = 0x1a8, \
- .inputs = mux_clkm_clkm2_clkm4_extern##_id, \
- .flags = MUX_CLK_OUT, \
- .max_rate = 216000000, \
- .u.periph = { \
- .clk_num = (_id - 1) * 8 + 2, \
- }, \
- }
-static struct clk tegra_clk_out_list[] = {
- CLK_OUT_CLK(1),
- CLK_OUT_CLK(2),
- CLK_OUT_CLK(3),
-};
-
-/* called after peripheral external clocks are initialized */
-static void init_clk_out_mux(void)
-{
- int i;
- struct clk *c;
-
- /* output clock con_id is the name of peripheral
- external clock connected to input 3 of the output mux */
- for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++) {
- c = tegra_get_clock_by_name(
- tegra_clk_out_list[i].lookup.con_id);
- if (!c)
- pr_err("%s: could not find clk %s\n", __func__,
- tegra_clk_out_list[i].lookup.con_id);
- mux_extern_out_list[i][3].input = c;
- }
-}
-
-/* Peripheral muxes */
-static struct clk_mux_sel mux_sclk[] = {
- { .input = &tegra_clk_m, .value = 0},
- { .input = &tegra_pll_c_out1, .value = 1},
- { .input = &tegra_pll_p_out4, .value = 2},
- { .input = &tegra_pll_p_out3, .value = 3},
- { .input = &tegra_pll_p_out2, .value = 4},
- /* { .input = &tegra_clk_d, .value = 5}, - no use on tegra30 */
- { .input = &tegra_clk_32k, .value = 6},
- { .input = &tegra_pll_m_out1, .value = 7},
- { 0, 0},
+struct clk_ops tegra_cml_clk_ops = {
+ .is_enabled = tegra30_cml_clk_is_enabled,
+ .enable = tegra30_cml_clk_enable,
+ .disable = tegra30_cml_clk_disable,
+ .recalc_rate = tegra30_clk_fixed_recalc_rate,
};
-static struct clk tegra_clk_sclk = {
- .name = "sclk",
- .inputs = mux_sclk,
- .reg = 0x28,
- .ops = &tegra_super_ops,
- .max_rate = 334000000,
- .min_rate = 40000000,
+struct clk_ops tegra_pciex_clk_ops = {
+ .recalc_rate = tegra30_clk_fixed_recalc_rate,
};
-
-static struct clk tegra_clk_blink = {
- .name = "blink",
- .parent = &tegra_clk_32k,
- .reg = 0x40,
- .ops = &tegra_blink_clk_ops,
- .max_rate = 32768,
-};
-
-static struct clk_mux_sel mux_pllm_pllc_pllp_plla[] = {
- { .input = &tegra_pll_m, .value = 0},
- { .input = &tegra_pll_c, .value = 1},
- { .input = &tegra_pll_p, .value = 2},
- { .input = &tegra_pll_a_out0, .value = 3},
- { 0, 0},
-};
-
-static struct clk_mux_sel mux_pllp_pllc_pllm_clkm[] = {
- { .input = &tegra_pll_p, .value = 0},
- { .input = &tegra_pll_c, .value = 1},
- { .input = &tegra_pll_m, .value = 2},
- { .input = &tegra_clk_m, .value = 3},
- { 0, 0},
-};
-
-static struct clk_mux_sel mux_pllp_clkm[] = {
- { .input = &tegra_pll_p, .value = 0},
- { .input = &tegra_clk_m, .value = 3},
- { 0, 0},
-};
-
-static struct clk_mux_sel mux_pllp_plld_pllc_clkm[] = {
- {.input = &tegra_pll_p, .value = 0},
- {.input = &tegra_pll_d_out0, .value = 1},
- {.input = &tegra_pll_c, .value = 2},
- {.input = &tegra_clk_m, .value = 3},
- { 0, 0},
-};
-
-static struct clk_mux_sel mux_pllp_pllm_plld_plla_pllc_plld2_clkm[] = {
- {.input = &tegra_pll_p, .value = 0},
- {.input = &tegra_pll_m, .value = 1},
- {.input = &tegra_pll_d_out0, .value = 2},
- {.input = &tegra_pll_a_out0, .value = 3},
- {.input = &tegra_pll_c, .value = 4},
- {.input = &tegra_pll_d2_out0, .value = 5},
- {.input = &tegra_clk_m, .value = 6},
- { 0, 0},
-};
-
-static struct clk_mux_sel mux_plla_pllc_pllp_clkm[] = {
- { .input = &tegra_pll_a_out0, .value = 0},
- /* { .input = &tegra_pll_c, .value = 1}, no use on tegra30 */
- { .input = &tegra_pll_p, .value = 2},
- { .input = &tegra_clk_m, .value = 3},
- { 0, 0},
-};
-
-static struct clk_mux_sel mux_pllp_pllc_clk32_clkm[] = {
- {.input = &tegra_pll_p, .value = 0},
- {.input = &tegra_pll_c, .value = 1},
- {.input = &tegra_clk_32k, .value = 2},
- {.input = &tegra_clk_m, .value = 3},
- { 0, 0},
-};
-
-static struct clk_mux_sel mux_pllp_pllc_clkm_clk32[] = {
- {.input = &tegra_pll_p, .value = 0},
- {.input = &tegra_pll_c, .value = 1},
- {.input = &tegra_clk_m, .value = 2},
- {.input = &tegra_clk_32k, .value = 3},
- { 0, 0},
-};
-
-static struct clk_mux_sel mux_pllp_pllc_pllm[] = {
- {.input = &tegra_pll_p, .value = 0},
- {.input = &tegra_pll_c, .value = 1},
- {.input = &tegra_pll_m, .value = 2},
- { 0, 0},
-};
-
-static struct clk_mux_sel mux_clk_m[] = {
- { .input = &tegra_clk_m, .value = 0},
- { 0, 0},
-};
-
-static struct clk_mux_sel mux_pllp_out3[] = {
- { .input = &tegra_pll_p_out3, .value = 0},
- { 0, 0},
-};
-
-static struct clk_mux_sel mux_plld_out0[] = {
- { .input = &tegra_pll_d_out0, .value = 0},
- { 0, 0},
-};
-
-static struct clk_mux_sel mux_plld_out0_plld2_out0[] = {
- { .input = &tegra_pll_d_out0, .value = 0},
- { .input = &tegra_pll_d2_out0, .value = 1},
- { 0, 0},
-};
-
-static struct clk_mux_sel mux_clk_32k[] = {
- { .input = &tegra_clk_32k, .value = 0},
- { 0, 0},
-};
-
-static struct clk_mux_sel mux_plla_clk32_pllp_clkm_plle[] = {
- { .input = &tegra_pll_a_out0, .value = 0},
- { .input = &tegra_clk_32k, .value = 1},
- { .input = &tegra_pll_p, .value = 2},
- { .input = &tegra_clk_m, .value = 3},
- { .input = &tegra_pll_e, .value = 4},
- { 0, 0},
-};
-
-static struct clk_mux_sel mux_cclk_g[] = {
- { .input = &tegra_clk_m, .value = 0},
- { .input = &tegra_pll_c, .value = 1},
- { .input = &tegra_clk_32k, .value = 2},
- { .input = &tegra_pll_m, .value = 3},
- { .input = &tegra_pll_p, .value = 4},
- { .input = &tegra_pll_p_out4, .value = 5},
- { .input = &tegra_pll_p_out3, .value = 6},
- { .input = &tegra_pll_x, .value = 8},
- { 0, 0},
-};
-
-static struct clk tegra_clk_cclk_g = {
- .name = "cclk_g",
- .flags = DIV_U71 | DIV_U71_INT,
- .inputs = mux_cclk_g,
- .reg = 0x368,
- .ops = &tegra_super_ops,
- .max_rate = 1700000000,
-};
-
-static struct clk tegra30_clk_twd = {
- .parent = &tegra_clk_cclk_g,
- .name = "twd",
- .ops = &tegra30_twd_ops,
- .max_rate = 1400000000, /* Same as tegra_clk_cpu_cmplx.max_rate */
- .mul = 1,
- .div = 2,
-};
-
-#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, _max, _inputs, _flags) \
- { \
- .name = _name, \
- .lookup = { \
- .dev_id = _dev, \
- .con_id = _con, \
- }, \
- .ops = &tegra_periph_clk_ops, \
- .reg = _reg, \
- .inputs = _inputs, \
- .flags = _flags, \
- .max_rate = _max, \
- .u.periph = { \
- .clk_num = _clk_num, \
- }, \
- }
-
-#define PERIPH_CLK_EX(_name, _dev, _con, _clk_num, _reg, _max, _inputs, \
- _flags, _ops) \
- { \
- .name = _name, \
- .lookup = { \
- .dev_id = _dev, \
- .con_id = _con, \
- }, \
- .ops = _ops, \
- .reg = _reg, \
- .inputs = _inputs, \
- .flags = _flags, \
- .max_rate = _max, \
- .u.periph = { \
- .clk_num = _clk_num, \
- }, \
- }
-
-#define SHARED_CLK(_name, _dev, _con, _parent, _id, _div, _mode)\
- { \
- .name = _name, \
- .lookup = { \
- .dev_id = _dev, \
- .con_id = _con, \
- }, \
- .ops = &tegra_clk_shared_bus_ops, \
- .parent = _parent, \
- .u.shared_bus_user = { \
- .client_id = _id, \
- .client_div = _div, \
- .mode = _mode, \
- }, \
- }
-struct clk tegra_list_clks[] = {
- PERIPH_CLK("apbdma", "tegra-apbdma", NULL, 34, 0, 26000000, mux_clk_m, 0),
- PERIPH_CLK("rtc", "rtc-tegra", NULL, 4, 0, 32768, mux_clk_32k, PERIPH_NO_RESET | PERIPH_ON_APB),
- PERIPH_CLK("kbc", "tegra-kbc", NULL, 36, 0, 32768, mux_clk_32k, PERIPH_NO_RESET | PERIPH_ON_APB),
- PERIPH_CLK("timer", "timer", NULL, 5, 0, 26000000, mux_clk_m, 0),
- PERIPH_CLK("kfuse", "kfuse-tegra", NULL, 40, 0, 26000000, mux_clk_m, 0),
- PERIPH_CLK("fuse", "fuse-tegra", "fuse", 39, 0, 26000000, mux_clk_m, PERIPH_ON_APB),
- PERIPH_CLK("fuse_burn", "fuse-tegra", "fuse_burn", 39, 0, 26000000, mux_clk_m, PERIPH_ON_APB),
- PERIPH_CLK("apbif", "tegra30-ahub", "apbif", 107, 0, 26000000, mux_clk_m, 0),
- PERIPH_CLK("i2s0", "tegra30-i2s.0", NULL, 30, 0x1d8, 26000000, mux_pllaout0_audio0_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
- PERIPH_CLK("i2s1", "tegra30-i2s.1", NULL, 11, 0x100, 26000000, mux_pllaout0_audio1_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
- PERIPH_CLK("i2s2", "tegra30-i2s.2", NULL, 18, 0x104, 26000000, mux_pllaout0_audio2_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
- PERIPH_CLK("i2s3", "tegra30-i2s.3", NULL, 101, 0x3bc, 26000000, mux_pllaout0_audio3_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
- PERIPH_CLK("i2s4", "tegra30-i2s.4", NULL, 102, 0x3c0, 26000000, mux_pllaout0_audio4_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
- PERIPH_CLK("spdif_out", "tegra30-spdif", "spdif_out", 10, 0x108, 100000000, mux_pllaout0_audio_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
- PERIPH_CLK("spdif_in", "tegra30-spdif", "spdif_in", 10, 0x10c, 100000000, mux_pllp_pllc_pllm, MUX | DIV_U71 | PERIPH_ON_APB),
- PERIPH_CLK("pwm", "tegra-pwm", NULL, 17, 0x110, 432000000, mux_pllp_pllc_clk32_clkm, MUX | MUX_PWM | DIV_U71 | PERIPH_ON_APB),
- PERIPH_CLK("d_audio", "tegra30-ahub", "d_audio", 106, 0x3d0, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71),
- PERIPH_CLK("dam0", "tegra30-dam.0", NULL, 108, 0x3d8, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71),
- PERIPH_CLK("dam1", "tegra30-dam.1", NULL, 109, 0x3dc, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71),
- PERIPH_CLK("dam2", "tegra30-dam.2", NULL, 110, 0x3e0, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71),
- PERIPH_CLK("hda", "tegra30-hda", "hda", 125, 0x428, 108000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("hda2codec_2x", "tegra30-hda", "hda2codec", 111, 0x3e4, 48000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("hda2hdmi", "tegra30-hda", "hda2hdmi", 128, 0, 48000000, mux_clk_m, 0),
- PERIPH_CLK("sbc1", "spi_tegra.0", NULL, 41, 0x134, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
- PERIPH_CLK("sbc2", "spi_tegra.1", NULL, 44, 0x118, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
- PERIPH_CLK("sbc3", "spi_tegra.2", NULL, 46, 0x11c, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
- PERIPH_CLK("sbc4", "spi_tegra.3", NULL, 68, 0x1b4, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
- PERIPH_CLK("sbc5", "spi_tegra.4", NULL, 104, 0x3c8, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
- PERIPH_CLK("sbc6", "spi_tegra.5", NULL, 105, 0x3cc, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
- PERIPH_CLK("sata_oob", "tegra_sata_oob", NULL, 123, 0x420, 216000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("sata", "tegra_sata", NULL, 124, 0x424, 216000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("sata_cold", "tegra_sata_cold", NULL, 129, 0, 48000000, mux_clk_m, 0),
- PERIPH_CLK_EX("ndflash", "tegra_nand", NULL, 13, 0x160, 240000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71, &tegra_nand_clk_ops),
- PERIPH_CLK("ndspeed", "tegra_nand_speed", NULL, 80, 0x3f8, 240000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("vfir", "vfir", NULL, 7, 0x168, 72000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
- PERIPH_CLK("sdmmc1", "sdhci-tegra.0", NULL, 14, 0x150, 208000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
- PERIPH_CLK("sdmmc2", "sdhci-tegra.1", NULL, 9, 0x154, 104000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
- PERIPH_CLK("sdmmc3", "sdhci-tegra.2", NULL, 69, 0x1bc, 208000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
- PERIPH_CLK("sdmmc4", "sdhci-tegra.3", NULL, 15, 0x164, 104000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
- PERIPH_CLK("vcp", "tegra-avp", "vcp", 29, 0, 250000000, mux_clk_m, 0),
- PERIPH_CLK("bsea", "tegra-avp", "bsea", 62, 0, 250000000, mux_clk_m, 0),
- PERIPH_CLK("bsev", "tegra-aes", "bsev", 63, 0, 250000000, mux_clk_m, 0),
- PERIPH_CLK("vde", "vde", NULL, 61, 0x1c8, 520000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_INT),
- PERIPH_CLK("csite", "csite", NULL, 73, 0x1d4, 144000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* max rate ??? */
- PERIPH_CLK("la", "la", NULL, 76, 0x1f8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- 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("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),
- PERIPH_CLK("uartd", "tegra-uart.3", NULL, 65, 0x1c0, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
- PERIPH_CLK("uarte", "tegra-uart.4", NULL, 66, 0x1c4, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
- PERIPH_CLK_EX("vi", "tegra_camera", "vi", 20, 0x148, 425000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT, &tegra_vi_clk_ops),
- PERIPH_CLK("3d", "3d", NULL, 24, 0x158, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET),
- PERIPH_CLK("3d2", "3d2", NULL, 98, 0x3b0, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET),
- PERIPH_CLK("2d", "2d", NULL, 21, 0x15c, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE),
- PERIPH_CLK("vi_sensor", "tegra_camera", "vi_sensor", 20, 0x1a8, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_NO_RESET),
- PERIPH_CLK("epp", "epp", NULL, 19, 0x16c, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT),
- PERIPH_CLK("mpe", "mpe", NULL, 60, 0x170, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT),
- PERIPH_CLK("host1x", "host1x", NULL, 28, 0x180, 260000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT),
- PERIPH_CLK("cve", "cve", NULL, 49, 0x140, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
- PERIPH_CLK("tvo", "tvo", NULL, 49, 0x188, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
- PERIPH_CLK_EX("dtv", "dtv", NULL, 79, 0x1dc, 250000000, mux_clk_m, 0, &tegra_dtv_clk_ops),
- PERIPH_CLK("hdmi", "hdmi", NULL, 51, 0x18c, 148500000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8 | DIV_U71),
- PERIPH_CLK("tvdac", "tvdac", NULL, 53, 0x194, 220000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
- PERIPH_CLK("disp1", "tegradc.0", NULL, 27, 0x138, 600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8),
- PERIPH_CLK("disp2", "tegradc.1", NULL, 26, 0x13c, 600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8),
- PERIPH_CLK("usbd", "fsl-tegra-udc", NULL, 22, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
- PERIPH_CLK("usb2", "tegra-ehci.1", NULL, 58, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
- PERIPH_CLK("usb3", "tegra-ehci.2", NULL, 59, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
- PERIPH_CLK("dsia", "tegradc.0", "dsia", 48, 0, 500000000, mux_plld_out0, 0),
- PERIPH_CLK_EX("dsib", "tegradc.1", "dsib", 82, 0xd0, 500000000, mux_plld_out0_plld2_out0, MUX | PLLD, &tegra_dsib_clk_ops),
- PERIPH_CLK("csi", "tegra_camera", "csi", 52, 0, 102000000, mux_pllp_out3, 0),
- PERIPH_CLK("isp", "tegra_camera", "isp", 23, 0, 150000000, mux_clk_m, 0), /* same frequency as VI */
- PERIPH_CLK("csus", "tegra_camera", "csus", 92, 0, 150000000, mux_clk_m, PERIPH_NO_RESET),
-
- PERIPH_CLK("tsensor", "tegra-tsensor", NULL, 100, 0x3b8, 216000000, mux_pllp_pllc_clkm_clk32, MUX | DIV_U71),
- PERIPH_CLK("actmon", "actmon", NULL, 119, 0x3e8, 216000000, mux_pllp_pllc_clk32_clkm, MUX | DIV_U71),
- PERIPH_CLK("extern1", "extern1", NULL, 120, 0x3ec, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71),
- PERIPH_CLK("extern2", "extern2", NULL, 121, 0x3f0, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71),
- PERIPH_CLK("extern3", "extern3", NULL, 122, 0x3f4, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71),
- PERIPH_CLK("i2cslow", "i2cslow", NULL, 81, 0x3fc, 26000000, mux_pllp_pllc_clk32_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
- PERIPH_CLK("pcie", "tegra-pcie", "pcie", 70, 0, 250000000, mux_clk_m, 0),
- PERIPH_CLK("afi", "tegra-pcie", "afi", 72, 0, 250000000, mux_clk_m, 0),
- PERIPH_CLK("se", "se", NULL, 127, 0x42c, 520000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_INT),
-};
-
-#define CLK_DUPLICATE(_name, _dev, _con) \
- { \
- .name = _name, \
- .lookup = { \
- .dev_id = _dev, \
- .con_id = _con, \
- }, \
- }
-
-/* Some clocks may be used by different drivers depending on the board
- * configuration. List those here to register them twice in the clock lookup
- * table under two names.
- */
-struct clk_duplicate tegra_clk_duplicates[] = {
- CLK_DUPLICATE("uarta", "serial8250.0", NULL),
- CLK_DUPLICATE("uartb", "serial8250.1", NULL),
- CLK_DUPLICATE("uartc", "serial8250.2", NULL),
- CLK_DUPLICATE("uartd", "serial8250.3", NULL),
- CLK_DUPLICATE("uarte", "serial8250.4", NULL),
- CLK_DUPLICATE("usbd", "utmip-pad", NULL),
- CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),
- CLK_DUPLICATE("usbd", "tegra-otg", NULL),
- CLK_DUPLICATE("hdmi", "tegradc.0", "hdmi"),
- CLK_DUPLICATE("hdmi", "tegradc.1", "hdmi"),
- CLK_DUPLICATE("dsib", "tegradc.0", "dsib"),
- CLK_DUPLICATE("dsia", "tegradc.1", "dsia"),
- CLK_DUPLICATE("bsev", "tegra-avp", "bsev"),
- CLK_DUPLICATE("bsev", "nvavp", "bsev"),
- CLK_DUPLICATE("vde", "tegra-aes", "vde"),
- CLK_DUPLICATE("bsea", "tegra-aes", "bsea"),
- CLK_DUPLICATE("bsea", "nvavp", "bsea"),
- CLK_DUPLICATE("cml1", "tegra_sata_cml", NULL),
- CLK_DUPLICATE("cml0", "tegra_pcie", "cml"),
- CLK_DUPLICATE("pciex", "tegra_pcie", "pciex"),
- CLK_DUPLICATE("i2c1", "tegra-i2c-slave.0", NULL),
- CLK_DUPLICATE("i2c2", "tegra-i2c-slave.1", NULL),
- CLK_DUPLICATE("i2c3", "tegra-i2c-slave.2", NULL),
- CLK_DUPLICATE("i2c4", "tegra-i2c-slave.3", NULL),
- CLK_DUPLICATE("i2c5", "tegra-i2c-slave.4", NULL),
- CLK_DUPLICATE("sbc1", "spi_slave_tegra.0", NULL),
- CLK_DUPLICATE("sbc2", "spi_slave_tegra.1", NULL),
- CLK_DUPLICATE("sbc3", "spi_slave_tegra.2", NULL),
- CLK_DUPLICATE("sbc4", "spi_slave_tegra.3", NULL),
- CLK_DUPLICATE("sbc5", "spi_slave_tegra.4", NULL),
- CLK_DUPLICATE("sbc6", "spi_slave_tegra.5", NULL),
- CLK_DUPLICATE("twd", "smp_twd", NULL),
- CLK_DUPLICATE("vcp", "nvavp", "vcp"),
- CLK_DUPLICATE("i2s0", NULL, "i2s0"),
- CLK_DUPLICATE("i2s1", NULL, "i2s1"),
- CLK_DUPLICATE("i2s2", NULL, "i2s2"),
- CLK_DUPLICATE("i2s3", NULL, "i2s3"),
- CLK_DUPLICATE("i2s4", NULL, "i2s4"),
- CLK_DUPLICATE("dam0", NULL, "dam0"),
- CLK_DUPLICATE("dam1", NULL, "dam1"),
- CLK_DUPLICATE("dam2", NULL, "dam2"),
- CLK_DUPLICATE("spdif_in", NULL, "spdif_in"),
-};
-
-struct clk *tegra_ptr_clks[] = {
- &tegra_clk_32k,
- &tegra_clk_m,
- &tegra_clk_m_div2,
- &tegra_clk_m_div4,
- &tegra_pll_ref,
- &tegra_pll_m,
- &tegra_pll_m_out1,
- &tegra_pll_c,
- &tegra_pll_c_out1,
- &tegra_pll_p,
- &tegra_pll_p_out1,
- &tegra_pll_p_out2,
- &tegra_pll_p_out3,
- &tegra_pll_p_out4,
- &tegra_pll_a,
- &tegra_pll_a_out0,
- &tegra_pll_d,
- &tegra_pll_d_out0,
- &tegra_pll_d2,
- &tegra_pll_d2_out0,
- &tegra_pll_u,
- &tegra_pll_x,
- &tegra_pll_x_out0,
- &tegra_pll_e,
- &tegra_clk_cclk_g,
- &tegra_cml0_clk,
- &tegra_cml1_clk,
- &tegra_pciex_clk,
- &tegra_clk_sclk,
- &tegra_clk_blink,
- &tegra30_clk_twd,
-};
-
-
-static void tegra30_init_one_clock(struct clk *c)
-{
- clk_init(c);
- INIT_LIST_HEAD(&c->shared_bus_list);
- if (!c->lookup.dev_id && !c->lookup.con_id)
- c->lookup.con_id = c->name;
- c->lookup.clk = c;
- clkdev_add(&c->lookup);
-}
-
-void __init tegra30_init_clocks(void)
-{
- int i;
- struct clk *c;
-
- for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++)
- tegra30_init_one_clock(tegra_ptr_clks[i]);
-
- for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++)
- tegra30_init_one_clock(&tegra_list_clks[i]);
-
- for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) {
- c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name);
- if (!c) {
- pr_err("%s: Unknown duplicate clock %s\n", __func__,
- tegra_clk_duplicates[i].name);
- continue;
- }
-
- tegra_clk_duplicates[i].lookup.clk = c;
- clkdev_add(&tegra_clk_duplicates[i].lookup);
- }
-
- for (i = 0; i < ARRAY_SIZE(tegra_sync_source_list); i++)
- tegra30_init_one_clock(&tegra_sync_source_list[i]);
- for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_list); i++)
- tegra30_init_one_clock(&tegra_clk_audio_list[i]);
- for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_2x_list); i++)
- tegra30_init_one_clock(&tegra_clk_audio_2x_list[i]);
-
- init_clk_out_mux();
- for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++)
- tegra30_init_one_clock(&tegra_clk_out_list[i]);
-
-}
diff --git a/arch/arm/mach-tegra/tegra30_clocks.h b/arch/arm/mach-tegra/tegra30_clocks.h
new file mode 100644
index 000000000000..f2f88fef6b8b
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra30_clocks.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MACH_TEGRA30_CLOCK_H
+#define __MACH_TEGRA30_CLOCK_H
+
+extern struct clk_ops tegra30_clk_32k_ops;
+extern struct clk_ops tegra30_clk_m_ops;
+extern struct clk_ops tegra_clk_m_div_ops;
+extern struct clk_ops tegra_pll_ref_ops;
+extern struct clk_ops tegra30_pll_ops;
+extern struct clk_ops tegra30_pll_div_ops;
+extern struct clk_ops tegra_plld_ops;
+extern struct clk_ops tegra30_plle_ops;
+extern struct clk_ops tegra_cml_clk_ops;
+extern struct clk_ops tegra_pciex_clk_ops;
+extern struct clk_ops tegra_sync_source_ops;
+extern struct clk_ops tegra30_audio_sync_clk_ops;
+extern struct clk_ops tegra30_clk_double_ops;
+extern struct clk_ops tegra_clk_out_ops;
+extern struct clk_ops tegra30_super_ops;
+extern struct clk_ops tegra30_blink_clk_ops;
+extern struct clk_ops tegra30_twd_ops;
+extern struct clk_ops tegra30_periph_clk_ops;
+extern struct clk_ops tegra30_dsib_clk_ops;
+extern struct clk_ops tegra_nand_clk_ops;
+extern struct clk_ops tegra_vi_clk_ops;
+extern struct clk_ops tegra_dtv_clk_ops;
+extern struct clk_ops tegra_clk_shared_bus_ops;
+
+int tegra30_plld_clk_cfg_ex(struct clk_hw *hw,
+ enum tegra_clk_ex_param p, u32 setting);
+void tegra30_periph_clk_reset(struct clk_hw *hw, bool assert);
+int tegra30_vi_clk_cfg_ex(struct clk_hw *hw,
+ enum tegra_clk_ex_param p, u32 setting);
+int tegra30_nand_clk_cfg_ex(struct clk_hw *hw,
+ enum tegra_clk_ex_param p, u32 setting);
+int tegra30_dtv_clk_cfg_ex(struct clk_hw *hw,
+ enum tegra_clk_ex_param p, u32 setting);
+#endif
diff --git a/arch/arm/mach-tegra/tegra30_clocks_data.c b/arch/arm/mach-tegra/tegra30_clocks_data.c
new file mode 100644
index 000000000000..8d2dbdd59174
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra30_clocks_data.c
@@ -0,0 +1,1374 @@
+/*
+ * arch/arm/mach-tegra/tegra30_clocks.c
+ *
+ * Copyright (c) 2010-2012 NVIDIA CORPORATION. All rights reserved.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/clk-private.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+
+#include "clock.h"
+#include "fuse.h"
+#include "tegra30_clocks.h"
+
+#define DEFINE_CLK_TEGRA(_name, _rate, _ops, _flags, \
+ _parent_names, _parents, _parent) \
+ static struct clk tegra_##_name = { \
+ .hw = &tegra_##_name##_hw.hw, \
+ .name = #_name, \
+ .rate = _rate, \
+ .ops = _ops, \
+ .flags = _flags, \
+ .parent_names = _parent_names, \
+ .parents = _parents, \
+ .num_parents = ARRAY_SIZE(_parent_names), \
+ .parent = _parent, \
+ };
+
+static struct clk tegra_clk_32k;
+static struct clk_tegra tegra_clk_32k_hw = {
+ .hw = {
+ .clk = &tegra_clk_32k,
+ },
+ .fixed_rate = 32768,
+};
+static struct clk tegra_clk_32k = {
+ .name = "clk_32k",
+ .hw = &tegra_clk_32k_hw.hw,
+ .ops = &tegra30_clk_32k_ops,
+ .flags = CLK_IS_ROOT,
+};
+
+static struct clk tegra_clk_m;
+static struct clk_tegra tegra_clk_m_hw = {
+ .hw = {
+ .clk = &tegra_clk_m,
+ },
+ .flags = ENABLE_ON_INIT,
+ .reg = 0x1fc,
+ .reg_shift = 28,
+ .max_rate = 48000000,
+};
+static struct clk tegra_clk_m = {
+ .name = "clk_m",
+ .hw = &tegra_clk_m_hw.hw,
+ .ops = &tegra30_clk_m_ops,
+ .flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED,
+};
+
+static const char *clk_m_div_parent_names[] = {
+ "clk_m",
+};
+
+static struct clk *clk_m_div_parents[] = {
+ &tegra_clk_m,
+};
+
+static struct clk tegra_clk_m_div2;
+static struct clk_tegra tegra_clk_m_div2_hw = {
+ .hw = {
+ .clk = &tegra_clk_m_div2,
+ },
+ .mul = 1,
+ .div = 2,
+ .max_rate = 24000000,
+};
+DEFINE_CLK_TEGRA(clk_m_div2, 0, &tegra_clk_m_div_ops, 0,
+ clk_m_div_parent_names, clk_m_div_parents, &tegra_clk_m);
+
+static struct clk tegra_clk_m_div4;
+static struct clk_tegra tegra_clk_m_div4_hw = {
+ .hw = {
+ .clk = &tegra_clk_m_div4,
+ },
+ .mul = 1,
+ .div = 4,
+ .max_rate = 12000000,
+};
+DEFINE_CLK_TEGRA(clk_m_div4, 0, &tegra_clk_m_div_ops, 0,
+ clk_m_div_parent_names, clk_m_div_parents, &tegra_clk_m);
+
+static struct clk tegra_pll_ref;
+static struct clk_tegra tegra_pll_ref_hw = {
+ .hw = {
+ .clk = &tegra_pll_ref,
+ },
+ .flags = ENABLE_ON_INIT,
+ .max_rate = 26000000,
+};
+DEFINE_CLK_TEGRA(pll_ref, 0, &tegra_pll_ref_ops, 0, clk_m_div_parent_names,
+ clk_m_div_parents, &tegra_clk_m);
+
+#define DEFINE_PLL(_name, _flags, _reg, _max_rate, _input_min, \
+ _input_max, _cf_min, _cf_max, _vco_min, \
+ _vco_max, _freq_table, _lock_delay, _ops, \
+ _fixed_rate, _clk_cfg_ex, _parent) \
+ static struct clk tegra_##_name; \
+ static const char *_name##_parent_names[] = { \
+ #_parent, \
+ }; \
+ static struct clk *_name##_parents[] = { \
+ &tegra_##_parent, \
+ }; \
+ static struct clk_tegra tegra_##_name##_hw = { \
+ .hw = { \
+ .clk = &tegra_##_name, \
+ }, \
+ .flags = _flags, \
+ .reg = _reg, \
+ .max_rate = _max_rate, \
+ .u.pll = { \
+ .input_min = _input_min, \
+ .input_max = _input_max, \
+ .cf_min = _cf_min, \
+ .cf_max = _cf_max, \
+ .vco_min = _vco_min, \
+ .vco_max = _vco_max, \
+ .freq_table = _freq_table, \
+ .lock_delay = _lock_delay, \
+ .fixed_rate = _fixed_rate, \
+ }, \
+ .clk_cfg_ex = _clk_cfg_ex, \
+ }; \
+ DEFINE_CLK_TEGRA(_name, 0, &_ops, CLK_IGNORE_UNUSED, \
+ _name##_parent_names, _name##_parents, \
+ &tegra_##_parent);
+
+#define DEFINE_PLL_OUT(_name, _flags, _reg, _reg_shift, \
+ _max_rate, _ops, _parent, _clk_flags) \
+ static const char *_name##_parent_names[] = { \
+ #_parent, \
+ }; \
+ static struct clk *_name##_parents[] = { \
+ &tegra_##_parent, \
+ }; \
+ static struct clk tegra_##_name; \
+ static struct clk_tegra tegra_##_name##_hw = { \
+ .hw = { \
+ .clk = &tegra_##_name, \
+ }, \
+ .flags = _flags, \
+ .reg = _reg, \
+ .max_rate = _max_rate, \
+ .reg_shift = _reg_shift, \
+ }; \
+ DEFINE_CLK_TEGRA(_name, 0, &tegra30_pll_div_ops, \
+ _clk_flags, _name##_parent_names, \
+ _name##_parents, &tegra_##_parent);
+
+static struct clk_pll_freq_table tegra_pll_c_freq_table[] = {
+ { 12000000, 1040000000, 520, 6, 1, 8},
+ { 13000000, 1040000000, 480, 6, 1, 8},
+ { 16800000, 1040000000, 495, 8, 1, 8}, /* actual: 1039.5 MHz */
+ { 19200000, 1040000000, 325, 6, 1, 6},
+ { 26000000, 1040000000, 520, 13, 1, 8},
+
+ { 12000000, 832000000, 416, 6, 1, 8},
+ { 13000000, 832000000, 832, 13, 1, 8},
+ { 16800000, 832000000, 396, 8, 1, 8}, /* actual: 831.6 MHz */
+ { 19200000, 832000000, 260, 6, 1, 8},
+ { 26000000, 832000000, 416, 13, 1, 8},
+
+ { 12000000, 624000000, 624, 12, 1, 8},
+ { 13000000, 624000000, 624, 13, 1, 8},
+ { 16800000, 600000000, 520, 14, 1, 8},
+ { 19200000, 624000000, 520, 16, 1, 8},
+ { 26000000, 624000000, 624, 26, 1, 8},
+
+ { 12000000, 600000000, 600, 12, 1, 8},
+ { 13000000, 600000000, 600, 13, 1, 8},
+ { 16800000, 600000000, 500, 14, 1, 8},
+ { 19200000, 600000000, 375, 12, 1, 6},
+ { 26000000, 600000000, 600, 26, 1, 8},
+
+ { 12000000, 520000000, 520, 12, 1, 8},
+ { 13000000, 520000000, 520, 13, 1, 8},
+ { 16800000, 520000000, 495, 16, 1, 8}, /* actual: 519.75 MHz */
+ { 19200000, 520000000, 325, 12, 1, 6},
+ { 26000000, 520000000, 520, 26, 1, 8},
+
+ { 12000000, 416000000, 416, 12, 1, 8},
+ { 13000000, 416000000, 416, 13, 1, 8},
+ { 16800000, 416000000, 396, 16, 1, 8}, /* actual: 415.8 MHz */
+ { 19200000, 416000000, 260, 12, 1, 6},
+ { 26000000, 416000000, 416, 26, 1, 8},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_c, PLL_HAS_CPCON, 0x80, 1400000000, 2000000, 31000000, 1000000,
+ 6000000, 20000000, 1400000000, tegra_pll_c_freq_table, 300,
+ tegra30_pll_ops, 0, NULL, pll_ref);
+
+DEFINE_PLL_OUT(pll_c_out1, DIV_U71, 0x84, 0, 700000000,
+ tegra30_pll_div_ops, pll_c, CLK_IGNORE_UNUSED);
+
+static struct clk_pll_freq_table tegra_pll_m_freq_table[] = {
+ { 12000000, 666000000, 666, 12, 1, 8},
+ { 13000000, 666000000, 666, 13, 1, 8},
+ { 16800000, 666000000, 555, 14, 1, 8},
+ { 19200000, 666000000, 555, 16, 1, 8},
+ { 26000000, 666000000, 666, 26, 1, 8},
+ { 12000000, 600000000, 600, 12, 1, 8},
+ { 13000000, 600000000, 600, 13, 1, 8},
+ { 16800000, 600000000, 500, 14, 1, 8},
+ { 19200000, 600000000, 375, 12, 1, 6},
+ { 26000000, 600000000, 600, 26, 1, 8},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_m, PLL_HAS_CPCON | PLLM, 0x90, 800000000, 2000000, 31000000,
+ 1000000, 6000000, 20000000, 1200000000, tegra_pll_m_freq_table,
+ 300, tegra30_pll_ops, 0, NULL, pll_ref);
+
+DEFINE_PLL_OUT(pll_m_out1, DIV_U71, 0x94, 0, 600000000,
+ tegra30_pll_div_ops, pll_m, CLK_IGNORE_UNUSED);
+
+static struct clk_pll_freq_table tegra_pll_p_freq_table[] = {
+ { 12000000, 216000000, 432, 12, 2, 8},
+ { 13000000, 216000000, 432, 13, 2, 8},
+ { 16800000, 216000000, 360, 14, 2, 8},
+ { 19200000, 216000000, 360, 16, 2, 8},
+ { 26000000, 216000000, 432, 26, 2, 8},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_p, ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON, 0xa0, 432000000,
+ 2000000, 31000000, 1000000, 6000000, 20000000, 1400000000,
+ tegra_pll_p_freq_table, 300, tegra30_pll_ops, 408000000, NULL,
+ pll_ref);
+
+DEFINE_PLL_OUT(pll_p_out1, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4,
+ 0, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED);
+DEFINE_PLL_OUT(pll_p_out2, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa4,
+ 16, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED);
+DEFINE_PLL_OUT(pll_p_out3, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8,
+ 0, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED);
+DEFINE_PLL_OUT(pll_p_out4, ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED, 0xa8,
+ 16, 432000000, tegra30_pll_div_ops, pll_p, CLK_IGNORE_UNUSED);
+
+static struct clk_pll_freq_table tegra_pll_a_freq_table[] = {
+ { 9600000, 564480000, 294, 5, 1, 4},
+ { 9600000, 552960000, 288, 5, 1, 4},
+ { 9600000, 24000000, 5, 2, 1, 1},
+
+ { 28800000, 56448000, 49, 25, 1, 1},
+ { 28800000, 73728000, 64, 25, 1, 1},
+ { 28800000, 24000000, 5, 6, 1, 1},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_a, PLL_HAS_CPCON, 0xb0, 700000000, 2000000, 31000000, 1000000,
+ 6000000, 20000000, 1400000000, tegra_pll_a_freq_table,
+ 300, tegra30_pll_ops, 0, NULL, pll_p_out1);
+
+DEFINE_PLL_OUT(pll_a_out0, DIV_U71, 0xb4, 0, 100000000, tegra30_pll_div_ops,
+ pll_a, CLK_IGNORE_UNUSED);
+
+static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
+ { 12000000, 216000000, 216, 12, 1, 4},
+ { 13000000, 216000000, 216, 13, 1, 4},
+ { 16800000, 216000000, 180, 14, 1, 4},
+ { 19200000, 216000000, 180, 16, 1, 4},
+ { 26000000, 216000000, 216, 26, 1, 4},
+
+ { 12000000, 594000000, 594, 12, 1, 8},
+ { 13000000, 594000000, 594, 13, 1, 8},
+ { 16800000, 594000000, 495, 14, 1, 8},
+ { 19200000, 594000000, 495, 16, 1, 8},
+ { 26000000, 594000000, 594, 26, 1, 8},
+
+ { 12000000, 1000000000, 1000, 12, 1, 12},
+ { 13000000, 1000000000, 1000, 13, 1, 12},
+ { 19200000, 1000000000, 625, 12, 1, 8},
+ { 26000000, 1000000000, 1000, 26, 1, 12},
+
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_d, PLL_HAS_CPCON | PLLD, 0xd0, 1000000000, 2000000, 40000000,
+ 1000000, 6000000, 40000000, 1000000000, tegra_pll_d_freq_table,
+ 1000, tegra30_pll_ops, 0, tegra30_plld_clk_cfg_ex, pll_ref);
+
+DEFINE_PLL_OUT(pll_d_out0, DIV_2 | PLLD, 0, 0, 500000000, tegra30_pll_div_ops,
+ pll_d, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED);
+
+DEFINE_PLL(pll_d2, PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLD, 0x4b8, 1000000000,
+ 2000000, 40000000, 1000000, 6000000, 40000000, 1000000000,
+ tegra_pll_d_freq_table, 1000, tegra30_pll_ops, 0, NULL,
+ pll_ref);
+
+DEFINE_PLL_OUT(pll_d2_out0, DIV_2 | PLLD, 0, 0, 500000000, tegra30_pll_div_ops,
+ pll_d2, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED);
+
+static struct clk_pll_freq_table tegra_pll_u_freq_table[] = {
+ { 12000000, 480000000, 960, 12, 2, 12},
+ { 13000000, 480000000, 960, 13, 2, 12},
+ { 16800000, 480000000, 400, 7, 2, 5},
+ { 19200000, 480000000, 200, 4, 2, 3},
+ { 26000000, 480000000, 960, 26, 2, 12},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_u, PLL_HAS_CPCON | PLLU, 0xc0, 480000000, 2000000, 40000000,
+ 1000000, 6000000, 48000000, 960000000, tegra_pll_u_freq_table,
+ 1000, tegra30_pll_ops, 0, NULL, pll_ref);
+
+static struct clk_pll_freq_table tegra_pll_x_freq_table[] = {
+ /* 1.7 GHz */
+ { 12000000, 1700000000, 850, 6, 1, 8},
+ { 13000000, 1700000000, 915, 7, 1, 8}, /* actual: 1699.2 MHz */
+ { 16800000, 1700000000, 708, 7, 1, 8}, /* actual: 1699.2 MHz */
+ { 19200000, 1700000000, 885, 10, 1, 8}, /* actual: 1699.2 MHz */
+ { 26000000, 1700000000, 850, 13, 1, 8},
+
+ /* 1.6 GHz */
+ { 12000000, 1600000000, 800, 6, 1, 8},
+ { 13000000, 1600000000, 738, 6, 1, 8}, /* actual: 1599.0 MHz */
+ { 16800000, 1600000000, 857, 9, 1, 8}, /* actual: 1599.7 MHz */
+ { 19200000, 1600000000, 500, 6, 1, 8},
+ { 26000000, 1600000000, 800, 13, 1, 8},
+
+ /* 1.5 GHz */
+ { 12000000, 1500000000, 750, 6, 1, 8},
+ { 13000000, 1500000000, 923, 8, 1, 8}, /* actual: 1499.8 MHz */
+ { 16800000, 1500000000, 625, 7, 1, 8},
+ { 19200000, 1500000000, 625, 8, 1, 8},
+ { 26000000, 1500000000, 750, 13, 1, 8},
+
+ /* 1.4 GHz */
+ { 12000000, 1400000000, 700, 6, 1, 8},
+ { 13000000, 1400000000, 969, 9, 1, 8}, /* actual: 1399.7 MHz */
+ { 16800000, 1400000000, 1000, 12, 1, 8},
+ { 19200000, 1400000000, 875, 12, 1, 8},
+ { 26000000, 1400000000, 700, 13, 1, 8},
+
+ /* 1.3 GHz */
+ { 12000000, 1300000000, 975, 9, 1, 8},
+ { 13000000, 1300000000, 1000, 10, 1, 8},
+ { 16800000, 1300000000, 928, 12, 1, 8}, /* actual: 1299.2 MHz */
+ { 19200000, 1300000000, 812, 12, 1, 8}, /* actual: 1299.2 MHz */
+ { 26000000, 1300000000, 650, 13, 1, 8},
+
+ /* 1.2 GHz */
+ { 12000000, 1200000000, 1000, 10, 1, 8},
+ { 13000000, 1200000000, 923, 10, 1, 8}, /* actual: 1199.9 MHz */
+ { 16800000, 1200000000, 1000, 14, 1, 8},
+ { 19200000, 1200000000, 1000, 16, 1, 8},
+ { 26000000, 1200000000, 600, 13, 1, 8},
+
+ /* 1.1 GHz */
+ { 12000000, 1100000000, 825, 9, 1, 8},
+ { 13000000, 1100000000, 846, 10, 1, 8}, /* actual: 1099.8 MHz */
+ { 16800000, 1100000000, 982, 15, 1, 8}, /* actual: 1099.8 MHz */
+ { 19200000, 1100000000, 859, 15, 1, 8}, /* actual: 1099.5 MHz */
+ { 26000000, 1100000000, 550, 13, 1, 8},
+
+ /* 1 GHz */
+ { 12000000, 1000000000, 1000, 12, 1, 8},
+ { 13000000, 1000000000, 1000, 13, 1, 8},
+ { 16800000, 1000000000, 833, 14, 1, 8}, /* actual: 999.6 MHz */
+ { 19200000, 1000000000, 625, 12, 1, 8},
+ { 26000000, 1000000000, 1000, 26, 1, 8},
+
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_x, PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLX, 0xe0, 1700000000,
+ 2000000, 31000000, 1000000, 6000000, 20000000, 1700000000,
+ tegra_pll_x_freq_table, 300, tegra30_pll_ops, 0, NULL, pll_ref);
+
+DEFINE_PLL_OUT(pll_x_out0, DIV_2 | PLLX, 0, 0, 850000000, tegra30_pll_div_ops,
+ pll_x, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED);
+
+static struct clk_pll_freq_table tegra_pll_e_freq_table[] = {
+ /* PLLE special case: use cpcon field to store cml divider value */
+ { 12000000, 100000000, 150, 1, 18, 11},
+ { 216000000, 100000000, 200, 18, 24, 13},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+DEFINE_PLL(pll_e, PLL_ALT_MISC_REG, 0xe8, 100000000, 2000000, 216000000,
+ 12000000, 12000000, 1200000000, 2400000000U,
+ tegra_pll_e_freq_table, 300, tegra30_plle_ops, 100000000, NULL,
+ pll_ref);
+
+static const char *mux_plle[] = {
+ "pll_e",
+};
+
+static struct clk *mux_plle_p[] = {
+ &tegra_pll_e,
+};
+
+static struct clk tegra_cml0;
+static struct clk_tegra tegra_cml0_hw = {
+ .hw = {
+ .clk = &tegra_cml0,
+ },
+ .reg = 0x48c,
+ .fixed_rate = 100000000,
+ .u.periph = {
+ .clk_num = 0,
+ },
+};
+DEFINE_CLK_TEGRA(cml0, 0, &tegra_cml_clk_ops, 0, mux_plle,
+ mux_plle_p, &tegra_pll_e);
+
+static struct clk tegra_cml1;
+static struct clk_tegra tegra_cml1_hw = {
+ .hw = {
+ .clk = &tegra_cml1,
+ },
+ .reg = 0x48c,
+ .fixed_rate = 100000000,
+ .u.periph = {
+ .clk_num = 1,
+ },
+};
+DEFINE_CLK_TEGRA(cml1, 0, &tegra_cml_clk_ops, 0, mux_plle,
+ mux_plle_p, &tegra_pll_e);
+
+static struct clk tegra_pciex;
+static struct clk_tegra tegra_pciex_hw = {
+ .hw = {
+ .clk = &tegra_pciex,
+ },
+ .reg = 0x48c,
+ .fixed_rate = 100000000,
+ .reset = tegra30_periph_clk_reset,
+ .u.periph = {
+ .clk_num = 74,
+ },
+};
+DEFINE_CLK_TEGRA(pciex, 0, &tegra_pciex_clk_ops, 0, mux_plle,
+ mux_plle_p, &tegra_pll_e);
+
+#define SYNC_SOURCE(_name) \
+ static struct clk tegra_##_name##_sync; \
+ static struct clk_tegra tegra_##_name##_sync_hw = { \
+ .hw = { \
+ .clk = &tegra_##_name##_sync, \
+ }, \
+ .max_rate = 24000000, \
+ .fixed_rate = 24000000, \
+ }; \
+ static struct clk tegra_##_name##_sync = { \
+ .name = #_name "_sync", \
+ .hw = &tegra_##_name##_sync_hw.hw, \
+ .ops = &tegra_sync_source_ops, \
+ .flags = CLK_IS_ROOT, \
+ };
+
+SYNC_SOURCE(spdif_in);
+SYNC_SOURCE(i2s0);
+SYNC_SOURCE(i2s1);
+SYNC_SOURCE(i2s2);
+SYNC_SOURCE(i2s3);
+SYNC_SOURCE(i2s4);
+SYNC_SOURCE(vimclk);
+
+static struct clk *tegra_sync_source_list[] = {
+ &tegra_spdif_in_sync,
+ &tegra_i2s0_sync,
+ &tegra_i2s1_sync,
+ &tegra_i2s2_sync,
+ &tegra_i2s3_sync,
+ &tegra_i2s4_sync,
+ &tegra_vimclk_sync,
+};
+
+static const char *mux_audio_sync_clk[] = {
+ "spdif_in_sync",
+ "i2s0_sync",
+ "i2s1_sync",
+ "i2s2_sync",
+ "i2s3_sync",
+ "i2s4_sync",
+ "vimclk_sync",
+};
+
+#define AUDIO_SYNC_CLK(_name, _index) \
+ static struct clk tegra_##_name; \
+ static struct clk_tegra tegra_##_name##_hw = { \
+ .hw = { \
+ .clk = &tegra_##_name, \
+ }, \
+ .max_rate = 24000000, \
+ .reg = 0x4A0 + (_index) * 4, \
+ }; \
+ static struct clk tegra_##_name = { \
+ .name = #_name, \
+ .ops = &tegra30_audio_sync_clk_ops, \
+ .hw = &tegra_##_name##_hw.hw, \
+ .parent_names = mux_audio_sync_clk, \
+ .parents = tegra_sync_source_list, \
+ .num_parents = ARRAY_SIZE(mux_audio_sync_clk), \
+ };
+
+AUDIO_SYNC_CLK(audio0, 0);
+AUDIO_SYNC_CLK(audio1, 1);
+AUDIO_SYNC_CLK(audio2, 2);
+AUDIO_SYNC_CLK(audio3, 3);
+AUDIO_SYNC_CLK(audio4, 4);
+AUDIO_SYNC_CLK(audio5, 5);
+
+static struct clk *tegra_clk_audio_list[] = {
+ &tegra_audio0,
+ &tegra_audio1,
+ &tegra_audio2,
+ &tegra_audio3,
+ &tegra_audio4,
+ &tegra_audio5, /* SPDIF */
+};
+
+#define AUDIO_SYNC_2X_CLK(_name, _index) \
+ static const char *_name##_parent_names[] = { \
+ "tegra_" #_name, \
+ }; \
+ static struct clk *_name##_parents[] = { \
+ &tegra_##_name, \
+ }; \
+ static struct clk tegra_##_name##_2x; \
+ static struct clk_tegra tegra_##_name##_2x_hw = { \
+ .hw = { \
+ .clk = &tegra_##_name##_2x, \
+ }, \
+ .flags = PERIPH_NO_RESET, \
+ .max_rate = 48000000, \
+ .reg = 0x49C, \
+ .reg_shift = 24 + (_index), \
+ .u.periph = { \
+ .clk_num = 113 + (_index), \
+ }, \
+ }; \
+ static struct clk tegra_##_name##_2x = { \
+ .name = #_name "_2x", \
+ .ops = &tegra30_clk_double_ops, \
+ .hw = &tegra_##_name##_2x_hw.hw, \
+ .parent_names = _name##_parent_names, \
+ .parents = _name##_parents, \
+ .parent = &tegra_##_name, \
+ .num_parents = 1, \
+ };
+
+AUDIO_SYNC_2X_CLK(audio0, 0);
+AUDIO_SYNC_2X_CLK(audio1, 1);
+AUDIO_SYNC_2X_CLK(audio2, 2);
+AUDIO_SYNC_2X_CLK(audio3, 3);
+AUDIO_SYNC_2X_CLK(audio4, 4);
+AUDIO_SYNC_2X_CLK(audio5, 5); /* SPDIF */
+
+static struct clk *tegra_clk_audio_2x_list[] = {
+ &tegra_audio0_2x,
+ &tegra_audio1_2x,
+ &tegra_audio2_2x,
+ &tegra_audio3_2x,
+ &tegra_audio4_2x,
+ &tegra_audio5_2x, /* SPDIF */
+};
+
+#define MUX_I2S_SPDIF(_id) \
+static const char *mux_pllaout0_##_id##_2x_pllp_clkm[] = { \
+ "pll_a_out0", \
+ #_id "_2x", \
+ "pll_p", \
+ "clk_m", \
+}; \
+static struct clk *mux_pllaout0_##_id##_2x_pllp_clkm_p[] = { \
+ &tegra_pll_a_out0, \
+ &tegra_##_id##_2x, \
+ &tegra_pll_p, \
+ &tegra_clk_m, \
+};
+
+MUX_I2S_SPDIF(audio0);
+MUX_I2S_SPDIF(audio1);
+MUX_I2S_SPDIF(audio2);
+MUX_I2S_SPDIF(audio3);
+MUX_I2S_SPDIF(audio4);
+MUX_I2S_SPDIF(audio5); /* SPDIF */
+
+static struct clk tegra_extern1;
+static struct clk tegra_extern2;
+static struct clk tegra_extern3;
+
+/* External clock outputs (through PMC) */
+#define MUX_EXTERN_OUT(_id) \
+static const char *mux_clkm_clkm2_clkm4_extern##_id[] = { \
+ "clk_m", \
+ "clk_m_div2", \
+ "clk_m_div4", \
+ "extern" #_id, \
+}; \
+static struct clk *mux_clkm_clkm2_clkm4_extern##_id##_p[] = { \
+ &tegra_clk_m, \
+ &tegra_clk_m_div2, \
+ &tegra_clk_m_div4, \
+ &tegra_extern##_id, \
+};
+
+MUX_EXTERN_OUT(1);
+MUX_EXTERN_OUT(2);
+MUX_EXTERN_OUT(3);
+
+#define CLK_OUT_CLK(_name, _index) \
+ static struct clk tegra_##_name; \
+ static struct clk_tegra tegra_##_name##_hw = { \
+ .hw = { \
+ .clk = &tegra_##_name, \
+ }, \
+ .lookup = { \
+ .dev_id = #_name, \
+ .con_id = "extern" #_index, \
+ }, \
+ .flags = MUX_CLK_OUT, \
+ .fixed_rate = 216000000, \
+ .reg = 0x1a8, \
+ .u.periph = { \
+ .clk_num = (_index - 1) * 8 + 2, \
+ }, \
+ }; \
+ static struct clk tegra_##_name = { \
+ .name = #_name, \
+ .ops = &tegra_clk_out_ops, \
+ .hw = &tegra_##_name##_hw.hw, \
+ .parent_names = mux_clkm_clkm2_clkm4_extern##_index, \
+ .parents = mux_clkm_clkm2_clkm4_extern##_index##_p, \
+ .num_parents = ARRAY_SIZE(mux_clkm_clkm2_clkm4_extern##_index),\
+ };
+
+CLK_OUT_CLK(clk_out_1, 1);
+CLK_OUT_CLK(clk_out_2, 2);
+CLK_OUT_CLK(clk_out_3, 3);
+
+static struct clk *tegra_clk_out_list[] = {
+ &tegra_clk_out_1,
+ &tegra_clk_out_2,
+ &tegra_clk_out_3,
+};
+
+static const char *mux_sclk[] = {
+ "clk_m",
+ "pll_c_out1",
+ "pll_p_out4",
+ "pll_p_out3",
+ "pll_p_out2",
+ "dummy",
+ "clk_32k",
+ "pll_m_out1",
+};
+
+static struct clk *mux_sclk_p[] = {
+ &tegra_clk_m,
+ &tegra_pll_c_out1,
+ &tegra_pll_p_out4,
+ &tegra_pll_p_out3,
+ &tegra_pll_p_out2,
+ NULL,
+ &tegra_clk_32k,
+ &tegra_pll_m_out1,
+};
+
+static struct clk tegra_clk_sclk;
+static struct clk_tegra tegra_clk_sclk_hw = {
+ .hw = {
+ .clk = &tegra_clk_sclk,
+ },
+ .reg = 0x28,
+ .max_rate = 334000000,
+ .min_rate = 40000000,
+};
+
+static struct clk tegra_clk_sclk = {
+ .name = "sclk",
+ .ops = &tegra30_super_ops,
+ .hw = &tegra_clk_sclk_hw.hw,
+ .parent_names = mux_sclk,
+ .parents = mux_sclk_p,
+ .num_parents = ARRAY_SIZE(mux_sclk),
+};
+
+static const char *mux_blink[] = {
+ "clk_32k",
+};
+
+static struct clk *mux_blink_p[] = {
+ &tegra_clk_32k,
+};
+
+static struct clk tegra_clk_blink;
+static struct clk_tegra tegra_clk_blink_hw = {
+ .hw = {
+ .clk = &tegra_clk_blink,
+ },
+ .reg = 0x40,
+ .max_rate = 32768,
+};
+static struct clk tegra_clk_blink = {
+ .name = "blink",
+ .ops = &tegra30_blink_clk_ops,
+ .hw = &tegra_clk_blink_hw.hw,
+ .parent = &tegra_clk_32k,
+ .parent_names = mux_blink,
+ .parents = mux_blink_p,
+ .num_parents = ARRAY_SIZE(mux_blink),
+};
+
+static const char *mux_pllm_pllc_pllp_plla[] = {
+ "pll_m",
+ "pll_c",
+ "pll_p",
+ "pll_a_out0",
+};
+
+static const char *mux_pllp_pllc_pllm_clkm[] = {
+ "pll_p",
+ "pll_c",
+ "pll_m",
+ "clk_m",
+};
+
+static const char *mux_pllp_clkm[] = {
+ "pll_p",
+ "dummy",
+ "dummy",
+ "clk_m",
+};
+
+static const char *mux_pllp_plld_pllc_clkm[] = {
+ "pll_p",
+ "pll_d_out0",
+ "pll_c",
+ "clk_m",
+};
+
+static const char *mux_pllp_pllm_plld_plla_pllc_plld2_clkm[] = {
+ "pll_p",
+ "pll_m",
+ "pll_d_out0",
+ "pll_a_out0",
+ "pll_c",
+ "pll_d2_out0",
+ "clk_m",
+};
+
+static const char *mux_plla_pllc_pllp_clkm[] = {
+ "pll_a_out0",
+ "dummy",
+ "pll_p",
+ "clk_m"
+};
+
+static const char *mux_pllp_pllc_clk32_clkm[] = {
+ "pll_p",
+ "pll_c",
+ "clk_32k",
+ "clk_m",
+};
+
+static const char *mux_pllp_pllc_clkm_clk32[] = {
+ "pll_p",
+ "pll_c",
+ "clk_m",
+ "clk_32k",
+};
+
+static const char *mux_pllp_pllc_pllm[] = {
+ "pll_p",
+ "pll_c",
+ "pll_m",
+};
+
+static const char *mux_clk_m[] = {
+ "clk_m",
+};
+
+static const char *mux_pllp_out3[] = {
+ "pll_p_out3",
+};
+
+static const char *mux_plld_out0[] = {
+ "pll_d_out0",
+};
+
+static const char *mux_plld_out0_plld2_out0[] = {
+ "pll_d_out0",
+ "pll_d2_out0",
+};
+
+static const char *mux_clk_32k[] = {
+ "clk_32k",
+};
+
+static const char *mux_plla_clk32_pllp_clkm_plle[] = {
+ "pll_a_out0",
+ "clk_32k",
+ "pll_p",
+ "clk_m",
+ "pll_e",
+};
+
+static const char *mux_cclk_g[] = {
+ "clk_m",
+ "pll_c",
+ "clk_32k",
+ "pll_m",
+ "pll_p",
+ "pll_p_out4",
+ "pll_p_out3",
+ "dummy",
+ "pll_x",
+};
+
+static struct clk *mux_pllm_pllc_pllp_plla_p[] = {
+ &tegra_pll_m,
+ &tegra_pll_c,
+ &tegra_pll_p,
+ &tegra_pll_a_out0,
+};
+
+static struct clk *mux_pllp_pllc_pllm_clkm_p[] = {
+ &tegra_pll_p,
+ &tegra_pll_c,
+ &tegra_pll_m,
+ &tegra_clk_m,
+};
+
+static struct clk *mux_pllp_clkm_p[] = {
+ &tegra_pll_p,
+ NULL,
+ NULL,
+ &tegra_clk_m,
+};
+
+static struct clk *mux_pllp_plld_pllc_clkm_p[] = {
+ &tegra_pll_p,
+ &tegra_pll_d_out0,
+ &tegra_pll_c,
+ &tegra_clk_m,
+};
+
+static struct clk *mux_pllp_pllm_plld_plla_pllc_plld2_clkm_p[] = {
+ &tegra_pll_p,
+ &tegra_pll_m,
+ &tegra_pll_d_out0,
+ &tegra_pll_a_out0,
+ &tegra_pll_c,
+ &tegra_pll_d2_out0,
+ &tegra_clk_m,
+};
+
+static struct clk *mux_plla_pllc_pllp_clkm_p[] = {
+ &tegra_pll_a_out0,
+ NULL,
+ &tegra_pll_p,
+ &tegra_clk_m,
+};
+
+static struct clk *mux_pllp_pllc_clk32_clkm_p[] = {
+ &tegra_pll_p,
+ &tegra_pll_c,
+ &tegra_clk_32k,
+ &tegra_clk_m,
+};
+
+static struct clk *mux_pllp_pllc_clkm_clk32_p[] = {
+ &tegra_pll_p,
+ &tegra_pll_c,
+ &tegra_clk_m,
+ &tegra_clk_32k,
+};
+
+static struct clk *mux_pllp_pllc_pllm_p[] = {
+ &tegra_pll_p,
+ &tegra_pll_c,
+ &tegra_pll_m,
+};
+
+static struct clk *mux_clk_m_p[] = {
+ &tegra_clk_m,
+};
+
+static struct clk *mux_pllp_out3_p[] = {
+ &tegra_pll_p_out3,
+};
+
+static struct clk *mux_plld_out0_p[] = {
+ &tegra_pll_d_out0,
+};
+
+static struct clk *mux_plld_out0_plld2_out0_p[] = {
+ &tegra_pll_d_out0,
+ &tegra_pll_d2_out0,
+};
+
+static struct clk *mux_clk_32k_p[] = {
+ &tegra_clk_32k,
+};
+
+static struct clk *mux_plla_clk32_pllp_clkm_plle_p[] = {
+ &tegra_pll_a_out0,
+ &tegra_clk_32k,
+ &tegra_pll_p,
+ &tegra_clk_m,
+ &tegra_pll_e,
+};
+
+static struct clk *mux_cclk_g_p[] = {
+ &tegra_clk_m,
+ &tegra_pll_c,
+ &tegra_clk_32k,
+ &tegra_pll_m,
+ &tegra_pll_p,
+ &tegra_pll_p_out4,
+ &tegra_pll_p_out3,
+ NULL,
+ &tegra_pll_x,
+};
+
+static struct clk tegra_clk_cclk_g;
+static struct clk_tegra tegra_clk_cclk_g_hw = {
+ .hw = {
+ .clk = &tegra_clk_cclk_g,
+ },
+ .flags = DIV_U71 | DIV_U71_INT,
+ .reg = 0x368,
+ .max_rate = 1700000000,
+};
+static struct clk tegra_clk_cclk_g = {
+ .name = "cclk_g",
+ .ops = &tegra30_super_ops,
+ .hw = &tegra_clk_cclk_g_hw.hw,
+ .parent_names = mux_cclk_g,
+ .parents = mux_cclk_g_p,
+ .num_parents = ARRAY_SIZE(mux_cclk_g),
+};
+
+static const char *mux_twd[] = {
+ "cclk_g",
+};
+
+static struct clk *mux_twd_p[] = {
+ &tegra_clk_cclk_g,
+};
+
+static struct clk tegra30_clk_twd;
+static struct clk_tegra tegra30_clk_twd_hw = {
+ .hw = {
+ .clk = &tegra30_clk_twd,
+ },
+ .max_rate = 1400000000,
+ .mul = 1,
+ .div = 2,
+};
+
+static struct clk tegra30_clk_twd = {
+ .name = "twd",
+ .ops = &tegra30_twd_ops,
+ .hw = &tegra30_clk_twd_hw.hw,
+ .parent = &tegra_clk_cclk_g,
+ .parent_names = mux_twd,
+ .parents = mux_twd_p,
+ .num_parents = ARRAY_SIZE(mux_twd),
+};
+
+#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, \
+ _max, _inputs, _flags) \
+ static struct clk tegra_##_name; \
+ static struct clk_tegra tegra_##_name##_hw = { \
+ .hw = { \
+ .clk = &tegra_##_name, \
+ }, \
+ .lookup = { \
+ .dev_id = _dev, \
+ .con_id = _con, \
+ }, \
+ .reg = _reg, \
+ .flags = _flags, \
+ .max_rate = _max, \
+ .u.periph = { \
+ .clk_num = _clk_num, \
+ }, \
+ .reset = &tegra30_periph_clk_reset, \
+ }; \
+ static struct clk tegra_##_name = { \
+ .name = #_name, \
+ .ops = &tegra30_periph_clk_ops, \
+ .hw = &tegra_##_name##_hw.hw, \
+ .parent_names = _inputs, \
+ .parents = _inputs##_p, \
+ .num_parents = ARRAY_SIZE(_inputs), \
+ };
+
+PERIPH_CLK(apbdma, "tegra-apbdma", NULL, 34, 0, 26000000, mux_clk_m, 0);
+PERIPH_CLK(rtc, "rtc-tegra", NULL, 4, 0, 32768, mux_clk_32k, PERIPH_NO_RESET | PERIPH_ON_APB);
+PERIPH_CLK(kbc, "tegra-kbc", NULL, 36, 0, 32768, mux_clk_32k, PERIPH_NO_RESET | PERIPH_ON_APB);
+PERIPH_CLK(timer, "timer", NULL, 5, 0, 26000000, mux_clk_m, 0);
+PERIPH_CLK(kfuse, "kfuse-tegra", NULL, 40, 0, 26000000, mux_clk_m, 0);
+PERIPH_CLK(fuse, "fuse-tegra", "fuse", 39, 0, 26000000, mux_clk_m, PERIPH_ON_APB);
+PERIPH_CLK(fuse_burn, "fuse-tegra", "fuse_burn", 39, 0, 26000000, mux_clk_m, PERIPH_ON_APB);
+PERIPH_CLK(apbif, "tegra30-ahub", "apbif", 107, 0, 26000000, mux_clk_m, 0);
+PERIPH_CLK(i2s0, "tegra30-i2s.0", NULL, 30, 0x1d8, 26000000, mux_pllaout0_audio0_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(i2s1, "tegra30-i2s.1", NULL, 11, 0x100, 26000000, mux_pllaout0_audio1_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(i2s2, "tegra30-i2s.2", NULL, 18, 0x104, 26000000, mux_pllaout0_audio2_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(i2s3, "tegra30-i2s.3", NULL, 101, 0x3bc, 26000000, mux_pllaout0_audio3_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(i2s4, "tegra30-i2s.4", NULL, 102, 0x3c0, 26000000, mux_pllaout0_audio4_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(spdif_out, "tegra30-spdif", "spdif_out", 10, 0x108, 100000000, mux_pllaout0_audio5_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(spdif_in, "tegra30-spdif", "spdif_in", 10, 0x10c, 100000000, mux_pllp_pllc_pllm, MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(pwm, "tegra-pwm", NULL, 17, 0x110, 432000000, mux_pllp_pllc_clk32_clkm, MUX | MUX_PWM | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(d_audio, "tegra30-ahub", "d_audio", 106, 0x3d0, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71);
+PERIPH_CLK(dam0, "tegra30-dam.0", NULL, 108, 0x3d8, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71);
+PERIPH_CLK(dam1, "tegra30-dam.1", NULL, 109, 0x3dc, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71);
+PERIPH_CLK(dam2, "tegra30-dam.2", NULL, 110, 0x3e0, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71);
+PERIPH_CLK(hda, "tegra30-hda", "hda", 125, 0x428, 108000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
+PERIPH_CLK(hda2codec_2x, "tegra30-hda", "hda2codec", 111, 0x3e4, 48000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
+PERIPH_CLK(hda2hdmi, "tegra30-hda", "hda2hdmi", 128, 0, 48000000, mux_clk_m, 0);
+PERIPH_CLK(sbc1, "spi_tegra.0", NULL, 41, 0x134, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(sbc2, "spi_tegra.1", NULL, 44, 0x118, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(sbc3, "spi_tegra.2", NULL, 46, 0x11c, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(sbc4, "spi_tegra.3", NULL, 68, 0x1b4, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(sbc5, "spi_tegra.4", NULL, 104, 0x3c8, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(sbc6, "spi_tegra.5", NULL, 105, 0x3cc, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(sata_oob, "tegra_sata_oob", NULL, 123, 0x420, 216000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
+PERIPH_CLK(sata, "tegra_sata", NULL, 124, 0x424, 216000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
+PERIPH_CLK(sata_cold, "tegra_sata_cold", NULL, 129, 0, 48000000, mux_clk_m, 0);
+PERIPH_CLK(ndflash, "tegra_nand", NULL, 13, 0x160, 240000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
+PERIPH_CLK(ndspeed, "tegra_nand_speed", NULL, 80, 0x3f8, 240000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
+PERIPH_CLK(vfir, "vfir", NULL, 7, 0x168, 72000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(sdmmc1, "sdhci-tegra.0", NULL, 14, 0x150, 208000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(sdmmc2, "sdhci-tegra.1", NULL, 9, 0x154, 104000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(sdmmc3, "sdhci-tegra.2", NULL, 69, 0x1bc, 208000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(sdmmc4, "sdhci-tegra.3", NULL, 15, 0x164, 104000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* scales with voltage */
+PERIPH_CLK(vcp, "tegra-avp", "vcp", 29, 0, 250000000, mux_clk_m, 0);
+PERIPH_CLK(bsea, "tegra-avp", "bsea", 62, 0, 250000000, mux_clk_m, 0);
+PERIPH_CLK(bsev, "tegra-aes", "bsev", 63, 0, 250000000, mux_clk_m, 0);
+PERIPH_CLK(vde, "vde", NULL, 61, 0x1c8, 520000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_INT);
+PERIPH_CLK(csite, "csite", NULL, 73, 0x1d4, 144000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71); /* max rate ??? */
+PERIPH_CLK(la, "la", NULL, 76, 0x1f8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71);
+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", "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);
+PERIPH_CLK(uartd, "tegra-uart.3", NULL, 65, 0x1c0, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB);
+PERIPH_CLK(uarte, "tegra-uart.4", NULL, 66, 0x1c4, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB);
+PERIPH_CLK(vi, "tegra_camera", "vi", 20, 0x148, 425000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT);
+PERIPH_CLK(3d, "3d", NULL, 24, 0x158, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET);
+PERIPH_CLK(3d2, "3d2", NULL, 98, 0x3b0, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET);
+PERIPH_CLK(2d, "2d", NULL, 21, 0x15c, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE);
+PERIPH_CLK(vi_sensor, "tegra_camera", "vi_sensor", 20, 0x1a8, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_NO_RESET);
+PERIPH_CLK(epp, "epp", NULL, 19, 0x16c, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT);
+PERIPH_CLK(mpe, "mpe", NULL, 60, 0x170, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT);
+PERIPH_CLK(host1x, "host1x", NULL, 28, 0x180, 260000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT);
+PERIPH_CLK(cve, "cve", NULL, 49, 0x140, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(tvo, "tvo", NULL, 49, 0x188, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(dtv, "dtv", NULL, 79, 0x1dc, 250000000, mux_clk_m, 0);
+PERIPH_CLK(hdmi, "hdmi", NULL, 51, 0x18c, 148500000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8 | DIV_U71);
+PERIPH_CLK(tvdac, "tvdac", NULL, 53, 0x194, 220000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71); /* requires min voltage */
+PERIPH_CLK(disp1, "tegradc.0", NULL, 27, 0x138, 600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8);
+PERIPH_CLK(disp2, "tegradc.1", NULL, 26, 0x13c, 600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8);
+PERIPH_CLK(usbd, "fsl-tegra-udc", NULL, 22, 0, 480000000, mux_clk_m, 0); /* requires min voltage */
+PERIPH_CLK(usb2, "tegra-ehci.1", NULL, 58, 0, 480000000, mux_clk_m, 0); /* requires min voltage */
+PERIPH_CLK(usb3, "tegra-ehci.2", NULL, 59, 0, 480000000, mux_clk_m, 0); /* requires min voltage */
+PERIPH_CLK(dsia, "tegradc.0", "dsia", 48, 0, 500000000, mux_plld_out0, 0);
+PERIPH_CLK(csi, "tegra_camera", "csi", 52, 0, 102000000, mux_pllp_out3, 0);
+PERIPH_CLK(isp, "tegra_camera", "isp", 23, 0, 150000000, mux_clk_m, 0); /* same frequency as VI */
+PERIPH_CLK(csus, "tegra_camera", "csus", 92, 0, 150000000, mux_clk_m, PERIPH_NO_RESET);
+PERIPH_CLK(tsensor, "tegra-tsensor", NULL, 100, 0x3b8, 216000000, mux_pllp_pllc_clkm_clk32, MUX | DIV_U71);
+PERIPH_CLK(actmon, "actmon", NULL, 119, 0x3e8, 216000000, mux_pllp_pllc_clk32_clkm, MUX | DIV_U71);
+PERIPH_CLK(extern1, "extern1", NULL, 120, 0x3ec, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71);
+PERIPH_CLK(extern2, "extern2", NULL, 121, 0x3f0, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71);
+PERIPH_CLK(extern3, "extern3", NULL, 122, 0x3f4, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71);
+PERIPH_CLK(i2cslow, "i2cslow", NULL, 81, 0x3fc, 26000000, mux_pllp_pllc_clk32_clkm, MUX | DIV_U71 | PERIPH_ON_APB);
+PERIPH_CLK(pcie, "tegra-pcie", "pcie", 70, 0, 250000000, mux_clk_m, 0);
+PERIPH_CLK(afi, "tegra-pcie", "afi", 72, 0, 250000000, mux_clk_m, 0);
+PERIPH_CLK(se, "se", NULL, 127, 0x42c, 520000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_INT);
+
+static struct clk tegra_dsib;
+static struct clk_tegra tegra_dsib_hw = {
+ .hw = {
+ .clk = &tegra_dsib,
+ },
+ .lookup = {
+ .dev_id = "tegradc.1",
+ .con_id = "dsib",
+ },
+ .reg = 0xd0,
+ .flags = MUX | PLLD,
+ .max_rate = 500000000,
+ .u.periph = {
+ .clk_num = 82,
+ },
+ .reset = &tegra30_periph_clk_reset,
+};
+static struct clk tegra_dsib = {
+ .name = "dsib",
+ .ops = &tegra30_dsib_clk_ops,
+ .hw = &tegra_dsib_hw.hw,
+ .parent_names = mux_plld_out0_plld2_out0,
+ .parents = mux_plld_out0_plld2_out0_p,
+ .num_parents = ARRAY_SIZE(mux_plld_out0_plld2_out0),
+};
+
+struct clk *tegra_list_clks[] = {
+ &tegra_apbdma,
+ &tegra_rtc,
+ &tegra_kbc,
+ &tegra_kfuse,
+ &tegra_fuse,
+ &tegra_fuse_burn,
+ &tegra_apbif,
+ &tegra_i2s0,
+ &tegra_i2s1,
+ &tegra_i2s2,
+ &tegra_i2s3,
+ &tegra_i2s4,
+ &tegra_spdif_out,
+ &tegra_spdif_in,
+ &tegra_pwm,
+ &tegra_d_audio,
+ &tegra_dam0,
+ &tegra_dam1,
+ &tegra_dam2,
+ &tegra_hda,
+ &tegra_hda2codec_2x,
+ &tegra_hda2hdmi,
+ &tegra_sbc1,
+ &tegra_sbc2,
+ &tegra_sbc3,
+ &tegra_sbc4,
+ &tegra_sbc5,
+ &tegra_sbc6,
+ &tegra_sata_oob,
+ &tegra_sata,
+ &tegra_sata_cold,
+ &tegra_ndflash,
+ &tegra_ndspeed,
+ &tegra_vfir,
+ &tegra_sdmmc1,
+ &tegra_sdmmc2,
+ &tegra_sdmmc3,
+ &tegra_sdmmc4,
+ &tegra_vcp,
+ &tegra_bsea,
+ &tegra_bsev,
+ &tegra_vde,
+ &tegra_csite,
+ &tegra_la,
+ &tegra_owr,
+ &tegra_nor,
+ &tegra_mipi,
+ &tegra_i2c1,
+ &tegra_i2c2,
+ &tegra_i2c3,
+ &tegra_i2c4,
+ &tegra_i2c5,
+ &tegra_uarta,
+ &tegra_uartb,
+ &tegra_uartc,
+ &tegra_uartd,
+ &tegra_uarte,
+ &tegra_vi,
+ &tegra_3d,
+ &tegra_3d2,
+ &tegra_2d,
+ &tegra_vi_sensor,
+ &tegra_epp,
+ &tegra_mpe,
+ &tegra_host1x,
+ &tegra_cve,
+ &tegra_tvo,
+ &tegra_dtv,
+ &tegra_hdmi,
+ &tegra_tvdac,
+ &tegra_disp1,
+ &tegra_disp2,
+ &tegra_usbd,
+ &tegra_usb2,
+ &tegra_usb3,
+ &tegra_dsia,
+ &tegra_dsib,
+ &tegra_csi,
+ &tegra_isp,
+ &tegra_csus,
+ &tegra_tsensor,
+ &tegra_actmon,
+ &tegra_extern1,
+ &tegra_extern2,
+ &tegra_extern3,
+ &tegra_i2cslow,
+ &tegra_pcie,
+ &tegra_afi,
+ &tegra_se,
+};
+
+#define CLK_DUPLICATE(_name, _dev, _con) \
+ { \
+ .name = _name, \
+ .lookup = { \
+ .dev_id = _dev, \
+ .con_id = _con, \
+ }, \
+ }
+
+/* Some clocks may be used by different drivers depending on the board
+ * configuration. List those here to register them twice in the clock lookup
+ * table under two names.
+ */
+struct clk_duplicate tegra_clk_duplicates[] = {
+ CLK_DUPLICATE("uarta", "serial8250.0", NULL),
+ CLK_DUPLICATE("uartb", "serial8250.1", NULL),
+ CLK_DUPLICATE("uartc", "serial8250.2", NULL),
+ CLK_DUPLICATE("uartd", "serial8250.3", NULL),
+ CLK_DUPLICATE("uarte", "serial8250.4", NULL),
+ CLK_DUPLICATE("usbd", "utmip-pad", NULL),
+ CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),
+ CLK_DUPLICATE("usbd", "tegra-otg", NULL),
+ CLK_DUPLICATE("hdmi", "tegradc.0", "hdmi"),
+ CLK_DUPLICATE("hdmi", "tegradc.1", "hdmi"),
+ CLK_DUPLICATE("dsib", "tegradc.0", "dsib"),
+ CLK_DUPLICATE("dsia", "tegradc.1", "dsia"),
+ CLK_DUPLICATE("bsev", "tegra-avp", "bsev"),
+ CLK_DUPLICATE("bsev", "nvavp", "bsev"),
+ CLK_DUPLICATE("vde", "tegra-aes", "vde"),
+ CLK_DUPLICATE("bsea", "tegra-aes", "bsea"),
+ CLK_DUPLICATE("bsea", "nvavp", "bsea"),
+ CLK_DUPLICATE("cml1", "tegra_sata_cml", NULL),
+ CLK_DUPLICATE("cml0", "tegra_pcie", "cml"),
+ CLK_DUPLICATE("pciex", "tegra_pcie", "pciex"),
+ CLK_DUPLICATE("i2c1", "tegra-i2c-slave.0", NULL),
+ CLK_DUPLICATE("i2c2", "tegra-i2c-slave.1", NULL),
+ CLK_DUPLICATE("i2c3", "tegra-i2c-slave.2", NULL),
+ CLK_DUPLICATE("i2c4", "tegra-i2c-slave.3", NULL),
+ CLK_DUPLICATE("i2c5", "tegra-i2c-slave.4", NULL),
+ CLK_DUPLICATE("sbc1", "spi_slave_tegra.0", NULL),
+ CLK_DUPLICATE("sbc2", "spi_slave_tegra.1", NULL),
+ CLK_DUPLICATE("sbc3", "spi_slave_tegra.2", NULL),
+ CLK_DUPLICATE("sbc4", "spi_slave_tegra.3", NULL),
+ CLK_DUPLICATE("sbc5", "spi_slave_tegra.4", NULL),
+ CLK_DUPLICATE("sbc6", "spi_slave_tegra.5", NULL),
+ CLK_DUPLICATE("twd", "smp_twd", NULL),
+ CLK_DUPLICATE("vcp", "nvavp", "vcp"),
+ CLK_DUPLICATE("i2s0", NULL, "i2s0"),
+ CLK_DUPLICATE("i2s1", NULL, "i2s1"),
+ CLK_DUPLICATE("i2s2", NULL, "i2s2"),
+ CLK_DUPLICATE("i2s3", NULL, "i2s3"),
+ CLK_DUPLICATE("i2s4", NULL, "i2s4"),
+ CLK_DUPLICATE("dam0", NULL, "dam0"),
+ 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[] = {
+ &tegra_clk_32k,
+ &tegra_clk_m,
+ &tegra_clk_m_div2,
+ &tegra_clk_m_div4,
+ &tegra_pll_ref,
+ &tegra_pll_m,
+ &tegra_pll_m_out1,
+ &tegra_pll_c,
+ &tegra_pll_c_out1,
+ &tegra_pll_p,
+ &tegra_pll_p_out1,
+ &tegra_pll_p_out2,
+ &tegra_pll_p_out3,
+ &tegra_pll_p_out4,
+ &tegra_pll_a,
+ &tegra_pll_a_out0,
+ &tegra_pll_d,
+ &tegra_pll_d_out0,
+ &tegra_pll_d2,
+ &tegra_pll_d2_out0,
+ &tegra_pll_u,
+ &tegra_pll_x,
+ &tegra_pll_x_out0,
+ &tegra_pll_e,
+ &tegra_clk_cclk_g,
+ &tegra_cml0,
+ &tegra_cml1,
+ &tegra_pciex,
+ &tegra_clk_sclk,
+ &tegra_clk_blink,
+ &tegra30_clk_twd,
+};
+
+static void tegra30_init_one_clock(struct clk *c)
+{
+ struct clk_tegra *clk = to_clk_tegra(c->hw);
+ __clk_init(NULL, c);
+ INIT_LIST_HEAD(&clk->shared_bus_list);
+ if (!clk->lookup.dev_id && !clk->lookup.con_id)
+ clk->lookup.con_id = c->name;
+ clk->lookup.clk = c;
+ clkdev_add(&clk->lookup);
+ tegra_clk_add(c);
+}
+
+void __init tegra30_init_clocks(void)
+{
+ int i;
+ struct clk *c;
+
+ for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++)
+ tegra30_init_one_clock(tegra_ptr_clks[i]);
+
+ for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++)
+ tegra30_init_one_clock(tegra_list_clks[i]);
+
+ for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) {
+ c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name);
+ if (!c) {
+ pr_err("%s: Unknown duplicate clock %s\n", __func__,
+ tegra_clk_duplicates[i].name);
+ continue;
+ }
+
+ tegra_clk_duplicates[i].lookup.clk = c;
+ clkdev_add(&tegra_clk_duplicates[i].lookup);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(tegra_sync_source_list); i++)
+ tegra30_init_one_clock(tegra_sync_source_list[i]);
+ for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_list); i++)
+ tegra30_init_one_clock(tegra_clk_audio_list[i]);
+ for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_2x_list); i++)
+ tegra30_init_one_clock(tegra_clk_audio_2x_list[i]);
+
+ for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++)
+ tegra30_init_one_clock(tegra_clk_out_list[i]);
+}
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index cd8ea3588f93..855ca02581e8 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>
@@ -763,10 +762,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 dd36eba9506c..13910baae228 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -41,9 +41,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 39407cbe34c6..24e23f3dd6a8 100644
--- a/arch/arm/plat-omap/debug-leds.c
+++ b/arch/arm/plat-omap/debug-leds.c
@@ -1,279 +1,118 @@
/*
* 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/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;
@@ -281,13 +120,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 ece958d3762e..324e958d5ac3 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 5b421840c48d..f8cdeeb5c484 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -5,6 +5,8 @@
# Rewritten to use lists instead of if-statements.
#
+obj-y += bus/
+
# GPIO must come after pinctrl as gpios may need to mux pins etc
obj-y += pinctrl/
obj-y += gpio/
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 d15225ff5c49..ab911a33f8a8 100644
--- a/arch/arm/mach-omap2/omap_l3_noc.c
+++ b/drivers/bus/omap_l3_noc.c
@@ -190,7 +190,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",
- OMAP44XX_IRQ_L3_DBG);
+ l3->debug_irq);
goto err3;
}
@@ -200,7 +200,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",
- OMAP44XX_IRQ_L3_APP);
+ 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 ba126cc04073..41ab7f66cdf9 100644
--- a/drivers/gpio/gpio-samsung.c
+++ b/drivers/gpio/gpio-samsung.c
@@ -2734,6 +2734,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..447818d9851b
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-exynos.c
@@ -0,0 +1,560 @@
+/*
+ * 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);
+ unsigned int shift = EXYNOS_EINT_CON_LEN * edata->pin;
+ unsigned int con, trig_type;
+ unsigned long reg_con = ctrl->geint_con + edata->eint_offset;
+
+ 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 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 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;
+
+ chained_irq_enter(chip, desc);
+ pend = readl(d->virt_base + d->ctrl->weint_pend + 0x8);
+ exynos_irq_demux_eint(16, pend, eintd->domain);
+ pend = readl(d->virt_base + d->ctrl->weint_pend + 0xC);
+ exynos_irq_demux_eint(24, pend, 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;
+ struct exynos_weint_data *weint_data;
+ int idx, irq;
+
+ wkup_np = of_find_matching_node(dev->of_node, exynos_wkup_irq_ids);
+ if (!wkup_np) {
+ dev_err(dev, "wakeup controller node not found\n");
+ return -ENODEV;
+ }
+
+ d->wkup_irqd = irq_domain_add_linear(wkup_np, d->ctrl->nr_wint,
+ &exynos_wkup_irqd_ops, d);
+ if (!d->gpio_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..5f27ba974a3a
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-exynos.h
@@ -0,0 +1,217 @@
+/*
+ * 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
+
+/* 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..8a24223d5334
--- /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,
+ &reg, &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, &reg, &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, &reg_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, &reg, &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, &reg, &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 inline 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 */
OpenPOWER on IntegriCloud