diff options
171 files changed, 9757 insertions, 8243 deletions
diff --git a/Documentation/devicetree/bindings/bus/omap-ocp2scp.txt b/Documentation/devicetree/bindings/bus/omap-ocp2scp.txt new file mode 100644 index 00000000000..d2fe064a828 --- /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 00000000000..03dee50532f --- /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 c5f9ae5dbd1..aad7400e091 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 00000000000..b12cf272ad0 --- /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 02891fe876e..a4bd0c9a206 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 04cbbcb6ff9..8a780b2a508 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 2afdf67c212..c285a9d777d 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 d54e2acd3ab..4ae57a34a58 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 ade6b2f2311..1e8712ef062 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 1cf96264cba..d2050cada82 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 994d331b231..e1b0e80b54a 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 ad562ee6420..7cf87856d63 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 bbf729e2fb6..921480c23b9 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 e7d7942927f..ea116cbdffa 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 9160f3b7751..42d5db1876a 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 d5e260b8b16..52f1488591c 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 2e39f38b962..a1501e1e1a9 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 c545739f39b..00000000000 --- 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 7ad2d5cf700..8951577c4ce 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 1911dae19e4..00000000000 --- 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 693b744fd57..04eea22d795 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 af2afb01967..09be0c3c906 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 01fb7325fec..9ac427a702d 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); +	for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { -	/* CLK */ -	at91_set_A_periph(AT91_PIN_PA27, 0); +		if (!data->slot[i].bus_width) +			continue; -	if (data->slot_b) { -		/* CMD */ -		at91_set_B_periph(AT91_PIN_PA8, 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); -		/* 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); +		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;  		} -	} else { -		/* CMD */ -		at91_set_A_periph(AT91_PIN_PA28, 1); +		if (slot_count) { +			/* CLK */ +			at91_set_A_periph(AT91_PIN_PA27, 0); -		/* 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); +			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 7b9c2ba396e..156e639257c 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 8df5c1bdff9..06c0c6e025b 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); +	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); +		/* CLK */ +		at91_set_B_periph(AT91_PIN_PA2, 0); -	/* CMD */ -	at91_set_B_periph(AT91_PIN_PA1, 1); +		/* 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); -	} +		/* 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); +		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 84b38105231..144ef5de51b 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 eb6bbf86fb9..1e176aaaaec 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); -			/* 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); +		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;  			} -		} else { -			/* CMD */ -			at91_set_A_periph(AT91_PIN_PA1, 1); +			if (slot_count) { +				/* CLK */ +				at91_set_A_periph(AT91_PIN_PA12, 0); -			/* 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); +				mmc0_data = *data; +				platform_device_register(&at91sam9263_mmc0_device);  			} -		} - -		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 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;  			} -		} else { -			/* CMD */ -			at91_set_A_periph(AT91_PIN_PA7, 1); +			if (slot_count) { +				/* CLK */ +				at91_set_A_periph(AT91_PIN_PA6, 0); -			/* 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 f09fff93217..ea4479e7c3f 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); +	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); +		/* CLK */ +		at91_set_A_periph(AT91_PIN_PA2, 0); -	/* CMD */ -	at91_set_A_periph(AT91_PIN_PA1, 1); +		/* 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); -	} +		/* 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 de7be193181..93a832f7023 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 a5b002f32a6..71d8f362a1d 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 ecbc13b594d..e71c473316e 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 2e6d043c82f..2cbd1a2b6c3 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 462bc319cbc..3e37437a7a6 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 d1e1f3fc0a4..0cfac16ee9d 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 9c24cb25707..3d931ffac4b 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 82bdfde3405..d93658a2b12 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 6cc83a87d77..fa98abacb1b 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 69ab1247ef8..6e47071d820 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 64c1dbf88a0..86050da3ba5 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 5d96cb85175..abe9fed7a3e 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 18103c5d993..9cda3fd346a 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 12706550450..f83e1de699e 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 bf351e28542..799f214edeb 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 cc2bf979607..66338e7ebfb 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 62e19e64c9d..5d1b5729dc6 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 c3b43aefdb7..a0ecf04e9ae 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 7bf6da70d7d..c5f01acce3c 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 889c1bf71eb..8cd6e679fbe 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 2269be5fa38..27b3af1a304 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 82adf581afc..073e17403d9 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 4ea4ee00364..3ab2b86a376 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 e7dc3ead704..fb89ea92e3f 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 29eae1626bf..c3fb31d5116 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 c1476b9fe7b..6ea069b5733 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 516d340549d..f162fdfd66e 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 369afc2ffc5..c55a4364ffb 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 8dfafe76ffe..1b1e62b5f41 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 f2f0256232e..5872b49bfae 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 f15293bd797..3a4af00db9e 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 bbc449fbe14..00000000000 --- 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 f266d90b9ef..b752b586fc2 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 6520ac83580..935e4af01a2 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 99e14e36250..0398258c20c 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 b5b4c8c9db1..195b50eb1e5 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 4eb39cdf75e..715b690e500 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 3afb1b25946..0b64dd430d6 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 5bd266754b9..00000000000 --- 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 27716a7e5fc..b09551ef89c 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 cac9f67e7da..d2d14339c6c 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 5a2bd89cbdc..00000000000 --- 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 ebeef966e1f..5521d18bf19 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 3fa6c51390d..2af5034ea29 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 445d57adb04..1a78692e32a 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 466defa9784..7a7f6d3273b 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 853efd9133c..9324ef965c2 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 73bd6381287..47399bc3c02 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 85a3c9aa7d1..1e6594a0f29 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 4bd70754729..00000000000 --- 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 398e9e53e18..cd169c38616 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 44a4ab195fb..cd8836f43f0 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 86cb5a04a40..1fa9c45c1ae 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 8784705edb6..7ee1c1eac35 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 f6b14a14a95..00000000000 --- 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 3a066ee8d02..00000000000 --- 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 936ed426b84..00000000000 --- 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 ae6dd93b8dd..00000000000 --- 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 a1e9fedc376..00000000000 --- 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 4062480bfec..4d4816fd6fc 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 eae49c3980c..74529549130 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 fcd4e85c4dd..728b05eb296 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 f6a24b3f9c4..7fed980acb9 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 78a6a11d821..9b1c9531029 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 2f5dc54cd4c..51ba2b81a10 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 399130fac0b..0a56b9444f1 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 92df49c1b62..ed50910b08a 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 0cfe8af3d3b..47a7ae96156 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 be0f7df8685..d4337e300ad 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 6ff466bd43e..ae1e9977603 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 06b060025d1..00000000000 --- 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 0bd85c884a7..00000000000 --- 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 4058ab340fe..00000000000 --- 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 bbe4d5f6afa..00000000000 --- 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 7f0dfe01345..00000000000 --- 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 0ca0db78790..3c48035afd6 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 1aebaf71946..bdc6c335830 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 45868bb43cb..d22dee96484 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 f8f2c0ac4c0..f2141ae5a7d 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 baf382c5e77..21661ade885 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 b1d7cafa1a6..c0ff882c5cb 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 a98c536e332..30779ae40c0 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 59650174e6e..081cd72c090 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 3f2f605624e..1ce62b9f846 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 60b97ec0167..1aed9e70465 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 d673211f121..1710ed1a0ac 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 b30fb99b587..038df4894b0 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 09d7f4b4b35..5240f104a3c 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 7f86bd91182..fc106aab7c7 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 b775a0abec0..b2ce04bf4c9 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 3699176bca9..00000000000 --- 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 f99fac3eedb..00000000000 --- 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 30fc3b2bf55..00000000000 --- 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 f8e47235bab..00000000000 --- 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 50a5b143b46..00000000000 --- 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 5fe71a0f105..00000000000 --- 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 776b6020f55..00000000000 --- 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 45be9b04e7b..29657183c45 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 2704bcd869c..c709979ee75 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 25609076921..081c778a10a 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> - -#define LED_STATE_ENABLED	1 -#define LED_STATE_CLAIMED	2 - -#define SEQUOIA_LED_GREEN       (1<<6) -#define SEQUOIA_LED_AMBER       (1<<5) -#define SEQUOIA_LED_BACK        (1<<7) +#include <asm/mach-types.h> -static char led_state; -static short hw_led_state; -static short saved_state; +#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) +struct shark_led { +	struct led_classdev cdev; +	u8 mask; +}; -static DEFINE_RAW_SPINLOCK(leds_lock); +/* + * 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 */ +}; -short sequoia_read(int addr) { -  outw(addr,0x24); -  return inw(0x26); +static u16 led_reg_read(void) +{ +	outw(0x09, 0x24); +	return inw(0x26);  } -void sequoia_write(short value,short addr) { -  outw(addr,0x24); -  outw(value,0x26); +static void led_reg_write(u16 value) +{ +	outw(0x09, 0x24); +	outw(value, 0x26);  } -static void sequoia_leds_event(led_event_t evt) +static void shark_led_set(struct led_classdev *cdev, +			      enum led_brightness b)  { -	unsigned long flags; - -	raw_spin_lock_irqsave(&leds_lock, flags); - -	hw_led_state = sequoia_read(0x09); - -	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; +	struct shark_led *led = container_of(cdev, +						 struct shark_led, cdev); +	u16 reg = led_reg_read(); -	case led_release: -		led_state &= ~LED_STATE_CLAIMED; -		hw_led_state = saved_state; -		break; +	if (b != LED_OFF) +		reg |= led->mask; +	else +		reg &= ~led->mask; -#ifdef CONFIG_LEDS_TIMER -	case led_timer: -		if (!(led_state & LED_STATE_CLAIMED)) -			hw_led_state ^= SEQUOIA_LED_GREEN; -		break; -#endif +	led_reg_write(reg); +} -#ifdef CONFIG_LEDS_CPU -	case led_idle_start: -		if (!(led_state & LED_STATE_CLAIMED)) -			hw_led_state &= ~SEQUOIA_LED_BACK; -		break; +static enum led_brightness shark_led_get(struct led_classdev *cdev) +{ +	struct shark_led *led = container_of(cdev, +						 struct shark_led, cdev); +	u16 reg = led_reg_read(); -	case led_idle_end: -		if (!(led_state & LED_STATE_CLAIMED)) -			hw_led_state |= SEQUOIA_LED_BACK; -		break; -#endif +	return (reg & led->mask) ? LED_FULL : LED_OFF; +} -	case led_green_on: -		if (led_state & LED_STATE_CLAIMED) -			hw_led_state &= ~SEQUOIA_LED_GREEN; -		break; +static int __init shark_leds_init(void) +{ +	int i; +	u16 reg; -	case led_green_off: -		if (led_state & LED_STATE_CLAIMED) -			hw_led_state |= SEQUOIA_LED_GREEN; -		break; +	if (!machine_is_shark()) +		return -ENODEV; -	case led_amber_on: -		if (led_state & LED_STATE_CLAIMED) -			hw_led_state &= ~SEQUOIA_LED_AMBER; -		break; +	for (i = 0; i < ARRAY_SIZE(shark_leds); i++) { +		struct shark_led *led; -	case led_amber_off: -		if (led_state & LED_STATE_CLAIMED) -			hw_led_state |= SEQUOIA_LED_AMBER; -		break; +		led = kzalloc(sizeof(*led), GFP_KERNEL); +		if (!led) +			break; -	case led_red_on: -		if (led_state & LED_STATE_CLAIMED) -			hw_led_state |= SEQUOIA_LED_BACK; -		break; +		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; -	case led_red_off: -		if (led_state & LED_STATE_CLAIMED) -			hw_led_state &= ~SEQUOIA_LED_BACK; -		break; +		/* Count in 5 bits offset */ +		led->mask = BIT(i + 5); -	default: -		break; +		if (led_classdev_register(NULL, &led->cdev) < 0) { +			kfree(led); +			break; +		}  	} -	if  (led_state & LED_STATE_ENABLED) -		sequoia_write(hw_led_state,0x09); - -	raw_spin_unlock_irqrestore(&leds_lock, flags); -} - -static int __init leds_init(void) -{ -	extern void (*leds_event)(led_event_t); -	short temp; -	 -	leds_event = sequoia_leds_event; -  	/* 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 c3d7303b9ac..f07f99452a9 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 c0999633a9a..b4e7cc14713 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 58f981c0819..632133fc985 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 bc300657deb..2aa37f5c44c 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 96fef6bcc65..f3654f83099 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 ceb52db1e2f..627bf0f4262 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 d97e403303a..95f3a547c77 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 00000000000..840ab262272 --- /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 00000000000..8bfd31bcc49 --- /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 00000000000..6cfe2f9840f --- /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 a703844b206..00000000000 --- 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 6674f100e16..63615dadfbb 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 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, +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; +} + +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); - -	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)); +		return (index == 0) ? 0 : (-EINVAL); -			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, +}; + +/* Audio sync clock ops */ +struct clk_ops tegra_sync_source_ops = { +	.recalc_rate = tegra30_clk_fixed_recalc_rate,  }; -static void tegra30_audio_sync_clk_init(struct clk *c) +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, +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_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 }, +struct clk_ops tegra_pciex_clk_ops = { +	.recalc_rate = tegra30_clk_fixed_recalc_rate,  }; - -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}, -}; - -static struct clk tegra_clk_sclk = { -	.name	= "sclk", -	.inputs	= mux_sclk, -	.reg	= 0x28, -	.ops	= &tegra_super_ops, -	.max_rate = 334000000, -	.min_rate = 40000000, -}; - -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 00000000000..f2f88fef6b8 --- /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 00000000000..8d2dbdd5917 --- /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 cd8ea3588f9..855ca02581e 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 dd36eba9506..13910baae22 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 39407cbe34c..24e23f3dd6a 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 4dcb11c3d89..60552e22f22 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 8d5c10a5084..2a4ae8a6a08 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 3169fa555ea..d2490d00b46 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 ece958d3762..324e958d5ac 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 5b421840c48..f8cdeeb5c48 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 00000000000..bbec35d21fe --- /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 00000000000..45d997c8545 --- /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 00000000000..ff63560b846 --- /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 d15225ff5c4..ab911a33f8a 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 a6ce34dc481..a6ce34dc481 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 acc216491b8..acc216491b8 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 4f3cebca417..4f3cebca417 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 d45c3345b4a..a0e2f7d7035 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 ba126cc0407..41ab7f66cdf 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 9a08c57bc93..f981ac4e678 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 c96bbaadeeb..16578d3b52b 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 a4429a9217b..a9b627c4f8b 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 00000000000..b312056da14 --- /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 8ca417614c5..598cd0a3ade 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 54e3588bef6..34e94c7f68c 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 f40b1f81ff2..6a88113e11d 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 00000000000..447818d9851 --- /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 00000000000..5f27ba974a3 --- /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 00000000000..8a24223d533 --- /dev/null +++ b/drivers/pinctrl/pinctrl-samsung.c @@ -0,0 +1,888 @@ +/* + * pin-controller/pin-mux/pin-config/gpio-driver for Samsung's SoC's. + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + *		http://www.samsung.com + * Copyright (c) 2012 Linaro Ltd + *		http://www.linaro.org + * + * Author: Thomas Abraham <thomas.ab@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This driver implements the Samsung pinctrl driver. It supports setting up of + * pinmux and pinconf configurations. The gpiolib interface is also included. + * External interrupt (gpio and wakeup) support are not included in this driver + * but provides extensions to which platform specific implementation of the gpio + * and wakeup interrupts can be hooked to. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/gpio.h> + +#include "core.h" +#include "pinctrl-samsung.h" + +#define GROUP_SUFFIX		"-grp" +#define GSUFFIX_LEN		sizeof(GROUP_SUFFIX) +#define FUNCTION_SUFFIX		"-mux" +#define FSUFFIX_LEN		sizeof(FUNCTION_SUFFIX) + +/* list of all possible config options supported */ +struct pin_config { +	char		*prop_cfg; +	unsigned int	cfg_type; +} pcfgs[] = { +	{ "samsung,pin-pud", PINCFG_TYPE_PUD }, +	{ "samsung,pin-drv", PINCFG_TYPE_DRV }, +	{ "samsung,pin-con-pdn", PINCFG_TYPE_CON_PDN }, +	{ "samsung,pin-pud-pdn", PINCFG_TYPE_PUD_PDN }, +}; + +/* check if the selector is a valid pin group selector */ +static int samsung_get_group_count(struct pinctrl_dev *pctldev) +{ +	struct samsung_pinctrl_drv_data *drvdata; + +	drvdata = pinctrl_dev_get_drvdata(pctldev); +	return drvdata->nr_groups; +} + +/* return the name of the group selected by the group selector */ +static const char *samsung_get_group_name(struct pinctrl_dev *pctldev, +						unsigned selector) +{ +	struct samsung_pinctrl_drv_data *drvdata; + +	drvdata = pinctrl_dev_get_drvdata(pctldev); +	return drvdata->pin_groups[selector].name; +} + +/* return the pin numbers associated with the specified group */ +static int samsung_get_group_pins(struct pinctrl_dev *pctldev, +		unsigned selector, const unsigned **pins, unsigned *num_pins) +{ +	struct samsung_pinctrl_drv_data *drvdata; + +	drvdata = pinctrl_dev_get_drvdata(pctldev); +	*pins = drvdata->pin_groups[selector].pins; +	*num_pins = drvdata->pin_groups[selector].num_pins; +	return 0; +} + +/* create pinctrl_map entries by parsing device tree nodes */ +static int samsung_dt_node_to_map(struct pinctrl_dev *pctldev, +			struct device_node *np, struct pinctrl_map **maps, +			unsigned *nmaps) +{ +	struct device *dev = pctldev->dev; +	struct pinctrl_map *map; +	unsigned long *cfg = NULL; +	char *gname, *fname; +	int cfg_cnt = 0, map_cnt = 0, idx = 0; + +	/* count the number of config options specfied in the node */ +	for (idx = 0; idx < ARRAY_SIZE(pcfgs); idx++) { +		if (of_find_property(np, pcfgs[idx].prop_cfg, NULL)) +			cfg_cnt++; +	} + +	/* +	 * Find out the number of map entries to create. All the config options +	 * can be accomadated into a single config map entry. +	 */ +	if (cfg_cnt) +		map_cnt = 1; +	if (of_find_property(np, "samsung,pin-function", NULL)) +		map_cnt++; +	if (!map_cnt) { +		dev_err(dev, "node %s does not have either config or function " +				"configurations\n", np->name); +		return -EINVAL; +	} + +	/* Allocate memory for pin-map entries */ +	map = kzalloc(sizeof(*map) * map_cnt, GFP_KERNEL); +	if (!map) { +		dev_err(dev, "could not alloc memory for pin-maps\n"); +		return -ENOMEM; +	} +	*nmaps = 0; + +	/* +	 * Allocate memory for pin group name. The pin group name is derived +	 * from the node name from which these map entries are be created. +	 */ +	gname = kzalloc(strlen(np->name) + GSUFFIX_LEN, GFP_KERNEL); +	if (!gname) { +		dev_err(dev, "failed to alloc memory for group name\n"); +		goto free_map; +	} +	sprintf(gname, "%s%s", np->name, GROUP_SUFFIX); + +	/* +	 * don't have config options? then skip over to creating function +	 * map entries. +	 */ +	if (!cfg_cnt) +		goto skip_cfgs; + +	/* Allocate memory for config entries */ +	cfg = kzalloc(sizeof(*cfg) * cfg_cnt, GFP_KERNEL); +	if (!cfg) { +		dev_err(dev, "failed to alloc memory for configs\n"); +		goto free_gname; +	} + +	/* Prepare a list of config settings */ +	for (idx = 0, cfg_cnt = 0; idx < ARRAY_SIZE(pcfgs); idx++) { +		u32 value; +		if (!of_property_read_u32(np, pcfgs[idx].prop_cfg, &value)) +			cfg[cfg_cnt++] = +				PINCFG_PACK(pcfgs[idx].cfg_type, value); +	} + +	/* create the config map entry */ +	map[*nmaps].data.configs.group_or_pin = gname; +	map[*nmaps].data.configs.configs = cfg; +	map[*nmaps].data.configs.num_configs = cfg_cnt; +	map[*nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP; +	*nmaps += 1; + +skip_cfgs: +	/* create the function map entry */ +	if (of_find_property(np, "samsung,pin-function", NULL)) { +		fname = kzalloc(strlen(np->name) + FSUFFIX_LEN,	GFP_KERNEL); +		if (!fname) { +			dev_err(dev, "failed to alloc memory for func name\n"); +			goto free_cfg; +		} +		sprintf(fname, "%s%s", np->name, FUNCTION_SUFFIX); + +		map[*nmaps].data.mux.group = gname; +		map[*nmaps].data.mux.function = fname; +		map[*nmaps].type = PIN_MAP_TYPE_MUX_GROUP; +		*nmaps += 1; +	} + +	*maps = map; +	return 0; + +free_cfg: +	kfree(cfg); +free_gname: +	kfree(gname); +free_map: +	kfree(map); +	return -ENOMEM; +} + +/* free the memory allocated to hold the pin-map table */ +static void samsung_dt_free_map(struct pinctrl_dev *pctldev, +			     struct pinctrl_map *map, unsigned num_maps) +{ +	int idx; + +	for (idx = 0; idx < num_maps; idx++) { +		if (map[idx].type == PIN_MAP_TYPE_MUX_GROUP) { +			kfree(map[idx].data.mux.function); +			if (!idx) +				kfree(map[idx].data.mux.group); +		} else if (map->type == PIN_MAP_TYPE_CONFIGS_GROUP) { +			kfree(map[idx].data.configs.configs); +			if (!idx) +				kfree(map[idx].data.configs.group_or_pin); +		} +	}; + +	kfree(map); +} + +/* list of pinctrl callbacks for the pinctrl core */ +static struct pinctrl_ops samsung_pctrl_ops = { +	.get_groups_count	= samsung_get_group_count, +	.get_group_name		= samsung_get_group_name, +	.get_group_pins		= samsung_get_group_pins, +	.dt_node_to_map		= samsung_dt_node_to_map, +	.dt_free_map		= samsung_dt_free_map, +}; + +/* check if the selector is a valid pin function selector */ +static int samsung_get_functions_count(struct pinctrl_dev *pctldev) +{ +	struct samsung_pinctrl_drv_data *drvdata; + +	drvdata = pinctrl_dev_get_drvdata(pctldev); +	return drvdata->nr_functions; +} + +/* return the name of the pin function specified */ +static const char *samsung_pinmux_get_fname(struct pinctrl_dev *pctldev, +						unsigned selector) +{ +	struct samsung_pinctrl_drv_data *drvdata; + +	drvdata = pinctrl_dev_get_drvdata(pctldev); +	return drvdata->pmx_functions[selector].name; +} + +/* return the groups associated for the specified function selector */ +static int samsung_pinmux_get_groups(struct pinctrl_dev *pctldev, +		unsigned selector, const char * const **groups, +		unsigned * const num_groups) +{ +	struct samsung_pinctrl_drv_data *drvdata; + +	drvdata = pinctrl_dev_get_drvdata(pctldev); +	*groups = drvdata->pmx_functions[selector].groups; +	*num_groups = drvdata->pmx_functions[selector].num_groups; +	return 0; +} + +/* + * given a pin number that is local to a pin controller, find out the pin bank + * and the register base of the pin bank. + */ +static void pin_to_reg_bank(struct gpio_chip *gc, unsigned pin, +			void __iomem **reg, u32 *offset, +			struct samsung_pin_bank **bank) +{ +	struct samsung_pinctrl_drv_data *drvdata; +	struct samsung_pin_bank *b; + +	drvdata = dev_get_drvdata(gc->dev); +	b = drvdata->ctrl->pin_banks; + +	while ((pin >= b->pin_base) && +			((b->pin_base + b->nr_pins - 1) < pin)) +		b++; + +	*reg = drvdata->virt_base + b->pctl_offset; +	*offset = pin - b->pin_base; +	if (bank) +		*bank = b; + +	/* some banks have two config registers in a single bank */ +	if (*offset * b->func_width > BITS_PER_LONG) +		*reg += 4; +} + +/* enable or disable a pinmux function */ +static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, +					unsigned group, bool enable) +{ +	struct samsung_pinctrl_drv_data *drvdata; +	const unsigned int *pins; +	struct samsung_pin_bank *bank; +	void __iomem *reg; +	u32 mask, shift, data, pin_offset, cnt; + +	drvdata = pinctrl_dev_get_drvdata(pctldev); +	pins = drvdata->pin_groups[group].pins; + +	/* +	 * for each pin in the pin group selected, program the correspoding pin +	 * pin function number in the config register. +	 */ +	for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) { +		pin_to_reg_bank(drvdata->gc, pins[cnt] - drvdata->ctrl->base, +				®, &pin_offset, &bank); +		mask = (1 << bank->func_width) - 1; +		shift = pin_offset * bank->func_width; + +		data = readl(reg); +		data &= ~(mask << shift); +		if (enable) +			data |= drvdata->pin_groups[group].func << shift; +		writel(data, reg); +	} +} + +/* enable a specified pinmux by writing to registers */ +static int samsung_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector, +					unsigned group) +{ +	samsung_pinmux_setup(pctldev, selector, group, true); +	return 0; +} + +/* disable a specified pinmux by writing to registers */ +static void samsung_pinmux_disable(struct pinctrl_dev *pctldev, +					unsigned selector, unsigned group) +{ +	samsung_pinmux_setup(pctldev, selector, group, false); +} + +/* + * The calls to gpio_direction_output() and gpio_direction_input() + * leads to this function call (via the pinctrl_gpio_direction_{input|output}() + * function called from the gpiolib interface). + */ +static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, +		struct pinctrl_gpio_range *range, unsigned offset, bool input) +{ +	struct samsung_pin_bank *bank; +	void __iomem *reg; +	u32 data, pin_offset, mask, shift; + +	pin_to_reg_bank(range->gc, offset, ®, &pin_offset, &bank); +	mask = (1 << bank->func_width) - 1; +	shift = pin_offset * bank->func_width; + +	data = readl(reg); +	data &= ~(mask << shift); +	if (!input) +		data |= FUNC_OUTPUT << shift; +	writel(data, reg); +	return 0; +} + +/* list of pinmux callbacks for the pinmux vertical in pinctrl core */ +static struct pinmux_ops samsung_pinmux_ops = { +	.get_functions_count	= samsung_get_functions_count, +	.get_function_name	= samsung_pinmux_get_fname, +	.get_function_groups	= samsung_pinmux_get_groups, +	.enable			= samsung_pinmux_enable, +	.disable		= samsung_pinmux_disable, +	.gpio_set_direction	= samsung_pinmux_gpio_set_direction, +}; + +/* set or get the pin config settings for a specified pin */ +static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, +				unsigned long *config, bool set) +{ +	struct samsung_pinctrl_drv_data *drvdata; +	struct samsung_pin_bank *bank; +	void __iomem *reg_base; +	enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(*config); +	u32 data, width, pin_offset, mask, shift; +	u32 cfg_value, cfg_reg; + +	drvdata = pinctrl_dev_get_drvdata(pctldev); +	pin_to_reg_bank(drvdata->gc, pin - drvdata->ctrl->base, ®_base, +					&pin_offset, &bank); + +	switch (cfg_type) { +	case PINCFG_TYPE_PUD: +		width = bank->pud_width; +		cfg_reg = PUD_REG; +		break; +	case PINCFG_TYPE_DRV: +		width = bank->drv_width; +		cfg_reg = DRV_REG; +		break; +	case PINCFG_TYPE_CON_PDN: +		width = bank->conpdn_width; +		cfg_reg = CONPDN_REG; +		break; +	case PINCFG_TYPE_PUD_PDN: +		width = bank->pudpdn_width; +		cfg_reg = PUDPDN_REG; +		break; +	default: +		WARN_ON(1); +		return -EINVAL; +	} + +	mask = (1 << width) - 1; +	shift = pin_offset * width; +	data = readl(reg_base + cfg_reg); + +	if (set) { +		cfg_value = PINCFG_UNPACK_VALUE(*config); +		data &= ~(mask << shift); +		data |= (cfg_value << shift); +		writel(data, reg_base + cfg_reg); +	} else { +		data >>= shift; +		data &= mask; +		*config = PINCFG_PACK(cfg_type, data); +	} +	return 0; +} + +/* set the pin config settings for a specified pin */ +static int samsung_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, +				unsigned long config) +{ +	return samsung_pinconf_rw(pctldev, pin, &config, true); +} + +/* get the pin config settings for a specified pin */ +static int samsung_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, +					unsigned long *config) +{ +	return samsung_pinconf_rw(pctldev, pin, config, false); +} + +/* set the pin config settings for a specified pin group */ +static int samsung_pinconf_group_set(struct pinctrl_dev *pctldev, +			unsigned group, unsigned long config) +{ +	struct samsung_pinctrl_drv_data *drvdata; +	const unsigned int *pins; +	unsigned int cnt; + +	drvdata = pinctrl_dev_get_drvdata(pctldev); +	pins = drvdata->pin_groups[group].pins; + +	for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) +		samsung_pinconf_set(pctldev, pins[cnt], config); + +	return 0; +} + +/* get the pin config settings for a specified pin group */ +static int samsung_pinconf_group_get(struct pinctrl_dev *pctldev, +				unsigned int group, unsigned long *config) +{ +	struct samsung_pinctrl_drv_data *drvdata; +	const unsigned int *pins; + +	drvdata = pinctrl_dev_get_drvdata(pctldev); +	pins = drvdata->pin_groups[group].pins; +	samsung_pinconf_get(pctldev, pins[0], config); +	return 0; +} + +/* list of pinconfig callbacks for pinconfig vertical in the pinctrl code */ +static struct pinconf_ops samsung_pinconf_ops = { +	.pin_config_get		= samsung_pinconf_get, +	.pin_config_set		= samsung_pinconf_set, +	.pin_config_group_get	= samsung_pinconf_group_get, +	.pin_config_group_set	= samsung_pinconf_group_set, +}; + +/* gpiolib gpio_set callback function */ +static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) +{ +	void __iomem *reg; +	u32 pin_offset, data; + +	pin_to_reg_bank(gc, offset, ®, &pin_offset, NULL); +	data = readl(reg + DAT_REG); +	data &= ~(1 << pin_offset); +	if (value) +		data |= 1 << pin_offset; +	writel(data, reg + DAT_REG); +} + +/* gpiolib gpio_get callback function */ +static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset) +{ +	void __iomem *reg; +	u32 pin_offset, data; + +	pin_to_reg_bank(gc, offset, ®, &pin_offset, NULL); +	data = readl(reg + DAT_REG); +	data >>= pin_offset; +	data &= 1; +	return data; +} + +/* + * gpiolib gpio_direction_input callback function. The setting of the pin + * mux function as 'gpio input' will be handled by the pinctrl susbsystem + * interface. + */ +static int samsung_gpio_direction_input(struct gpio_chip *gc, unsigned offset) +{ +	return pinctrl_gpio_direction_input(gc->base + offset); +} + +/* + * gpiolib gpio_direction_output callback function. The setting of the pin + * mux function as 'gpio output' will be handled by the pinctrl susbsystem + * interface. + */ +static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset, +							int value) +{ +	samsung_gpio_set(gc, offset, value); +	return pinctrl_gpio_direction_output(gc->base + offset); +} + +/* + * Parse the pin names listed in the 'samsung,pins' property and convert it + * into a list of gpio numbers are create a pin group from it. + */ +static int __init samsung_pinctrl_parse_dt_pins(struct platform_device *pdev, +			struct device_node *cfg_np, struct pinctrl_desc *pctl, +			unsigned int **pin_list, unsigned int *npins) +{ +	struct device *dev = &pdev->dev; +	struct property *prop; +	struct pinctrl_pin_desc const *pdesc = pctl->pins; +	unsigned int idx = 0, cnt; +	const char *pin_name; + +	*npins = of_property_count_strings(cfg_np, "samsung,pins"); +	if (*npins < 0) { +		dev_err(dev, "invalid pin list in %s node", cfg_np->name); +		return -EINVAL; +	} + +	*pin_list = devm_kzalloc(dev, *npins * sizeof(**pin_list), GFP_KERNEL); +	if (!*pin_list) { +		dev_err(dev, "failed to allocate memory for pin list\n"); +		return -ENOMEM; +	} + +	of_property_for_each_string(cfg_np, "samsung,pins", prop, pin_name) { +		for (cnt = 0; cnt < pctl->npins; cnt++) { +			if (pdesc[cnt].name) { +				if (!strcmp(pin_name, pdesc[cnt].name)) { +					(*pin_list)[idx++] = pdesc[cnt].number; +					break; +				} +			} +		} +		if (cnt == pctl->npins) { +			dev_err(dev, "pin %s not valid in %s node\n", +					pin_name, cfg_np->name); +			devm_kfree(dev, *pin_list); +			return -EINVAL; +		} +	} + +	return 0; +} + +/* + * Parse the information about all the available pin groups and pin functions + * from device node of the pin-controller. A pin group is formed with all + * the pins listed in the "samsung,pins" property. + */ +static int __init samsung_pinctrl_parse_dt(struct platform_device *pdev, +				struct samsung_pinctrl_drv_data *drvdata) +{ +	struct device *dev = &pdev->dev; +	struct device_node *dev_np = dev->of_node; +	struct device_node *cfg_np; +	struct samsung_pin_group *groups, *grp; +	struct samsung_pmx_func *functions, *func; +	unsigned *pin_list; +	unsigned int npins, grp_cnt, func_idx = 0; +	char *gname, *fname; +	int ret; + +	grp_cnt = of_get_child_count(dev_np); +	if (!grp_cnt) +		return -EINVAL; + +	groups = devm_kzalloc(dev, grp_cnt * sizeof(*groups), GFP_KERNEL); +	if (!groups) { +		dev_err(dev, "failed allocate memory for ping group list\n"); +		return -EINVAL; +	} +	grp = groups; + +	functions = devm_kzalloc(dev, grp_cnt * sizeof(*functions), GFP_KERNEL); +	if (!functions) { +		dev_err(dev, "failed to allocate memory for function list\n"); +		return -EINVAL; +	} +	func = functions; + +	/* +	 * Iterate over all the child nodes of the pin controller node +	 * and create pin groups and pin function lists. +	 */ +	for_each_child_of_node(dev_np, cfg_np) { +		u32 function; +		if (of_find_property(cfg_np, "interrupt-controller", NULL)) +			continue; + +		ret = samsung_pinctrl_parse_dt_pins(pdev, cfg_np, +					&drvdata->pctl,	&pin_list, &npins); +		if (ret) +			return ret; + +		/* derive pin group name from the node name */ +		gname = devm_kzalloc(dev, strlen(cfg_np->name) + GSUFFIX_LEN, +					GFP_KERNEL); +		if (!gname) { +			dev_err(dev, "failed to alloc memory for group name\n"); +			return -ENOMEM; +		} +		sprintf(gname, "%s%s", cfg_np->name, GROUP_SUFFIX); + +		grp->name = gname; +		grp->pins = pin_list; +		grp->num_pins = npins; +		of_property_read_u32(cfg_np, "samsung,pin-function", &function); +		grp->func = function; +		grp++; + +		if (!of_find_property(cfg_np, "samsung,pin-function", NULL)) +			continue; + +		/* derive function name from the node name */ +		fname = devm_kzalloc(dev, strlen(cfg_np->name) + FSUFFIX_LEN, +					GFP_KERNEL); +		if (!fname) { +			dev_err(dev, "failed to alloc memory for func name\n"); +			return -ENOMEM; +		} +		sprintf(fname, "%s%s", cfg_np->name, FUNCTION_SUFFIX); + +		func->name = fname; +		func->groups = devm_kzalloc(dev, sizeof(char *), GFP_KERNEL); +		if (!func->groups) { +			dev_err(dev, "failed to alloc memory for group list " +					"in pin function"); +			return -ENOMEM; +		} +		func->groups[0] = gname; +		func->num_groups = 1; +		func++; +		func_idx++; +	} + +	drvdata->pin_groups = groups; +	drvdata->nr_groups = grp_cnt; +	drvdata->pmx_functions = functions; +	drvdata->nr_functions = func_idx; + +	return 0; +} + +/* register the pinctrl interface with the pinctrl subsystem */ +static int __init samsung_pinctrl_register(struct platform_device *pdev, +				struct samsung_pinctrl_drv_data *drvdata) +{ +	struct pinctrl_desc *ctrldesc = &drvdata->pctl; +	struct pinctrl_pin_desc *pindesc, *pdesc; +	struct samsung_pin_bank *pin_bank; +	char *pin_names; +	int pin, bank, ret; + +	ctrldesc->name = "samsung-pinctrl"; +	ctrldesc->owner = THIS_MODULE; +	ctrldesc->pctlops = &samsung_pctrl_ops; +	ctrldesc->pmxops = &samsung_pinmux_ops; +	ctrldesc->confops = &samsung_pinconf_ops; + +	pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) * +			drvdata->ctrl->nr_pins, GFP_KERNEL); +	if (!pindesc) { +		dev_err(&pdev->dev, "mem alloc for pin descriptors failed\n"); +		return -ENOMEM; +	} +	ctrldesc->pins = pindesc; +	ctrldesc->npins = drvdata->ctrl->nr_pins; +	ctrldesc->npins = drvdata->ctrl->nr_pins; + +	/* dynamically populate the pin number and pin name for pindesc */ +	for (pin = 0, pdesc = pindesc; pin < ctrldesc->npins; pin++, pdesc++) +		pdesc->number = pin + drvdata->ctrl->base; + +	/* +	 * allocate space for storing the dynamically generated names for all +	 * the pins which belong to this pin-controller. +	 */ +	pin_names = devm_kzalloc(&pdev->dev, sizeof(char) * PIN_NAME_LENGTH * +					drvdata->ctrl->nr_pins, GFP_KERNEL); +	if (!pin_names) { +		dev_err(&pdev->dev, "mem alloc for pin names failed\n"); +		return -ENOMEM; +	} + +	/* for each pin, the name of the pin is pin-bank name + pin number */ +	for (bank = 0; bank < drvdata->ctrl->nr_banks; bank++) { +		pin_bank = &drvdata->ctrl->pin_banks[bank]; +		for (pin = 0; pin < pin_bank->nr_pins; pin++) { +			sprintf(pin_names, "%s-%d", pin_bank->name, pin); +			pdesc = pindesc + pin_bank->pin_base + pin; +			pdesc->name = pin_names; +			pin_names += PIN_NAME_LENGTH; +		} +	} + +	drvdata->pctl_dev = pinctrl_register(ctrldesc, &pdev->dev, drvdata); +	if (!drvdata->pctl_dev) { +		dev_err(&pdev->dev, "could not register pinctrl driver\n"); +		return -EINVAL; +	} + +	drvdata->grange.name = "samsung-pctrl-gpio-range"; +	drvdata->grange.id = 0; +	drvdata->grange.base = drvdata->ctrl->base; +	drvdata->grange.npins = drvdata->ctrl->nr_pins; +	drvdata->grange.gc = drvdata->gc; +	pinctrl_add_gpio_range(drvdata->pctl_dev, &drvdata->grange); + +	ret = samsung_pinctrl_parse_dt(pdev, drvdata); +	if (ret) { +		pinctrl_unregister(drvdata->pctl_dev); +		return ret; +	} + +	return 0; +} + +/* register the gpiolib interface with the gpiolib subsystem */ +static int __init samsung_gpiolib_register(struct platform_device *pdev, +				struct samsung_pinctrl_drv_data *drvdata) +{ +	struct gpio_chip *gc; +	int ret; + +	gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL); +	if (!gc) { +		dev_err(&pdev->dev, "mem alloc for gpio_chip failed\n"); +		return -ENOMEM; +	} + +	drvdata->gc = gc; +	gc->base = drvdata->ctrl->base; +	gc->ngpio = drvdata->ctrl->nr_pins; +	gc->dev = &pdev->dev; +	gc->set = samsung_gpio_set; +	gc->get = samsung_gpio_get; +	gc->direction_input = samsung_gpio_direction_input; +	gc->direction_output = samsung_gpio_direction_output; +	gc->label = drvdata->ctrl->label; +	gc->owner = THIS_MODULE; +	ret = gpiochip_add(gc); +	if (ret) { +		dev_err(&pdev->dev, "failed to register gpio_chip %s, error " +					"code: %d\n", gc->label, ret); +		return ret; +	} + +	return 0; +} + +/* unregister the gpiolib interface with the gpiolib subsystem */ +static int __init samsung_gpiolib_unregister(struct platform_device *pdev, +				struct samsung_pinctrl_drv_data *drvdata) +{ +	int ret = gpiochip_remove(drvdata->gc); +	if (ret) { +		dev_err(&pdev->dev, "gpio chip remove failed\n"); +		return ret; +	} +	return 0; +} + +static const struct of_device_id samsung_pinctrl_dt_match[]; + +/* retrieve the soc specific data */ +static 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 00000000000..b8956934cda --- /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 3aade1d8f41..c6f8dad2ceb 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 */  |