diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-27 23:41:24 (GMT) |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-27 23:41:24 (GMT) |
commit | 34800598b2eebe061445216473b1e4c2ff5cba99 (patch) | |
tree | a6d0eb6fe45d9480888d7ddb34840e172ed80e56 | |
parent | 46b407ca4a6149c8d27fcec1881d4f184bec7c77 (diff) | |
parent | 511f1cb6d426938fabf9c6d69ce4861b66ffd919 (diff) | |
download | linux-34800598b2eebe061445216473b1e4c2ff5cba99.tar.xz |
Merge tag 'drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull "ARM: driver specific updates" from Arnd Bergmann:
"These are all specific to some driver. They are typically the
platform side of a change in the drivers directory, such as adding a
new driver or extending the interface to the platform. In cases where
there is no maintainer for the driver, or the maintainer prefers to
have the platform changes in the same branch as the driver changes,
the patches to the drivers are included as well.
A much smaller set of driver updates that depend on other branches
getting merged first will be sent later.
The new export of tegra_chip_uid conflicts with other changes in
fuse.c. In rtc-sa1100.c, the global removal of IRQF_DISABLED
conflicts with the cleanup of the interrupt handling of that driver.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>"
Fixed up aforementioned trivial conflicts.
* tag 'drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (94 commits)
ARM: SAMSUNG: change the name from s3c-sdhci to exynos4-sdhci
mmc: sdhci-s3c: add platform data for the second capability
ARM: SAMSUNG: support the second capability for samsung-soc
ARM: EXYNOS: add support DMA for EXYNOS4X12 SoC
ARM: EXYNOS: Add apb_pclk clkdev entry for mdma1
ARM: EXYNOS: Enable MDMA driver
regulator: Remove bq24022 regulator driver
rtc: sa1100: add OF support
pxa: magician/hx4700: Convert to gpio-regulator from bq24022
ARM: OMAP3+: SmartReflex: fix error handling
ARM: OMAP3+: SmartReflex: fix the use of debugfs_create_* API
ARM: OMAP3+: SmartReflex: micro-optimization for sanity check
ARM: OMAP3+: SmartReflex: misc cleanups
ARM: OMAP3+: SmartReflex: move late_initcall() closer to its argument
ARM: OMAP3+: SmartReflex: add missing platform_set_drvdata()
ARM: OMAP3+: hwmod: add SmartReflex IRQs
ARM: OMAP3+: SmartReflex: clear ERRCONFIG_VPBOUNDINTST only on a need
ARM: OMAP3+: SmartReflex: Fix status masking in ERRCONFIG register
ARM: OMAP3+: SmartReflex: Add a shutdown hook
ARM: OMAP3+: SmartReflex Class3: disable errorgen before disable VP
...
Conflicts:
arch/arm/mach-tegra/Makefile
arch/arm/mach-tegra/fuse.c
drivers/rtc/rtc-sa1100.c
118 files changed, 3077 insertions, 732 deletions
diff --git a/Documentation/devicetree/bindings/arm/tegra/emc.txt b/Documentation/devicetree/bindings/arm/tegra/emc.txt new file mode 100644 index 0000000..09335f8 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/tegra/emc.txt @@ -0,0 +1,100 @@ +Embedded Memory Controller + +Properties: +- name : Should be emc +- #address-cells : Should be 1 +- #size-cells : Should be 0 +- compatible : Should contain "nvidia,tegra20-emc". +- reg : Offset and length of the register set for the device +- nvidia,use-ram-code : If present, the sub-nodes will be addressed + and chosen using the ramcode board selector. If omitted, only one + set of tables can be present and said tables will be used + irrespective of ram-code configuration. + +Child device nodes describe the memory settings for different configurations and clock rates. + +Example: + + emc@7000f400 { + #address-cells = < 1 >; + #size-cells = < 0 >; + compatible = "nvidia,tegra20-emc"; + reg = <0x7000f4000 0x200>; + } + + +Embedded Memory Controller ram-code table + +If the emc node has the nvidia,use-ram-code property present, then the +next level of nodes below the emc table are used to specify which settings +apply for which ram-code settings. + +If the emc node lacks the nvidia,use-ram-code property, this level is omitted +and the tables are stored directly under the emc node (see below). + +Properties: + +- name : Should be emc-tables +- nvidia,ram-code : the binary representation of the ram-code board strappings + for which this node (and children) are valid. + + + +Embedded Memory Controller configuration table + +This is a table containing the EMC register settings for the various +operating speeds of the memory controller. They are always located as +subnodes of the emc controller node. + +There are two ways of specifying which tables to use: + +* The simplest is if there is just one set of tables in the device tree, + and they will always be used (based on which frequency is used). + This is the preferred method, especially when firmware can fill in + this information based on the specific system information and just + pass it on to the kernel. + +* The slightly more complex one is when more than one memory configuration + might exist on the system. The Tegra20 platform handles this during + early boot by selecting one out of possible 4 memory settings based + on a 2-pin "ram code" bootstrap setting on the board. The values of + these strappings can be read through a register in the SoC, and thus + used to select which tables to use. + +Properties: +- name : Should be emc-table +- compatible : Should contain "nvidia,tegra20-emc-table". +- reg : either an opaque enumerator to tell different tables apart, or + the valid frequency for which the table should be used (in kHz). +- clock-frequency : the clock frequency for the EMC at which this + table should be used (in kHz). +- nvidia,emc-registers : a 46 word array of EMC registers to be programmed + for operation at the 'clock-frequency' setting. + The order and contents of the registers are: + RC, RFC, RAS, RP, R2W, W2R, R2P, W2P, RD_RCD, WR_RCD, RRD, REXT, + WDV, QUSE, QRST, QSAFE, RDV, REFRESH, BURST_REFRESH_NUM, PDEX2WR, + PDEX2RD, PCHG2PDEN, ACT2PDEN, AR2PDEN, RW2PDEN, TXSR, TCKE, TFAW, + TRPAB, TCLKSTABLE, TCLKSTOP, TREFBW, QUSE_EXTRA, FBIO_CFG6, ODT_WRITE, + ODT_READ, FBIO_CFG5, CFG_DIG_DLL, DLL_XFORM_DQS, DLL_XFORM_QUSE, + ZCAL_REF_CNT, ZCAL_WAIT_CNT, AUTO_CAL_INTERVAL, CFG_CLKTRIM_0, + CFG_CLKTRIM_1, CFG_CLKTRIM_2 + + emc-table@166000 { + reg = <166000>; + compatible = "nvidia,tegra20-emc-table"; + clock-frequency = < 166000 >; + nvidia,emc-registers = < 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 >; + }; + + emc-table@333000 { + reg = <333000>; + compatible = "nvidia,tegra20-emc-table"; + clock-frequency = < 333000 >; + nvidia,emc-registers = < 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 >; + }; diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt new file mode 100644 index 0000000..b5846e2 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt @@ -0,0 +1,19 @@ +NVIDIA Tegra Power Management Controller (PMC) + +Properties: +- name : Should be pmc +- compatible : Should contain "nvidia,tegra<chip>-pmc". +- reg : Offset and length of the register set for the device +- nvidia,invert-interrupt : If present, inverts the PMU interrupt signal. + The PMU is an external Power Management Unit, whose interrupt output + signal is fed into the PMC. This signal is optionally inverted, and then + fed into the ARM GIC. The PMC is not involved in the detection or + handling of this interrupt signal, merely its inversion. + +Example: + +pmc@7000f400 { + compatible = "nvidia,tegra20-pmc"; + reg = <0x7000e400 0x400>; + nvidia,invert-interrupt; +}; diff --git a/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt b/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt new file mode 100644 index 0000000..90fa7da --- /dev/null +++ b/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt @@ -0,0 +1,30 @@ +* NVIDIA Tegra APB DMA controller + +Required properties: +- compatible: Should be "nvidia,<chip>-apbdma" +- reg: Should contain DMA registers location and length. This shuld include + all of the per-channel registers. +- interrupts: Should contain all of the per-channel DMA interrupts. + +Examples: + +apbdma: dma@6000a000 { + compatible = "nvidia,tegra20-apbdma"; + reg = <0x6000a000 0x1200>; + interrupts = < 0 136 0x04 + 0 137 0x04 + 0 138 0x04 + 0 139 0x04 + 0 140 0x04 + 0 141 0x04 + 0 142 0x04 + 0 143 0x04 + 0 144 0x04 + 0 145 0x04 + 0 146 0x04 + 0 147 0x04 + 0 148 0x04 + 0 149 0x04 + 0 150 0x04 + 0 151 0x04 >; +}; diff --git a/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt b/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt index eb4b530..023c952 100644 --- a/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt +++ b/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt @@ -1,8 +1,40 @@ -NVIDIA Tegra 2 GPIO controller +NVIDIA Tegra GPIO controller Required properties: -- compatible : "nvidia,tegra20-gpio" +- compatible : "nvidia,tegra<chip>-gpio" +- reg : Physical base address and length of the controller's registers. +- interrupts : The interrupt outputs from the controller. For Tegra20, + there should be 7 interrupts specified, and for Tegra30, there should + be 8 interrupts specified. - #gpio-cells : Should be two. The first cell is the pin number and the second cell is used to specify optional parameters: - bit 0 specifies polarity (0 for normal, 1 for inverted) - gpio-controller : Marks the device node as a GPIO controller. +- #interrupt-cells : Should be 2. + The first cell is the GPIO number. + The second cell is used to specify flags: + bits[3:0] trigger type and level flags: + 1 = low-to-high edge triggered. + 2 = high-to-low edge triggered. + 4 = active high level-sensitive. + 8 = active low level-sensitive. + Valid combinations are 1, 2, 3, 4, 8. +- interrupt-controller : Marks the device node as an interrupt controller. + +Example: + +gpio: gpio@6000d000 { + compatible = "nvidia,tegra20-gpio"; + reg = < 0x6000d000 0x1000 >; + interrupts = < 0 32 0x04 + 0 33 0x04 + 0 34 0x04 + 0 35 0x04 + 0 55 0x04 + 0 87 0x04 + 0 89 0x04 >; + #gpio-cells = <2>; + gpio-controller; + #interrupt-cells = <2>; + interrupt-controller; +}; diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index c941fd0..8ef416a 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -760,7 +760,7 @@ config ARCH_SA1100 select ARCH_HAS_CPUFREQ select CPU_FREQ select GENERIC_CLOCKEVENTS - select HAVE_CLK + select CLKDEV_LOOKUP select HAVE_SCHED_CLOCK select TICK_ONESHOT select ARCH_REQUIRE_GPIOLIB diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index b895a2a..66ca801 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -180,12 +180,12 @@ choice Say Y here if you want kernel low-level debugging support on i.MX50 or i.MX53. - config DEBUG_IMX6Q_UART - bool "i.MX6Q Debug UART" + config DEBUG_IMX6Q_UART4 + bool "i.MX6Q Debug UART4" depends on SOC_IMX6Q help Say Y here if you want kernel low-level debugging support - on i.MX6Q. + on i.MX6Q UART4. config DEBUG_MSM_UART1 bool "Kernel low-level debugging messages via MSM UART1" diff --git a/arch/arm/boot/dts/tegra-harmony.dts b/arch/arm/boot/dts/tegra-harmony.dts index 80afa1b..6e8447d 100644 --- a/arch/arm/boot/dts/tegra-harmony.dts +++ b/arch/arm/boot/dts/tegra-harmony.dts @@ -10,19 +10,25 @@ reg = < 0x00000000 0x40000000 >; }; + pmc@7000f400 { + nvidia,invert-interrupt; + }; + i2c@7000c000 { clock-frequency = <400000>; - codec: wm8903@1a { + wm8903: wm8903@1a { compatible = "wlf,wm8903"; reg = <0x1a>; - interrupts = < 347 >; + interrupt-parent = <&gpio>; + interrupts = < 187 0x04 >; gpio-controller; #gpio-cells = <2>; - /* 0x8000 = Not configured */ - gpio-cfg = < 0x8000 0x8000 0 0x8000 0x8000 >; + micdet-cfg = <0>; + micdet-delay = <100>; + gpio-cfg = < 0xffffffff 0xffffffff 0 0xffffffff 0xffffffff >; }; }; @@ -38,13 +44,32 @@ clock-frequency = <400000>; }; - sound { - compatible = "nvidia,harmony-sound", "nvidia,tegra-wm8903"; + i2s@70002a00 { + status = "disable"; + }; - spkr-en-gpios = <&codec 2 0>; - hp-det-gpios = <&gpio 178 0>; - int-mic-en-gpios = <&gpio 184 0>; - ext-mic-en-gpios = <&gpio 185 0>; + sound { + compatible = "nvidia,tegra-audio-wm8903-harmony", + "nvidia,tegra-audio-wm8903"; + nvidia,model = "NVIDIA Tegra Harmony"; + + nvidia,audio-routing = + "Headphone Jack", "HPOUTR", + "Headphone Jack", "HPOUTL", + "Int Spk", "ROP", + "Int Spk", "RON", + "Int Spk", "LOP", + "Int Spk", "LON", + "Mic Jack", "MICBIAS", + "IN1L", "Mic Jack"; + + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,audio-codec = <&wm8903>; + + nvidia,spkr-en-gpios = <&wm8903 2 0>; + nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */ + nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */ + nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */ }; serial@70006000 { diff --git a/arch/arm/boot/dts/tegra-paz00.dts b/arch/arm/boot/dts/tegra-paz00.dts index 61f3858..fc97254 100644 --- a/arch/arm/boot/dts/tegra-paz00.dts +++ b/arch/arm/boot/dts/tegra-paz00.dts @@ -12,6 +12,13 @@ i2c@7000c000 { clock-frequency = <400000>; + + alc5632: alc5632@1e { + compatible = "realtek,alc5632"; + reg = <0x1e>; + gpio-controller; + #gpio-cells = <2>; + }; }; i2c@7000c400 { @@ -42,6 +49,29 @@ }; }; + i2s@70002a00 { + status = "disable"; + }; + + sound { + compatible = "nvidia,tegra-audio-alc5632-paz00", + "nvidia,tegra-audio-alc5632"; + + nvidia,model = "Compal PAZ00"; + + nvidia,audio-routing = + "Int Spk", "SPKOUT", + "Int Spk", "SPKOUTN", + "Headset Mic", "MICBIAS1", + "MIC1", "Headset Mic", + "Headset Stereophone", "HPR", + "Headset Stereophone", "HPL"; + + nvidia,audio-codec = <&alc5632>; + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */ + }; + serial@70006000 { clock-frequency = <216000000>; }; diff --git a/arch/arm/boot/dts/tegra-seaboard.dts b/arch/arm/boot/dts/tegra-seaboard.dts index b55a02e..876d5c9 100644 --- a/arch/arm/boot/dts/tegra-seaboard.dts +++ b/arch/arm/boot/dts/tegra-seaboard.dts @@ -13,6 +13,20 @@ i2c@7000c000 { clock-frequency = <400000>; + + wm8903: wm8903@1a { + compatible = "wlf,wm8903"; + reg = <0x1a>; + interrupt-parent = <&gpio>; + interrupts = < 187 0x04 >; + + gpio-controller; + #gpio-cells = <2>; + + micdet-cfg = <0>; + micdet-delay = <100>; + gpio-cfg = < 0xffffffff 0xffffffff 0 0xffffffff 0xffffffff >; + }; }; i2c@7000c400 { @@ -32,6 +46,32 @@ }; }; + i2s@70002a00 { + status = "disable"; + }; + + sound { + compatible = "nvidia,tegra-audio-wm8903-seaboard", + "nvidia,tegra-audio-wm8903"; + nvidia,model = "NVIDIA Tegra Seaboard"; + + nvidia,audio-routing = + "Headphone Jack", "HPOUTR", + "Headphone Jack", "HPOUTL", + "Int Spk", "ROP", + "Int Spk", "RON", + "Int Spk", "LOP", + "Int Spk", "LON", + "Mic Jack", "MICBIAS", + "IN1R", "Mic Jack"; + + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,audio-codec = <&wm8903>; + + nvidia,spkr-en-gpios = <&wm8903 2 0>; + nvidia,hp-det-gpios = <&gpio 185 0>; /* gpio PX1 */ + }; + serial@70006000 { status = "disable"; }; @@ -93,4 +133,42 @@ gpio-key,wakeup; }; }; + + emc@7000f400 { + emc-table@190000 { + reg = < 190000 >; + compatible = "nvidia,tegra20-emc-table"; + clock-frequency = < 190000 >; + nvidia,emc-registers = < 0x0000000c 0x00000026 + 0x00000009 0x00000003 0x00000004 0x00000004 + 0x00000002 0x0000000c 0x00000003 0x00000003 + 0x00000002 0x00000001 0x00000004 0x00000005 + 0x00000004 0x00000009 0x0000000d 0x0000059f + 0x00000000 0x00000003 0x00000003 0x00000003 + 0x00000003 0x00000001 0x0000000b 0x000000c8 + 0x00000003 0x00000007 0x00000004 0x0000000f + 0x00000002 0x00000000 0x00000000 0x00000002 + 0x00000000 0x00000000 0x00000083 0xa06204ae + 0x007dc010 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 >; + }; + + emc-table@380000 { + reg = < 380000 >; + compatible = "nvidia,tegra20-emc-table"; + clock-frequency = < 380000 >; + nvidia,emc-registers = < 0x00000017 0x0000004b + 0x00000012 0x00000006 0x00000004 0x00000005 + 0x00000003 0x0000000c 0x00000006 0x00000006 + 0x00000003 0x00000001 0x00000004 0x00000005 + 0x00000004 0x00000009 0x0000000d 0x00000b5f + 0x00000000 0x00000003 0x00000003 0x00000006 + 0x00000006 0x00000001 0x00000011 0x000000c8 + 0x00000003 0x0000000e 0x00000007 0x0000000f + 0x00000002 0x00000000 0x00000000 0x00000002 + 0x00000000 0x00000000 0x00000083 0xe044048b + 0x007d8010 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 >; + }; + }; }; diff --git a/arch/arm/boot/dts/tegra-trimslice.dts b/arch/arm/boot/dts/tegra-trimslice.dts index 3b3ee7d..2524768 100644 --- a/arch/arm/boot/dts/tegra-trimslice.dts +++ b/arch/arm/boot/dts/tegra-trimslice.dts @@ -26,6 +26,18 @@ status = "disable"; }; + i2s@70002800 { + status = "disable"; + }; + + i2s@70002a00 { + status = "disable"; + }; + + das@70000c00 { + status = "disable"; + }; + serial@70006000 { clock-frequency = < 216000000 >; }; diff --git a/arch/arm/boot/dts/tegra-ventana.dts b/arch/arm/boot/dts/tegra-ventana.dts index c7d3b87..2dcff87 100644 --- a/arch/arm/boot/dts/tegra-ventana.dts +++ b/arch/arm/boot/dts/tegra-ventana.dts @@ -12,6 +12,20 @@ i2c@7000c000 { clock-frequency = <400000>; + + wm8903: wm8903@1a { + compatible = "wlf,wm8903"; + reg = <0x1a>; + interrupt-parent = <&gpio>; + interrupts = < 187 0x04 >; + + gpio-controller; + #gpio-cells = <2>; + + micdet-cfg = <0>; + micdet-delay = <100>; + gpio-cfg = < 0xffffffff 0xffffffff 0 0xffffffff 0xffffffff >; + }; }; i2c@7000c400 { @@ -26,6 +40,34 @@ clock-frequency = <400000>; }; + i2s@70002a00 { + status = "disable"; + }; + + sound { + compatible = "nvidia,tegra-audio-wm8903-ventana", + "nvidia,tegra-audio-wm8903"; + nvidia,model = "NVIDIA Tegra Ventana"; + + nvidia,audio-routing = + "Headphone Jack", "HPOUTR", + "Headphone Jack", "HPOUTL", + "Int Spk", "ROP", + "Int Spk", "RON", + "Int Spk", "LOP", + "Int Spk", "LON", + "Mic Jack", "MICBIAS", + "IN1L", "Mic Jack"; + + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,audio-codec = <&wm8903>; + + nvidia,spkr-en-gpios = <&wm8903 2 0>; + nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */ + nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */ + nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */ + }; + serial@70006000 { status = "disable"; }; diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 3da7afd..ec1f010 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -4,6 +4,11 @@ compatible = "nvidia,tegra20"; interrupt-parent = <&intc>; + pmc@7000f400 { + compatible = "nvidia,tegra20-pmc"; + reg = <0x7000e400 0x400>; + }; + intc: interrupt-controller@50041000 { compatible = "arm,cortex-a9-gic"; interrupt-controller; @@ -12,6 +17,27 @@ < 0x50040100 0x0100 >; }; + apbdma: dma@6000a000 { + compatible = "nvidia,tegra20-apbdma"; + reg = <0x6000a000 0x1200>; + interrupts = < 0 104 0x04 + 0 105 0x04 + 0 106 0x04 + 0 107 0x04 + 0 108 0x04 + 0 109 0x04 + 0 110 0x04 + 0 111 0x04 + 0 112 0x04 + 0 113 0x04 + 0 114 0x04 + 0 115 0x04 + 0 116 0x04 + 0 117 0x04 + 0 118 0x04 + 0 119 0x04 >; + }; + i2c@7000c000 { #address-cells = <1>; #size-cells = <0>; @@ -44,18 +70,18 @@ interrupts = < 0 53 0x04 >; }; - i2s@70002800 { + tegra_i2s1: i2s@70002800 { compatible = "nvidia,tegra20-i2s"; reg = <0x70002800 0x200>; interrupts = < 0 13 0x04 >; - dma-channel = < 2 >; + nvidia,dma-request-selector = < &apbdma 2 >; }; - i2s@70002a00 { + tegra_i2s2: i2s@70002a00 { compatible = "nvidia,tegra20-i2s"; reg = <0x70002a00 0x200>; interrupts = < 0 3 0x04 >; - dma-channel = < 1 >; + nvidia,dma-request-selector = < &apbdma 1 >; }; das@70000c00 { @@ -75,6 +101,8 @@ 0 89 0x04 >; #gpio-cells = <2>; gpio-controller; + #interrupt-cells = <2>; + interrupt-controller; }; pinmux: pinmux@70000000 { @@ -120,6 +148,13 @@ interrupts = < 0 91 0x04 >; }; + emc@7000f400 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nvidia,tegra20-emc"; + reg = <0x7000f400 0x200>; + }; + sdhci@c8000000 { compatible = "nvidia,tegra20-sdhci"; reg = <0xc8000000 0x200>; diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index ee7db98..ac4b75c 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -4,6 +4,11 @@ compatible = "nvidia,tegra30"; interrupt-parent = <&intc>; + pmc@7000f400 { + compatible = "nvidia,tegra20-pmc", "nvidia,tegra30-pmc"; + reg = <0x7000e400 0x400>; + }; + intc: interrupt-controller@50041000 { compatible = "arm,cortex-a9-gic"; interrupt-controller; @@ -12,6 +17,43 @@ < 0x50040100 0x0100 >; }; + apbdma: dma@6000a000 { + compatible = "nvidia,tegra30-apbdma", "nvidia,tegra20-apbdma"; + reg = <0x6000a000 0x1400>; + interrupts = < 0 104 0x04 + 0 105 0x04 + 0 106 0x04 + 0 107 0x04 + 0 108 0x04 + 0 109 0x04 + 0 110 0x04 + 0 111 0x04 + 0 112 0x04 + 0 113 0x04 + 0 114 0x04 + 0 115 0x04 + 0 116 0x04 + 0 117 0x04 + 0 118 0x04 + 0 119 0x04 + 0 128 0x04 + 0 129 0x04 + 0 130 0x04 + 0 131 0x04 + 0 132 0x04 + 0 133 0x04 + 0 134 0x04 + 0 135 0x04 + 0 136 0x04 + 0 137 0x04 + 0 138 0x04 + 0 139 0x04 + 0 140 0x04 + 0 141 0x04 + 0 142 0x04 + 0 143 0x04 >; + }; + i2c@7000c000 { #address-cells = <1>; #size-cells = <0>; @@ -55,9 +97,18 @@ gpio: gpio@6000d000 { compatible = "nvidia,tegra30-gpio", "nvidia,tegra20-gpio"; reg = < 0x6000d000 0x1000 >; - interrupts = < 0 32 0x04 0 33 0x04 0 34 0x04 0 35 0x04 0 55 0x04 0 87 0x04 0 89 0x04 >; + interrupts = < 0 32 0x04 + 0 33 0x04 + 0 34 0x04 + 0 35 0x04 + 0 55 0x04 + 0 87 0x04 + 0 89 0x04 + 0 125 0x04 >; #gpio-cells = <2>; gpio-controller; + #interrupt-cells = <2>; + interrupt-controller; }; serial@70006000 { diff --git a/arch/arm/configs/imx_v4_v5_defconfig b/arch/arm/configs/imx_v4_v5_defconfig index d88fb87..b5ac644 100644 --- a/arch/arm/configs/imx_v4_v5_defconfig +++ b/arch/arm/configs/imx_v4_v5_defconfig @@ -45,6 +45,7 @@ CONFIG_FPE_NWFPE=y CONFIG_FPE_NWFPE_XP=y CONFIG_PM_DEBUG=y CONFIG_NET=y +CONFIG_SMSC911X=y CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_INET=y @@ -79,6 +80,8 @@ CONFIG_MISC_DEVICES=y CONFIG_EEPROM_AT24=y CONFIG_EEPROM_AT25=y CONFIG_NETDEVICES=y +CONFIG_CS89x0=y +CONFIG_CS89x0_PLATFORM=y CONFIG_DM9000=y CONFIG_SMC91X=y CONFIG_SMC911X=y @@ -116,6 +119,21 @@ CONFIG_FB_IMX=y CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_LCD_CLASS_DEVICE=y CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_LCD_L4F00242T03=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2_COMMON=y +CONFIG_VIDEO_MEDIA=y +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEOBUF_GEN=y +CONFIG_VIDEOBUF_DMA_CONTIG=y +CONFIG_VIDEOBUF2_CORE=y +CONFIG_VIDEO_CAPTURE_DRIVERS=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_SOC_CAMERA=y +CONFIG_SOC_CAMERA_OV2640=y +CONFIG_VIDEO_MX2_HOSTSUPPORT=y +CONFIG_VIDEO_MX2=y CONFIG_BACKLIGHT_PWM=y CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_FONTS=y diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig index 3cd6069..dc6f641 100644 --- a/arch/arm/configs/imx_v6_v7_defconfig +++ b/arch/arm/configs/imx_v6_v7_defconfig @@ -81,6 +81,8 @@ CONFIG_PATA_IMX=y CONFIG_NETDEVICES=y # CONFIG_NET_VENDOR_BROADCOM is not set # CONFIG_NET_VENDOR_CHELSIO is not set +CONFIG_CS89x0=y +CONFIG_CS89x0_PLATFORM=y # CONFIG_NET_VENDOR_FARADAY is not set # CONFIG_NET_VENDOR_INTEL is not set # CONFIG_NET_VENDOR_MARVELL is not set @@ -125,7 +127,39 @@ CONFIG_IMX2_WDT=y CONFIG_MFD_MC13XXX=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_MC13783=y CONFIG_REGULATOR_MC13892=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2_COMMON=y +CONFIG_VIDEOBUF_GEN=y +CONFIG_VIDEOBUF2_CORE=y +CONFIG_VIDEOBUF2_MEMOPS=y +CONFIG_VIDEOBUF2_DMA_CONTIG=y +CONFIG_VIDEO_CAPTURE_DRIVERS=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_SOC_CAMERA=y +CONFIG_SOC_CAMERA_OV2640=y +CONFIG_MX3_VIDEO=y +CONFIG_VIDEO_MX3=y +CONFIG_FB=y +CONFIG_FB_MX3=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +CONFIG_LCD_L4F00242T03=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_GENERIC=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_MONO=y +CONFIG_LOGO_LINUX_VGA16=y +CONFIG_LOGO_LINUX_CLUT224=y CONFIG_USB=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_MXC=y diff --git a/arch/arm/configs/magician_defconfig b/arch/arm/configs/magician_defconfig index 443675d..a691ef4 100644 --- a/arch/arm/configs/magician_defconfig +++ b/arch/arm/configs/magician_defconfig @@ -101,7 +101,7 @@ CONFIG_MFD_ASIC3=y CONFIG_HTC_EGPIO=y CONFIG_HTC_PASIC3=y CONFIG_REGULATOR=y -CONFIG_REGULATOR_BQ24022=y +CONFIG_REGULATOR_GPIO=y CONFIG_FB=y CONFIG_FB_PXA=y CONFIG_FB_PXA_OVERLAY=y diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c index 366a776..70709ab 100644 --- a/arch/arm/mach-at91/at91sam9263_devices.c +++ b/arch/arm/mach-at91/at91sam9263_devices.c @@ -891,7 +891,8 @@ static struct platform_device at91sam9263_isi_device = { .num_resources = ARRAY_SIZE(isi_resources), }; -void __init at91_add_device_isi(void) +void __init at91_add_device_isi(struct isi_platform_data *data, + bool use_pck_as_mck) { at91_set_A_periph(AT91_PIN_PE0, 0); /* ISI_D0 */ at91_set_A_periph(AT91_PIN_PE1, 0); /* ISI_D1 */ @@ -904,14 +905,20 @@ void __init at91_add_device_isi(void) at91_set_A_periph(AT91_PIN_PE8, 0); /* ISI_PCK */ at91_set_A_periph(AT91_PIN_PE9, 0); /* ISI_HSYNC */ at91_set_A_periph(AT91_PIN_PE10, 0); /* ISI_VSYNC */ - at91_set_B_periph(AT91_PIN_PE11, 0); /* ISI_MCK (PCK3) */ at91_set_B_periph(AT91_PIN_PE12, 0); /* ISI_PD8 */ at91_set_B_periph(AT91_PIN_PE13, 0); /* ISI_PD9 */ at91_set_B_periph(AT91_PIN_PE14, 0); /* ISI_PD10 */ at91_set_B_periph(AT91_PIN_PE15, 0); /* ISI_PD11 */ + + if (use_pck_as_mck) { + at91_set_B_periph(AT91_PIN_PE11, 0); /* ISI_MCK (PCK3) */ + + /* TODO: register the PCK for ISI_MCK and set its parent */ + } } #else -void __init at91_add_device_isi(void) {} +void __init at91_add_device_isi(struct isi_platform_data *data, + bool use_pck_as_mck) {} #endif diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c index 96e2adc..bd4e68c 100644 --- a/arch/arm/mach-at91/at91sam9g45_devices.c +++ b/arch/arm/mach-at91/at91sam9g45_devices.c @@ -14,6 +14,7 @@ #include <linux/dma-mapping.h> #include <linux/gpio.h> +#include <linux/clk.h> #include <linux/platform_device.h> #include <linux/i2c-gpio.h> #include <linux/atmel-mci.h> @@ -28,7 +29,10 @@ #include <mach/at_hdmac.h> #include <mach/atmel-mci.h> +#include <media/atmel-isi.h> + #include "generic.h" +#include "clock.h" /* -------------------------------------------------------------------- @@ -870,6 +874,96 @@ void __init at91_add_device_ac97(struct ac97c_platform_data *data) void __init at91_add_device_ac97(struct ac97c_platform_data *data) {} #endif +/* -------------------------------------------------------------------- + * Image Sensor Interface + * -------------------------------------------------------------------- */ +#if defined(CONFIG_VIDEO_ATMEL_ISI) || defined(CONFIG_VIDEO_ATMEL_ISI_MODULE) +static u64 isi_dmamask = DMA_BIT_MASK(32); +static struct isi_platform_data isi_data; + +struct resource isi_resources[] = { + [0] = { + .start = AT91SAM9G45_BASE_ISI, + .end = AT91SAM9G45_BASE_ISI + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91SAM9G45_ID_ISI, + .end = AT91SAM9G45_ID_ISI, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device at91sam9g45_isi_device = { + .name = "atmel_isi", + .id = 0, + .dev = { + .dma_mask = &isi_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &isi_data, + }, + .resource = isi_resources, + .num_resources = ARRAY_SIZE(isi_resources), +}; + +static struct clk_lookup isi_mck_lookups[] = { + CLKDEV_CON_DEV_ID("isi_mck", "atmel_isi.0", NULL), +}; + +void __init at91_add_device_isi(struct isi_platform_data *data, + bool use_pck_as_mck) +{ + struct clk *pck; + struct clk *parent; + + if (!data) + return; + isi_data = *data; + + at91_set_A_periph(AT91_PIN_PB20, 0); /* ISI_D0 */ + at91_set_A_periph(AT91_PIN_PB21, 0); /* ISI_D1 */ + at91_set_A_periph(AT91_PIN_PB22, 0); /* ISI_D2 */ + at91_set_A_periph(AT91_PIN_PB23, 0); /* ISI_D3 */ + at91_set_A_periph(AT91_PIN_PB24, 0); /* ISI_D4 */ + at91_set_A_periph(AT91_PIN_PB25, 0); /* ISI_D5 */ + at91_set_A_periph(AT91_PIN_PB26, 0); /* ISI_D6 */ + at91_set_A_periph(AT91_PIN_PB27, 0); /* ISI_D7 */ + at91_set_A_periph(AT91_PIN_PB28, 0); /* ISI_PCK */ + at91_set_A_periph(AT91_PIN_PB30, 0); /* ISI_HSYNC */ + at91_set_A_periph(AT91_PIN_PB29, 0); /* ISI_VSYNC */ + at91_set_B_periph(AT91_PIN_PB8, 0); /* ISI_PD8 */ + at91_set_B_periph(AT91_PIN_PB9, 0); /* ISI_PD9 */ + at91_set_B_periph(AT91_PIN_PB10, 0); /* ISI_PD10 */ + at91_set_B_periph(AT91_PIN_PB11, 0); /* ISI_PD11 */ + + platform_device_register(&at91sam9g45_isi_device); + + if (use_pck_as_mck) { + at91_set_B_periph(AT91_PIN_PB31, 0); /* ISI_MCK (PCK1) */ + + pck = clk_get(NULL, "pck1"); + parent = clk_get(NULL, "plla"); + + BUG_ON(IS_ERR(pck) || IS_ERR(parent)); + + if (clk_set_parent(pck, parent)) { + pr_err("Failed to set PCK's parent\n"); + } else { + /* Register PCK as ISI_MCK */ + isi_mck_lookups[0].clk = pck; + clkdev_add_table(isi_mck_lookups, + ARRAY_SIZE(isi_mck_lookups)); + } + + clk_put(pck); + clk_put(parent); + } +} +#else +void __init at91_add_device_isi(struct isi_platform_data *data, + bool use_pck_as_mck) {} +#endif + /* -------------------------------------------------------------------- * LCD Controller diff --git a/arch/arm/mach-at91/board-flexibity.c b/arch/arm/mach-at91/board-flexibity.c index eec02cd..1815152 100644 --- a/arch/arm/mach-at91/board-flexibity.c +++ b/arch/arm/mach-at91/board-flexibity.c @@ -1,7 +1,7 @@ /* * linux/arch/arm/mach-at91/board-flexibity.c * - * Copyright (C) 2010 Flexibity + * Copyright (C) 2010-2011 Flexibity * Copyright (C) 2005 SAN People * Copyright (C) 2006 Atmel * @@ -62,6 +62,13 @@ static struct at91_udc_data __initdata flexibity_udc_data = { .pullup_pin = -EINVAL, /* pull-up driven by UDC */ }; +/* I2C devices */ +static struct i2c_board_info __initdata flexibity_i2c_devices[] = { + { + I2C_BOARD_INFO("ds1307", 0x68), + }, +}; + /* SPI devices */ static struct spi_board_info flexibity_spi_devices[] = { { /* DataFlash chip */ @@ -141,6 +148,9 @@ static void __init flexibity_board_init(void) at91_add_device_usbh(&flexibity_usbh_data); /* USB Device */ at91_add_device_udc(&flexibity_udc_data); + /* I2C */ + at91_add_device_i2c(flexibity_i2c_devices, + ARRAY_SIZE(flexibity_i2c_devices)); /* SPI */ at91_add_device_spi(flexibity_spi_devices, ARRAY_SIZE(flexibity_spi_devices)); diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c index ea0d1b9..57497e2 100644 --- a/arch/arm/mach-at91/board-sam9m10g45ek.c +++ b/arch/arm/mach-at91/board-sam9m10g45ek.c @@ -24,11 +24,13 @@ #include <linux/gpio_keys.h> #include <linux/input.h> #include <linux/leds.h> -#include <linux/clk.h> #include <linux/atmel-mci.h> +#include <linux/delay.h> #include <mach/hardware.h> #include <video/atmel_lcdc.h> +#include <media/soc_camera.h> +#include <media/atmel-isi.h> #include <asm/setup.h> #include <asm/mach-types.h> @@ -185,6 +187,71 @@ static void __init ek_add_device_nand(void) /* + * ISI + */ +static struct isi_platform_data __initdata isi_data = { + .frate = ISI_CFG1_FRATE_CAPTURE_ALL, + /* to use codec and preview path simultaneously */ + .full_mode = 1, + .data_width_flags = ISI_DATAWIDTH_8 | ISI_DATAWIDTH_10, + /* ISI_MCK is provided by programmable clock or external clock */ + .mck_hz = 25000000, +}; + + +/* + * soc-camera OV2640 + */ +#if defined(CONFIG_SOC_CAMERA_OV2640) || \ + defined(CONFIG_SOC_CAMERA_OV2640_MODULE) +static unsigned long isi_camera_query_bus_param(struct soc_camera_link *link) +{ + /* ISI board for ek using default 8-bits connection */ + return SOCAM_DATAWIDTH_8; +} + +static int i2c_camera_power(struct device *dev, int on) +{ + /* enable or disable the camera */ + pr_debug("%s: %s the camera\n", __func__, on ? "ENABLE" : "DISABLE"); + at91_set_gpio_output(AT91_PIN_PD13, !on); + + if (!on) + goto out; + + /* If enabled, give a reset impulse */ + at91_set_gpio_output(AT91_PIN_PD12, 0); + msleep(20); + at91_set_gpio_output(AT91_PIN_PD12, 1); + msleep(100); + +out: + return 0; +} + +static struct i2c_board_info i2c_camera = { + I2C_BOARD_INFO("ov2640", 0x30), +}; + +static struct soc_camera_link iclink_ov2640 = { + .bus_id = 0, + .board_info = &i2c_camera, + .i2c_adapter_id = 0, + .power = i2c_camera_power, + .query_bus_param = isi_camera_query_bus_param, +}; + +static struct platform_device isi_ov2640 = { + .name = "soc-camera-pdrv", + .id = 0, + .dev = { + .platform_data = &iclink_ov2640, + }, +}; +#endif + + +/* * LCD Controller */ #if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE) @@ -377,7 +444,12 @@ static struct gpio_led ek_pwm_led[] = { #endif }; - +static struct platform_device *devices[] __initdata = { +#if defined(CONFIG_SOC_CAMERA_OV2640) || \ + defined(CONFIG_SOC_CAMERA_OV2640_MODULE) + &isi_ov2640, +#endif +}; static void __init ek_board_init(void) { @@ -399,6 +471,8 @@ static void __init ek_board_init(void) ek_add_device_nand(); /* I2C */ at91_add_device_i2c(0, NULL, 0); + /* ISI, using programmable clock as ISI_MCK */ + at91_add_device_isi(&isi_data, true); /* LCD Controller */ at91_add_device_lcdc(&ek_lcdc_data); /* Touch Screen */ @@ -410,6 +484,8 @@ static void __init ek_board_init(void) /* LEDs */ at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds)); at91_pwm_leds(ek_pwm_led, ARRAY_SIZE(ek_pwm_led)); + /* Other platform devices */ + platform_add_devices(devices, ARRAY_SIZE(devices)); } MACHINE_START(AT91SAM9M10G45EK, "Atmel AT91SAM9M10G45-EK") diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h index 3b33f07..dc8d6d4 100644 --- a/arch/arm/mach-at91/include/mach/board.h +++ b/arch/arm/mach-at91/include/mach/board.h @@ -107,6 +107,8 @@ struct atmel_nand_data { u8 ale; /* address line number connected to ALE */ u8 cle; /* address line number connected to CLE */ u8 bus_width_16; /* buswidth is 16 bit */ + u8 correction_cap; /* PMECC correction capability */ + u16 sector_size; /* Sector size for PMECC */ struct mtd_partition *parts; unsigned int num_parts; }; @@ -179,7 +181,9 @@ extern void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data); extern void __init at91_add_device_ac97(struct ac97c_platform_data *data); /* ISI */ -extern void __init at91_add_device_isi(void); +struct isi_platform_data; +extern void __init at91_add_device_isi(struct isi_platform_data *data, + bool use_pck_as_mck); /* Touchscreen Controller */ struct at91_tsadcc_data { diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 98997c2..2bf7d6e 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -42,6 +42,7 @@ config SOC_EXYNOS4212 bool "SAMSUNG EXYNOS4212" default y depends on ARCH_EXYNOS4 + select SAMSUNG_DMADEV select S5P_PM if PM select S5P_SLEEP if PM help @@ -51,6 +52,7 @@ config SOC_EXYNOS4412 bool "SAMSUNG EXYNOS4412" default y depends on ARCH_EXYNOS4 + select SAMSUNG_DMADEV help Enable EXYNOS4412 SoC support @@ -335,6 +337,7 @@ config MACH_SMDK4212 select SAMSUNG_DEV_BACKLIGHT select SAMSUNG_DEV_KEYPAD select SAMSUNG_DEV_PWM + select EXYNOS4_DEV_DMA select EXYNOS4_SETUP_I2C1 select EXYNOS4_SETUP_I2C3 select EXYNOS4_SETUP_I2C7 diff --git a/arch/arm/mach-exynos/clock-exynos4.c b/arch/arm/mach-exynos/clock-exynos4.c index 060dde7..200159d 100644 --- a/arch/arm/mach-exynos/clock-exynos4.c +++ b/arch/arm/mach-exynos/clock-exynos4.c @@ -789,6 +789,13 @@ static struct clk exynos4_clk_pdma1 = { .ctrlbit = (1 << 1), }; +static struct clk exynos4_clk_mdma1 = { + .name = "dma", + .devname = "dma-pl330.2", + .enable = exynos4_clk_ip_image_ctrl, + .ctrlbit = ((1 << 8) | (1 << 5) | (1 << 2)), +}; + struct clk *exynos4_clkset_group_list[] = { [0] = &clk_ext_xtal_mux, [1] = &clk_xusbxti, @@ -1307,6 +1314,7 @@ static struct clksrc_clk *exynos4_sysclks[] = { static struct clk *exynos4_clk_cdev[] = { &exynos4_clk_pdma0, &exynos4_clk_pdma1, + &exynos4_clk_mdma1, }; static struct clksrc_clk *exynos4_clksrc_cdev[] = { @@ -1335,6 +1343,7 @@ static struct clk_lookup exynos4_clk_lookup[] = { CLKDEV_INIT("s3c-sdhci.3", "mmc_busclk.2", &exynos4_clk_sclk_mmc3.clk), CLKDEV_INIT("dma-pl330.0", "apb_pclk", &exynos4_clk_pdma0), CLKDEV_INIT("dma-pl330.1", "apb_pclk", &exynos4_clk_pdma1), + CLKDEV_INIT("dma-pl330.2", "apb_pclk", &exynos4_clk_mdma1), CLKDEV_INIT("s3c64xx-spi.0", "spi_busclk0", &exynos4_clk_sclk_spi0.clk), CLKDEV_INIT("s3c64xx-spi.1", "spi_busclk0", &exynos4_clk_sclk_spi1.clk), CLKDEV_INIT("s3c64xx-spi.2", "spi_busclk0", &exynos4_clk_sclk_spi2.clk), diff --git a/arch/arm/mach-exynos/dma.c b/arch/arm/mach-exynos/dma.c index 25f3ef2c..13607c4 100644 --- a/arch/arm/mach-exynos/dma.c +++ b/arch/arm/mach-exynos/dma.c @@ -29,6 +29,7 @@ #include <asm/irq.h> #include <plat/devs.h> #include <plat/irqs.h> +#include <plat/cpu.h> #include <mach/map.h> #include <mach/irqs.h> @@ -36,7 +37,7 @@ static u64 dma_dmamask = DMA_BIT_MASK(32); -static u8 pdma0_peri[] = { +static u8 exynos4210_pdma0_peri[] = { DMACH_PCM0_RX, DMACH_PCM0_TX, DMACH_PCM2_RX, @@ -69,15 +70,47 @@ static u8 pdma0_peri[] = { DMACH_AC97_PCMOUT, }; -static struct dma_pl330_platdata exynos4_pdma0_pdata = { - .nr_valid_peri = ARRAY_SIZE(pdma0_peri), - .peri_id = pdma0_peri, +static u8 exynos4212_pdma0_peri[] = { + DMACH_PCM0_RX, + DMACH_PCM0_TX, + DMACH_PCM2_RX, + DMACH_PCM2_TX, + DMACH_MIPI_HSI0, + DMACH_MIPI_HSI1, + DMACH_SPI0_RX, + DMACH_SPI0_TX, + DMACH_SPI2_RX, + DMACH_SPI2_TX, + DMACH_I2S0S_TX, + DMACH_I2S0_RX, + DMACH_I2S0_TX, + DMACH_I2S2_RX, + DMACH_I2S2_TX, + DMACH_UART0_RX, + DMACH_UART0_TX, + DMACH_UART2_RX, + DMACH_UART2_TX, + DMACH_UART4_RX, + DMACH_UART4_TX, + DMACH_SLIMBUS0_RX, + DMACH_SLIMBUS0_TX, + DMACH_SLIMBUS2_RX, + DMACH_SLIMBUS2_TX, + DMACH_SLIMBUS4_RX, + DMACH_SLIMBUS4_TX, + DMACH_AC97_MICIN, + DMACH_AC97_PCMIN, + DMACH_AC97_PCMOUT, + DMACH_MIPI_HSI4, + DMACH_MIPI_HSI5, }; +struct dma_pl330_platdata exynos4_pdma0_pdata; + static AMBA_AHB_DEVICE(exynos4_pdma0, "dma-pl330.0", 0x00041330, EXYNOS4_PA_PDMA0, {IRQ_PDMA0}, &exynos4_pdma0_pdata); -static u8 pdma1_peri[] = { +static u8 exynos4210_pdma1_peri[] = { DMACH_PCM0_RX, DMACH_PCM0_TX, DMACH_PCM1_RX, @@ -105,19 +138,84 @@ static u8 pdma1_peri[] = { DMACH_SLIMBUS5_TX, }; -static struct dma_pl330_platdata exynos4_pdma1_pdata = { - .nr_valid_peri = ARRAY_SIZE(pdma1_peri), - .peri_id = pdma1_peri, +static u8 exynos4212_pdma1_peri[] = { + DMACH_PCM0_RX, + DMACH_PCM0_TX, + DMACH_PCM1_RX, + DMACH_PCM1_TX, + DMACH_MIPI_HSI2, + DMACH_MIPI_HSI3, + DMACH_SPI1_RX, + DMACH_SPI1_TX, + DMACH_I2S0S_TX, + DMACH_I2S0_RX, + DMACH_I2S0_TX, + DMACH_I2S1_RX, + DMACH_I2S1_TX, + DMACH_UART0_RX, + DMACH_UART0_TX, + DMACH_UART1_RX, + DMACH_UART1_TX, + DMACH_UART3_RX, + DMACH_UART3_TX, + DMACH_SLIMBUS1_RX, + DMACH_SLIMBUS1_TX, + DMACH_SLIMBUS3_RX, + DMACH_SLIMBUS3_TX, + DMACH_SLIMBUS5_RX, + DMACH_SLIMBUS5_TX, + DMACH_SLIMBUS0AUX_RX, + DMACH_SLIMBUS0AUX_TX, + DMACH_SPDIF, + DMACH_MIPI_HSI6, + DMACH_MIPI_HSI7, }; +static struct dma_pl330_platdata exynos4_pdma1_pdata; + static AMBA_AHB_DEVICE(exynos4_pdma1, "dma-pl330.1", 0x00041330, EXYNOS4_PA_PDMA1, {IRQ_PDMA1}, &exynos4_pdma1_pdata); +static u8 mdma_peri[] = { + DMACH_MTOM_0, + DMACH_MTOM_1, + DMACH_MTOM_2, + DMACH_MTOM_3, + DMACH_MTOM_4, + DMACH_MTOM_5, + DMACH_MTOM_6, + DMACH_MTOM_7, +}; + +static struct dma_pl330_platdata exynos4_mdma1_pdata = { + .nr_valid_peri = ARRAY_SIZE(mdma_peri), + .peri_id = mdma_peri, +}; + +static AMBA_AHB_DEVICE(exynos4_mdma1, "dma-pl330.2", 0x00041330, + EXYNOS4_PA_MDMA1, {IRQ_MDMA1}, &exynos4_mdma1_pdata); + static int __init exynos4_dma_init(void) { if (of_have_populated_dt()) return 0; + if (soc_is_exynos4210()) { + exynos4_pdma0_pdata.nr_valid_peri = + ARRAY_SIZE(exynos4210_pdma0_peri); + exynos4_pdma0_pdata.peri_id = exynos4210_pdma0_peri; + exynos4_pdma1_pdata.nr_valid_peri = + ARRAY_SIZE(exynos4210_pdma1_peri); + exynos4_pdma1_pdata.peri_id = exynos4210_pdma1_peri; + } else if (soc_is_exynos4212() || soc_is_exynos4412()) { + exynos4_pdma0_pdata.nr_valid_peri = + ARRAY_SIZE(exynos4212_pdma0_peri); + exynos4_pdma0_pdata.peri_id = exynos4212_pdma0_peri; + exynos4_pdma1_pdata.nr_valid_peri = + ARRAY_SIZE(exynos4212_pdma1_peri); + exynos4_pdma1_pdata.peri_id = exynos4212_pdma1_peri; + } + dma_cap_set(DMA_SLAVE, exynos4_pdma0_pdata.cap_mask); dma_cap_set(DMA_CYCLIC, exynos4_pdma0_pdata.cap_mask); amba_device_register(&exynos4_pdma0_device, &iomem_resource); @@ -126,6 +224,9 @@ static int __init exynos4_dma_init(void) dma_cap_set(DMA_CYCLIC, exynos4_pdma1_pdata.cap_mask); amba_device_register(&exynos4_pdma1_device, &iomem_resource); + dma_cap_set(DMA_MEMCPY, exynos4_mdma1_pdata.cap_mask); + amba_device_register(&exynos4_mdma1_device, &iomem_resource); + return 0; } arch_initcall(exynos4_dma_init); diff --git a/arch/arm/mach-exynos/include/mach/irqs.h b/arch/arm/mach-exynos/include/mach/irqs.h index f77bce0..1d401c95 100644 --- a/arch/arm/mach-exynos/include/mach/irqs.h +++ b/arch/arm/mach-exynos/include/mach/irqs.h @@ -43,6 +43,8 @@ #define IRQ_EINT15 IRQ_SPI(31) #define IRQ_EINT16_31 IRQ_SPI(32) +#define IRQ_MDMA0 IRQ_SPI(33) +#define IRQ_MDMA1 IRQ_SPI(34) #define IRQ_PDMA0 IRQ_SPI(35) #define IRQ_PDMA1 IRQ_SPI(36) #define IRQ_TIMER0_VIC IRQ_SPI(37) diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h index a8cd65f..609127d 100644 --- a/arch/arm/mach-exynos/include/mach/map.h +++ b/arch/arm/mach-exynos/include/mach/map.h @@ -72,7 +72,8 @@ #define EXYNOS4_PA_TWD 0x10500600 #define EXYNOS4_PA_L2CC 0x10502000 -#define EXYNOS4_PA_MDMA 0x10810000 +#define EXYNOS4_PA_MDMA0 0x10810000 +#define EXYNOS4_PA_MDMA1 0x12840000 #define EXYNOS4_PA_PDMA0 0x12680000 #define EXYNOS4_PA_PDMA1 0x12690000 diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c index 191f5c6..82ea6fc 100644 --- a/arch/arm/mach-exynos/mach-nuri.c +++ b/arch/arm/mach-exynos/mach-nuri.c @@ -117,7 +117,7 @@ static struct s3c_sdhci_platdata nuri_hsmmc0_data __initdata = { }; static struct regulator_consumer_supply emmc_supplies[] = { - REGULATOR_SUPPLY("vmmc", "s3c-sdhci.0"), + REGULATOR_SUPPLY("vmmc", "exynos4-sdhci.0"), REGULATOR_SUPPLY("vmmc", "dw_mmc"), }; @@ -418,7 +418,7 @@ static struct regulator_consumer_supply __initdata max8997_ldo12_[] = { REGULATOR_SUPPLY("vddio", "6-003c"), /* HDC802 */ }; static struct regulator_consumer_supply __initdata max8997_ldo13_[] = { - REGULATOR_SUPPLY("vmmc", "s3c-sdhci.2"), /* TFLASH */ + REGULATOR_SUPPLY("vmmc", "exynos4-sdhci.2"), /* TFLASH */ }; static struct regulator_consumer_supply __initdata max8997_ldo14_[] = { REGULATOR_SUPPLY("inmotor", "max8997-haptic"), diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c index 0b944eb..28658da 100644 --- a/arch/arm/mach-exynos/mach-universal_c210.c +++ b/arch/arm/mach-exynos/mach-universal_c210.c @@ -752,7 +752,7 @@ static struct s3c_sdhci_platdata universal_hsmmc0_data __initdata = { }; static struct regulator_consumer_supply mmc0_supplies[] = { - REGULATOR_SUPPLY("vmmc", "s3c-sdhci.0"), + REGULATOR_SUPPLY("vmmc", "exynos4-sdhci.0"), }; static struct regulator_init_data mmc0_fixed_voltage_init_data = { diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 37a5d71..feeebde 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -298,6 +298,7 @@ config MACH_MX27_3DS select IMX_HAVE_PLATFORM_IMX_I2C select IMX_HAVE_PLATFORM_IMX_KEYPAD select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_MX2_CAMERA select IMX_HAVE_PLATFORM_MXC_EHCI select IMX_HAVE_PLATFORM_MXC_MMC select IMX_HAVE_PLATFORM_SPI_IMX diff --git a/arch/arm/mach-imx/clock-imx6q.c b/arch/arm/mach-imx/clock-imx6q.c index 2d88f8b..111c328 100644 --- a/arch/arm/mach-imx/clock-imx6q.c +++ b/arch/arm/mach-imx/clock-imx6q.c @@ -329,6 +329,12 @@ #define BM_CLPCR_MASK_SCU_IDLE (0x1 << 26) #define BM_CLPCR_MASK_L2CC_IDLE (0x1 << 27) +#define BP_CCOSR_CKO1_EN 7 +#define BP_CCOSR_CKO1_PODF 4 +#define BM_CCOSR_CKO1_PODF (0x7 << 4) +#define BP_CCOSR_CKO1_SEL 0 +#define BM_CCOSR_CKO1_SEL (0xf << 0) + #define FREQ_480M 480000000 #define FREQ_528M 528000000 #define FREQ_594M 594000000 @@ -393,6 +399,7 @@ static struct clk ipu1_di1_clk; static struct clk ipu2_di0_clk; static struct clk ipu2_di1_clk; static struct clk enfc_clk; +static struct clk cko1_clk; static struct clk dummy_clk = {}; static unsigned long external_high_reference; @@ -938,6 +945,24 @@ static void _clk_disable(struct clk *clk) writel_relaxed(reg, clk->enable_reg); } +static int _clk_enable_1b(struct clk *clk) +{ + u32 reg; + reg = readl_relaxed(clk->enable_reg); + reg |= 0x1 << clk->enable_shift; + writel_relaxed(reg, clk->enable_reg); + + return 0; +} + +static void _clk_disable_1b(struct clk *clk) +{ + u32 reg; + reg = readl_relaxed(clk->enable_reg); + reg &= ~(0x1 << clk->enable_shift); + writel_relaxed(reg, clk->enable_reg); +} + struct divider { struct clk *clk; void __iomem *reg; @@ -983,6 +1008,7 @@ DEF_CLK_DIV1(ipu2_di0_pre_div, &ipu2_di0_pre_clk, CSCDR2, IPU2_DI0_PRE); DEF_CLK_DIV1(ipu2_di1_pre_div, &ipu2_di1_pre_clk, CSCDR2, IPU2_DI1_PRE); DEF_CLK_DIV1(ipu1_div, &ipu1_clk, CSCDR3, IPU1_HSP); DEF_CLK_DIV1(ipu2_div, &ipu2_clk, CSCDR3, IPU2_HSP); +DEF_CLK_DIV1(cko1_div, &cko1_clk, CCOSR, CKO1); #define DEF_CLK_DIV2(d, c, r, b) \ static struct divider d = { \ @@ -1038,6 +1064,7 @@ static struct divider *dividers[] = { &enfc_div, &spdif_div, &asrc_serial_div, + &cko1_div, }; static unsigned long ldb_di_clk_get_rate(struct clk *clk) @@ -1625,6 +1652,32 @@ DEF_IPU_DI_MUX(CSCDR2, 2, 1); DEF_IPU_MUX(1); DEF_IPU_MUX(2); +static struct multiplexer cko1_mux = { + .clk = &cko1_clk, + .reg = CCOSR, + .bp = BP_CCOSR_CKO1_SEL, + .bm = BM_CCOSR_CKO1_SEL, + .parents = { + &pll3_usb_otg, + &pll2_bus, + &pll1_sys, + &pll5_video, + &dummy_clk, + &axi_clk, + &enfc_clk, + &ipu1_di0_clk, + &ipu1_di1_clk, + &ipu2_di0_clk, + &ipu2_di1_clk, + &ahb_clk, + &ipg_clk, + &ipg_perclk, + &ckil_clk, + &pll4_audio, + NULL + }, +}; + static struct multiplexer *multiplexers[] = { &axi_mux, &periph_mux, @@ -1667,6 +1720,7 @@ static struct multiplexer *multiplexers[] = { &ipu2_di1_mux, &ipu1_mux, &ipu2_mux, + &cko1_mux, }; static int _clk_set_parent(struct clk *clk, struct clk *parent) @@ -1690,7 +1744,7 @@ static int _clk_set_parent(struct clk *clk, struct clk *parent) break; i++; } - if (!m->parents[i]) + if (!m->parents[i] || m->parents[i] == &dummy_clk) return -EINVAL; val = readl_relaxed(m->reg); @@ -1745,6 +1799,20 @@ DEF_NG_CLK(asrc_serial_clk, &pll3_usb_otg); .secondary = s, \ } +#define DEF_CLK_1B(name, er, es, p, s) \ + static struct clk name = { \ + .enable_reg = er, \ + .enable_shift = es, \ + .enable = _clk_enable_1b, \ + .disable = _clk_disable_1b, \ + .get_rate = _clk_get_rate, \ + .set_rate = _clk_set_rate, \ + .round_rate = _clk_round_rate, \ + .set_parent = _clk_set_parent, \ + .parent = p, \ + .secondary = s, \ + } + DEF_CLK(aips_tz1_clk, CCGR0, CG0, &ahb_clk, NULL); DEF_CLK(aips_tz2_clk, CCGR0, CG1, &ahb_clk, NULL); DEF_CLK(apbh_dma_clk, CCGR0, CG2, &ahb_clk, NULL); @@ -1811,6 +1879,7 @@ DEF_CLK(usdhc4_clk, CCGR6, CG4, &pll2_pfd_400m, NULL); DEF_CLK(emi_slow_clk, CCGR6, CG5, &axi_clk, NULL); DEF_CLK(vdo_axi_clk, CCGR6, CG6, &axi_clk, NULL); DEF_CLK(vpu_clk, CCGR6, CG7, &axi_clk, NULL); +DEF_CLK_1B(cko1_clk, CCOSR, BP_CCOSR_CKO1_EN, &pll2_bus, NULL); static int pcie_clk_enable(struct clk *clk) { @@ -1922,6 +1991,7 @@ static struct clk_lookup lookups[] = { _REGISTER_CLOCK(NULL, "gpmi_io_clk", gpmi_io_clk), _REGISTER_CLOCK(NULL, "usboh3_clk", usboh3_clk), _REGISTER_CLOCK(NULL, "sata_clk", sata_clk), + _REGISTER_CLOCK(NULL, "cko1_clk", cko1_clk), }; int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) @@ -2029,6 +2099,8 @@ int __init mx6q_clocks_init(void) clk_set_rate(&usdhc3_clk, 49500000); clk_set_rate(&usdhc4_clk, 49500000); + clk_set_parent(&cko1_clk, &ahb_clk); + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt"); base = of_iomap(np, 0); WARN_ON(!base); diff --git a/arch/arm/mach-imx/lluart.c b/arch/arm/mach-imx/lluart.c index d4ab6f2..0213f8d 100644 --- a/arch/arm/mach-imx/lluart.c +++ b/arch/arm/mach-imx/lluart.c @@ -17,7 +17,7 @@ #include <mach/hardware.h> static struct map_desc imx_lluart_desc = { -#ifdef CONFIG_DEBUG_IMX6Q_UART +#ifdef CONFIG_DEBUG_IMX6Q_UART4 .virtual = MX6Q_IO_P2V(MX6Q_UART4_BASE_ADDR), .pfn = __phys_to_pfn(MX6Q_UART4_BASE_ADDR), .length = MX6Q_UART4_SIZE, diff --git a/arch/arm/mach-imx/mach-mx21ads.c b/arch/arm/mach-imx/mach-mx21ads.c index 8d9f955..e432d4a 100644 --- a/arch/arm/mach-imx/mach-mx21ads.c +++ b/arch/arm/mach-imx/mach-mx21ads.c @@ -37,8 +37,8 @@ #define MX21ADS_REG_ADDR(offset) (void __force __iomem *) \ (MX21ADS_MMIO_BASE_ADDR + (offset)) +#define MX21ADS_CS8900A_MMIO_SIZE 0x200000 #define MX21ADS_CS8900A_IRQ IRQ_GPIOE(11) -#define MX21ADS_CS8900A_IOBASE_REG MX21ADS_REG_ADDR(0x000000) #define MX21ADS_ST16C255_IOBASE_REG MX21ADS_REG_ADDR(0x200000) #define MX21ADS_VERSION_REG MX21ADS_REG_ADDR(0x400000) #define MX21ADS_IO_REG MX21ADS_REG_ADDR(0x800000) @@ -159,6 +159,18 @@ static struct platform_device mx21ads_nor_mtd_device = { .resource = &mx21ads_flash_resource, }; +static const struct resource mx21ads_cs8900_resources[] __initconst = { + DEFINE_RES_MEM(MX21_CS1_BASE_ADDR, MX21ADS_CS8900A_MMIO_SIZE), + DEFINE_RES_IRQ(MX21ADS_CS8900A_IRQ), +}; + +static const struct platform_device_info mx21ads_cs8900_devinfo __initconst = { + .name = "cs89x0", + .id = 0, + .res = mx21ads_cs8900_resources, + .num_res = ARRAY_SIZE(mx21ads_cs8900_resources), +}; + static const struct imxuart_platform_data uart_pdata_rts __initconst = { .flags = IMXUART_HAVE_RTSCTS, }; @@ -292,6 +304,8 @@ static void __init mx21ads_board_init(void) imx21_add_mxc_nand(&mx21ads_nand_board_info); platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); + platform_device_register_full( + (struct platform_device_info *)&mx21ads_cs8900_devinfo); } static void __init mx21ads_timer_init(void) diff --git a/arch/arm/mach-imx/mach-mx27_3ds.c b/arch/arm/mach-imx/mach-mx27_3ds.c index 18f3581..c6d385c 100644 --- a/arch/arm/mach-imx/mach-mx27_3ds.c +++ b/arch/arm/mach-imx/mach-mx27_3ds.c @@ -31,6 +31,8 @@ #include <linux/regulator/machine.h> #include <linux/spi/l4f00242t03.h> +#include <media/soc_camera.h> + #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <asm/mach/time.h> @@ -52,6 +54,8 @@ #define SD1_CD IMX_GPIO_NR(2, 26) #define LCD_RESET IMX_GPIO_NR(1, 3) #define LCD_ENABLE IMX_GPIO_NR(1, 31) +#define CSI_PWRDWN IMX_GPIO_NR(4, 19) +#define CSI_RESET IMX_GPIO_NR(3, 6) static const int mx27pdk_pins[] __initconst = { /* UART1 */ @@ -141,6 +145,26 @@ static const int mx27pdk_pins[] __initconst = { PA30_PF_CONTRAST, LCD_ENABLE | GPIO_GPIO | GPIO_OUT, LCD_RESET | GPIO_GPIO | GPIO_OUT, + /* CSI */ + PB10_PF_CSI_D0, + PB11_PF_CSI_D1, + PB12_PF_CSI_D2, + PB13_PF_CSI_D3, + PB14_PF_CSI_D4, + PB15_PF_CSI_MCLK, + PB16_PF_CSI_PIXCLK, + PB17_PF_CSI_D5, + PB18_PF_CSI_D6, + PB19_PF_CSI_D7, + PB20_PF_CSI_VSYNC, + PB21_PF_CSI_HSYNC, + CSI_PWRDWN | GPIO_GPIO | GPIO_OUT, + CSI_RESET | GPIO_GPIO | GPIO_OUT, +}; + +static struct gpio mx27_3ds_camera_gpios[] = { + { CSI_PWRDWN, GPIOF_OUT_INIT_HIGH, "camera-power" }, + { CSI_RESET, GPIOF_OUT_INIT_HIGH, "camera-reset" }, }; static const struct imxuart_platform_data uart_pdata __initconst = { @@ -242,6 +266,7 @@ static struct regulator_init_data gpo_init = { static struct regulator_consumer_supply vmmc1_consumers[] = { REGULATOR_SUPPLY("vcore", "spi0.0"), + REGULATOR_SUPPLY("cmos_2v8", "soc-camera-pdrv.0"), }; static struct regulator_init_data vmmc1_init = { @@ -270,6 +295,22 @@ static struct regulator_init_data vgen_init = { .consumer_supplies = vgen_consumers, }; +static struct regulator_consumer_supply vvib_consumers[] = { + REGULATOR_SUPPLY("cmos_vcore", "soc-camera-pdrv.0"), +}; + +static struct regulator_init_data vvib_init = { + .constraints = { + .min_uV = 1300000, + .max_uV = 1300000, + .apply_uV = 1, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(vvib_consumers), + .consumer_supplies = vvib_consumers, +}; + static struct mc13xxx_regulator_init_data mx27_3ds_regulators[] = { { .id = MC13783_REG_VMMC1, @@ -283,6 +324,9 @@ static struct mc13xxx_regulator_init_data mx27_3ds_regulators[] = { }, { .id = MC13783_REG_GPO3, /* Turn on 3.3V */ .init_data = &gpo_init, + }, { + .id = MC13783_REG_VVIB, /* Power OV2640 */ + .init_data = &vvib_init, }, }; @@ -311,6 +355,51 @@ static const struct spi_imx_master spi2_pdata __initconst = { .num_chipselect = ARRAY_SIZE(spi2_chipselect), }; +static int mx27_3ds_camera_power(struct device *dev, int on) +{ + /* enable or disable the camera */ + pr_debug("%s: %s the camera\n", __func__, on ? "ENABLE" : "DISABLE"); + gpio_set_value(CSI_PWRDWN, on ? 0 : 1); + + if (!on) + goto out; + + /* If enabled, give a reset impulse */ + gpio_set_value(CSI_RESET, 0); + msleep(20); + gpio_set_value(CSI_RESET, 1); + msleep(100); + +out: + return 0; +} + +static struct i2c_board_info mx27_3ds_i2c_camera = { + I2C_BOARD_INFO("ov2640", 0x30), +}; + +static struct regulator_bulk_data mx27_3ds_camera_regs[] = { + { .supply = "cmos_vcore" }, + { .supply = "cmos_2v8" }, +}; + +static struct soc_camera_link iclink_ov2640 = { + .bus_id = 0, + .board_info = &mx27_3ds_i2c_camera, + .i2c_adapter_id = 0, + .power = mx27_3ds_camera_power, + .regulators = mx27_3ds_camera_regs, + .num_regulators = ARRAY_SIZE(mx27_3ds_camera_regs), +}; + +static struct platform_device mx27_3ds_ov2640 = { + .name = "soc-camera-pdrv", + .id = 0, + .dev = { + .platform_data = &iclink_ov2640, + }, +}; + static struct imx_fb_videomode mx27_3ds_modes[] = { { /* 480x640 @ 60 Hz */ .mode = { @@ -367,12 +456,21 @@ static struct spi_board_info mx27_3ds_spi_devs[] __initdata = { }, }; +static struct platform_device *devices[] __initdata = { + &mx27_3ds_ov2640, +}; + +static const struct mx2_camera_platform_data mx27_3ds_cam_pdata __initconst = { + .clk = 26000000, +}; + static const struct imxi2c_platform_data mx27_3ds_i2c0_data __initconst = { .bitrate = 100000, }; static void __init mx27pdk_init(void) { + int ret; imx27_soc_init(); mxc_gpio_setup_multiple_pins(mx27pdk_pins, ARRAY_SIZE(mx27pdk_pins), @@ -404,7 +502,17 @@ static void __init mx27pdk_init(void) if (mxc_expio_init(MX27_CS5_BASE_ADDR, EXPIO_PARENT_INT)) pr_warn("Init of the debugboard failed, all devices on the debugboard are unusable.\n"); imx27_add_imx_i2c(0, &mx27_3ds_i2c0_data); + platform_add_devices(devices, ARRAY_SIZE(devices)); imx27_add_imx_fb(&mx27_3ds_fb_data); + + ret = gpio_request_array(mx27_3ds_camera_gpios, + ARRAY_SIZE(mx27_3ds_camera_gpios)); + if (ret) { + pr_err("Failed to request camera gpios"); + iclink_ov2640.power = NULL; + } + + imx27_add_mx2_camera(&mx27_3ds_cam_pdata); } static void __init mx27pdk_timer_init(void) diff --git a/arch/arm/mach-imx/mach-mx31ads.c b/arch/arm/mach-imx/mach-mx31ads.c index 4917aab..4518e54 100644 --- a/arch/arm/mach-imx/mach-mx31ads.c +++ b/arch/arm/mach-imx/mach-mx31ads.c @@ -28,7 +28,6 @@ #include <asm/memory.h> #include <asm/mach/map.h> #include <mach/common.h> -#include <mach/board-mx31ads.h> #include <mach/iomux-mx3.h> #ifdef CONFIG_MACH_MX31ADS_WM1133_EV1 @@ -39,6 +38,9 @@ #include "devices-imx31.h" +/* Base address of PBC controller */ +#define PBC_BASE_ADDRESS MX31_CS4_BASE_ADDR_VIRT + /* PBC Board interrupt status register */ #define PBC_INTSTATUS 0x000016 @@ -62,6 +64,7 @@ #define PBC_INTMASK_CLEAR_REG (PBC_INTMASK_CLEAR + PBC_BASE_ADDRESS) #define EXPIO_PARENT_INT IOMUX_TO_IRQ(MX31_PIN_GPIO1_4) +#define MXC_EXP_IO_BASE MXC_BOARD_IRQ_START #define MXC_IRQ_TO_EXPIO(irq) ((irq) - MXC_EXP_IO_BASE) #define EXPIO_INT_XUART_INTA (MXC_EXP_IO_BASE + 10) @@ -69,6 +72,10 @@ #define MXC_MAX_EXP_IO_LINES 16 +/* CS8900 */ +#define EXPIO_INT_ENET_INT (MXC_EXP_IO_BASE + 8) +#define CS4_CS8900_MMIO_START 0x20000 + /* * The serial port definition structure. */ @@ -101,11 +108,29 @@ static struct platform_device serial_device = { }, }; +static const struct resource mx31ads_cs8900_resources[] __initconst = { + DEFINE_RES_MEM(MX31_CS4_BASE_ADDR + CS4_CS8900_MMIO_START, SZ_64K), + DEFINE_RES_IRQ(EXPIO_INT_ENET_INT), +}; + +static const struct platform_device_info mx31ads_cs8900_devinfo __initconst = { + .name = "cs89x0", + .id = 0, + .res = mx31ads_cs8900_resources, + .num_res = ARRAY_SIZE(mx31ads_cs8900_resources), +}; + static int __init mxc_init_extuart(void) { return platform_device_register(&serial_device); } +static void __init mxc_init_ext_ethernet(void) +{ + platform_device_register_full( + (struct platform_device_info *)&mx31ads_cs8900_devinfo); +} + static const struct imxuart_platform_data uart_pdata __initconst = { .flags = IMXUART_HAVE_RTSCTS, }; @@ -492,12 +517,15 @@ static void __init mxc_init_audio(void) mxc_iomux_setup_multiple_pins(ssi_pins, ARRAY_SIZE(ssi_pins), "ssi"); } -/* static mappings */ +/* + * Static mappings, starting from the CS4 start address up to the start address + * of the CS8900. + */ static struct map_desc mx31ads_io_desc[] __initdata = { { .virtual = MX31_CS4_BASE_ADDR_VIRT, .pfn = __phys_to_pfn(MX31_CS4_BASE_ADDR), - .length = MX31_CS4_SIZE / 2, + .length = CS4_CS8900_MMIO_START, .type = MT_DEVICE }, }; @@ -522,6 +550,7 @@ static void __init mx31ads_init(void) mxc_init_imx_uart(); mxc_init_i2c(); mxc_init_audio(); + mxc_init_ext_ethernet(); } static void __init mx31ads_timer_init(void) diff --git a/arch/arm/mach-imx/mach-mx31moboard.c b/arch/arm/mach-imx/mach-mx31moboard.c index c0511fb..f17a15f 100644 --- a/arch/arm/mach-imx/mach-mx31moboard.c +++ b/arch/arm/mach-imx/mach-mx31moboard.c @@ -507,7 +507,7 @@ static void mx31moboard_poweroff(void) struct clk *clk = clk_get_sys("imx2-wdt.0", NULL); if (!IS_ERR(clk)) - clk_enable(clk); + clk_prepare_enable(clk); mxc_iomux_mode(MX31_PIN_WATCHDOG_RST__WATCHDOG_RST); diff --git a/arch/arm/mach-imx/pm-imx5.c b/arch/arm/mach-imx/pm-imx5.c index 6dc0934..e26a9cb 100644 --- a/arch/arm/mach-imx/pm-imx5.c +++ b/arch/arm/mach-imx/pm-imx5.c @@ -89,7 +89,7 @@ void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode) static int mx5_suspend_prepare(void) { - return clk_enable(gpc_dvfs_clk); + return clk_prepare_enable(gpc_dvfs_clk); } static int mx5_suspend_enter(suspend_state_t state) @@ -119,7 +119,7 @@ static int mx5_suspend_enter(suspend_state_t state) static void mx5_suspend_finish(void) { - clk_disable(gpc_dvfs_clk); + clk_disable_unprepare(gpc_dvfs_clk); } static int mx5_pm_valid(suspend_state_t state) diff --git a/arch/arm/mach-lpc32xx/clock.c b/arch/arm/mach-lpc32xx/clock.c index 0e01bf4..f55c772 100644 --- a/arch/arm/mach-lpc32xx/clock.c +++ b/arch/arm/mach-lpc32xx/clock.c @@ -721,6 +721,41 @@ static struct clk clk_tsc = { .get_rate = local_return_parent_rate, }; +static int adc_onoff_enable(struct clk *clk, int enable) +{ + u32 tmp; + u32 divider; + + /* Use PERIPH_CLOCK */ + tmp = __raw_readl(LPC32XX_CLKPWR_ADC_CLK_CTRL_1); + tmp |= LPC32XX_CLKPWR_ADCCTRL1_PCLK_SEL; + /* + * Set clock divider so that we have equal to or less than + * 4.5MHz clock at ADC + */ + divider = clk->get_rate(clk) / 4500000 + 1; + tmp |= divider; + __raw_writel(tmp, LPC32XX_CLKPWR_ADC_CLK_CTRL_1); + + /* synchronize rate of this clock w/ actual HW setting */ + clk->rate = clk->get_rate(clk->parent) / divider; + + if (enable == 0) + __raw_writel(0, clk->enable_reg); + else + __raw_writel(clk->enable_mask, clk->enable_reg); + + return 0; +} + +static struct clk clk_adc = { + .parent = &clk_pclk, + .enable = adc_onoff_enable, + .enable_reg = LPC32XX_CLKPWR_ADC_CLK_CTRL, + .enable_mask = LPC32XX_CLKPWR_ADC32CLKCTRL_CLK_EN, + .get_rate = local_return_parent_rate, +}; + static int mmc_onoff_enable(struct clk *clk, int enable) { u32 tmp; @@ -1055,6 +1090,7 @@ static struct clk_lookup lookups[] = { _REGISTER_CLOCK("dev:ssp1", NULL, clk_ssp1) _REGISTER_CLOCK("lpc32xx_keys.0", NULL, clk_kscan) _REGISTER_CLOCK("lpc32xx-nand.0", "nand_ck", clk_nand) + _REGISTER_CLOCK("lpc32xx-adc", NULL, clk_adc) _REGISTER_CLOCK(NULL, "i2s0_ck", clk_i2s0) _REGISTER_CLOCK(NULL, "i2s1_ck", clk_i2s1) _REGISTER_CLOCK("ts-lpc32xx", NULL, clk_tsc) diff --git a/arch/arm/mach-lpc32xx/common.c b/arch/arm/mach-lpc32xx/common.c index 369b152..6c76bb3 100644 --- a/arch/arm/mach-lpc32xx/common.c +++ b/arch/arm/mach-lpc32xx/common.c @@ -138,6 +138,28 @@ struct platform_device lpc32xx_rtc_device = { }; /* + * ADC support + */ +static struct resource adc_resources[] = { + { + .start = LPC32XX_ADC_BASE, + .end = LPC32XX_ADC_BASE + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_LPC32XX_TS_IRQ, + .end = IRQ_LPC32XX_TS_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device lpc32xx_adc_device = { + .name = "lpc32xx-adc", + .id = -1, + .num_resources = ARRAY_SIZE(adc_resources), + .resource = adc_resources, +}; + +/* * Returns the unique ID for the device */ void lpc32xx_get_uid(u32 devid[4]) diff --git a/arch/arm/mach-lpc32xx/common.h b/arch/arm/mach-lpc32xx/common.h index 75640bfb..68f2e46 100644 --- a/arch/arm/mach-lpc32xx/common.h +++ b/arch/arm/mach-lpc32xx/common.h @@ -29,6 +29,7 @@ extern struct platform_device lpc32xx_i2c0_device; extern struct platform_device lpc32xx_i2c1_device; extern struct platform_device lpc32xx_i2c2_device; extern struct platform_device lpc32xx_tsc_device; +extern struct platform_device lpc32xx_adc_device; extern struct platform_device lpc32xx_rtc_device; /* diff --git a/arch/arm/mach-lpc32xx/phy3250.c b/arch/arm/mach-lpc32xx/phy3250.c index 8571d62..0d79a3f 100644 --- a/arch/arm/mach-lpc32xx/phy3250.c +++ b/arch/arm/mach-lpc32xx/phy3250.c @@ -254,6 +254,7 @@ static struct platform_device *phy3250_devs[] __initdata = { &lpc32xx_i2c2_device, &lpc32xx_watchdog_device, &lpc32xx_gpio_led_device, + &lpc32xx_adc_device, }; static struct amba_device *amba_devs[] __initdata = { diff --git a/arch/arm/mach-mmp/include/mach/pxa910.h b/arch/arm/mach-mmp/include/mach/pxa910.h index 4de13ab..e2e1f1e 100644 --- a/arch/arm/mach-mmp/include/mach/pxa910.h +++ b/arch/arm/mach-mmp/include/mach/pxa910.h @@ -22,6 +22,7 @@ extern struct pxa_device_desc pxa910_device_pwm4; extern struct pxa_device_desc pxa910_device_nand; extern struct platform_device pxa910_device_gpio; +extern struct platform_device pxa910_device_rtc; static inline int pxa910_add_uart(int id) { diff --git a/arch/arm/mach-mmp/include/mach/regs-apbc.h b/arch/arm/mach-mmp/include/mach/regs-apbc.h index 1a96585..8a37fb0 100644 --- a/arch/arm/mach-mmp/include/mach/regs-apbc.h +++ b/arch/arm/mach-mmp/include/mach/regs-apbc.h @@ -57,6 +57,7 @@ #define APBC_PXA910_SSP1 APBC_REG(0x01c) #define APBC_PXA910_SSP2 APBC_REG(0x020) #define APBC_PXA910_IPC APBC_REG(0x024) +#define APBC_PXA910_RTC APBC_REG(0x028) #define APBC_PXA910_TWSI0 APBC_REG(0x02c) #define APBC_PXA910_KPC APBC_REG(0x030) #define APBC_PXA910_TIMERS APBC_REG(0x034) diff --git a/arch/arm/mach-mmp/include/mach/regs-rtc.h b/arch/arm/mach-mmp/include/mach/regs-rtc.h new file mode 100644 index 0000000..5bff886 --- /dev/null +++ b/arch/arm/mach-mmp/include/mach/regs-rtc.h @@ -0,0 +1,23 @@ +#ifndef __ASM_MACH_REGS_RTC_H +#define __ASM_MACH_REGS_RTC_H + +#include <mach/addr-map.h> + +#define RTC_VIRT_BASE (APB_VIRT_BASE + 0x10000) +#define RTC_REG(x) (*((volatile u32 __iomem *)(RTC_VIRT_BASE + (x)))) + +/* + * Real Time Clock + */ + +#define RCNR RTC_REG(0x00) /* RTC Count Register */ +#define RTAR RTC_REG(0x04) /* RTC Alarm Register */ +#define RTSR RTC_REG(0x08) /* RTC Status Register */ +#define RTTR RTC_REG(0x0C) /* RTC Timer Trim Register */ + +#define RTSR_HZE (1 << 3) /* HZ interrupt enable */ +#define RTSR_ALE (1 << 2) /* RTC alarm interrupt enable */ +#define RTSR_HZ (1 << 1) /* HZ rising-edge detected */ +#define RTSR_AL (1 << 0) /* RTC alarm detected */ + +#endif /* __ASM_MACH_REGS_RTC_H */ diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c index 0c87e69..43f8bcc 100644 --- a/arch/arm/mach-mmp/pxa910.c +++ b/arch/arm/mach-mmp/pxa910.c @@ -92,6 +92,7 @@ static APBC_CLK(pwm2, PXA910_PWM2, 1, 13000000); static APBC_CLK(pwm3, PXA910_PWM3, 1, 13000000); static APBC_CLK(pwm4, PXA910_PWM4, 1, 13000000); static APBC_CLK(gpio, PXA910_GPIO, 0, 13000000); +static APBC_CLK(rtc, PXA910_RTC, 8, 32768); static APMU_CLK(nand, NAND, 0x19b, 156000000); static APMU_CLK(u2o, USB, 0x1b, 480000000); @@ -109,6 +110,7 @@ static struct clk_lookup pxa910_clkregs[] = { INIT_CLKREG(&clk_nand, "pxa3xx-nand", NULL), INIT_CLKREG(&clk_gpio, "pxa-gpio", NULL), INIT_CLKREG(&clk_u2o, "pxa-u2o", "U2OCLK"), + INIT_CLKREG(&clk_rtc, "sa1100-rtc", NULL), }; static int __init pxa910_init(void) @@ -184,3 +186,28 @@ struct platform_device pxa910_device_gpio = { .num_resources = ARRAY_SIZE(pxa910_resource_gpio), .resource = pxa910_resource_gpio, }; + +static struct resource pxa910_resource_rtc[] = { + { + .start = 0xd4010000, + .end = 0xd401003f, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_PXA910_RTC_INT, + .end = IRQ_PXA910_RTC_INT, + .name = "rtc 1Hz", + .flags = IORESOURCE_IRQ, + }, { + .start = IRQ_PXA910_RTC_ALARM, + .end = IRQ_PXA910_RTC_ALARM, + .name = "rtc alarm", + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device pxa910_device_rtc = { + .name = "sa1100-rtc", + .id = -1, + .num_resources = ARRAY_SIZE(pxa910_resource_rtc), + .resource = pxa910_resource_rtc, +}; diff --git a/arch/arm/mach-mmp/ttc_dkb.c b/arch/arm/mach-mmp/ttc_dkb.c index 5ac5d58..e72c709d 100644 --- a/arch/arm/mach-mmp/ttc_dkb.c +++ b/arch/arm/mach-mmp/ttc_dkb.c @@ -124,6 +124,7 @@ static struct platform_device ttc_dkb_device_onenand = { static struct platform_device *ttc_dkb_devices[] = { &pxa910_device_gpio, + &pxa910_device_rtc, &ttc_dkb_device_onenand, }; diff --git a/arch/arm/mach-mxs/clock-mx23.c b/arch/arm/mach-mxs/clock-mx23.c index 293958b..e3ac52c 100644 --- a/arch/arm/mach-mxs/clock-mx23.c +++ b/arch/arm/mach-mxs/clock-mx23.c @@ -439,6 +439,7 @@ static struct clk_lookup lookups[] = { _REGISTER_CLOCK("mxs-pwm.3", NULL, pwm_clk) _REGISTER_CLOCK("mxs-pwm.4", NULL, pwm_clk) _REGISTER_CLOCK("imx23-fb", NULL, lcdif_clk) + _REGISTER_CLOCK("imx23-gpmi-nand", NULL, gpmi_clk) }; static int clk_misc_init(void) diff --git a/arch/arm/mach-mxs/clock-mx28.c b/arch/arm/mach-mxs/clock-mx28.c index 22ad12f..cea29c9 100644 --- a/arch/arm/mach-mxs/clock-mx28.c +++ b/arch/arm/mach-mxs/clock-mx28.c @@ -617,6 +617,7 @@ static struct clk_lookup lookups[] = { _REGISTER_CLOCK("duart", NULL, uart_clk) _REGISTER_CLOCK("imx28-fec.0", NULL, fec_clk) _REGISTER_CLOCK("imx28-fec.1", NULL, fec_clk) + _REGISTER_CLOCK("imx28-gpmi-nand", NULL, gpmi_clk) _REGISTER_CLOCK("mxs-auart.0", NULL, uart_clk) _REGISTER_CLOCK("mxs-auart.1", NULL, uart_clk) _REGISTER_CLOCK("mxs-auart.2", NULL, uart_clk) diff --git a/arch/arm/mach-mxs/devices-mx23.h b/arch/arm/mach-mxs/devices-mx23.h index 3fa651d..4d1329d 100644 --- a/arch/arm/mach-mxs/devices-mx23.h +++ b/arch/arm/mach-mxs/devices-mx23.h @@ -21,6 +21,10 @@ extern const struct mxs_auart_data mx23_auart_data[] __initconst; #define mx23_add_auart0() mx23_add_auart(0) #define mx23_add_auart1() mx23_add_auart(1) +extern const struct mxs_gpmi_nand_data mx23_gpmi_nand_data __initconst; +#define mx23_add_gpmi_nand(pdata) \ + mxs_add_gpmi_nand(pdata, &mx23_gpmi_nand_data) + extern const struct mxs_mxs_mmc_data mx23_mxs_mmc_data[] __initconst; #define mx23_add_mxs_mmc(id, pdata) \ mxs_add_mxs_mmc(&mx23_mxs_mmc_data[id], pdata) diff --git a/arch/arm/mach-mxs/devices-mx28.h b/arch/arm/mach-mxs/devices-mx28.h index 4f50094..9dbeae1 100644 --- a/arch/arm/mach-mxs/devices-mx28.h +++ b/arch/arm/mach-mxs/devices-mx28.h @@ -34,6 +34,10 @@ extern const struct mxs_flexcan_data mx28_flexcan_data[] __initconst; #define mx28_add_flexcan0(pdata) mx28_add_flexcan(0, pdata) #define mx28_add_flexcan1(pdata) mx28_add_flexcan(1, pdata) +extern const struct mxs_gpmi_nand_data mx28_gpmi_nand_data __initconst; +#define mx28_add_gpmi_nand(pdata) \ + mxs_add_gpmi_nand(pdata, &mx28_gpmi_nand_data) + extern const struct mxs_mxs_i2c_data mx28_mxs_i2c_data[] __initconst; #define mx28_add_mxs_i2c(id) mxs_add_mxs_i2c(&mx28_mxs_i2c_data[id]) diff --git a/arch/arm/mach-mxs/devices/Kconfig b/arch/arm/mach-mxs/devices/Kconfig index 18b6bf5..b8913df 100644 --- a/arch/arm/mach-mxs/devices/Kconfig +++ b/arch/arm/mach-mxs/devices/Kconfig @@ -12,6 +12,9 @@ config MXS_HAVE_PLATFORM_FLEXCAN select HAVE_CAN_FLEXCAN if CAN bool +config MXS_HAVE_PLATFORM_GPMI_NAND + bool + config MXS_HAVE_PLATFORM_MXS_I2C bool diff --git a/arch/arm/mach-mxs/devices/Makefile b/arch/arm/mach-mxs/devices/Makefile index f52e3e5..c8f5c95 100644 --- a/arch/arm/mach-mxs/devices/Makefile +++ b/arch/arm/mach-mxs/devices/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_MXS_HAVE_PLATFORM_AUART) += platform-auart.o obj-y += platform-dma.o obj-$(CONFIG_MXS_HAVE_PLATFORM_FEC) += platform-fec.o obj-$(CONFIG_MXS_HAVE_PLATFORM_FLEXCAN) += platform-flexcan.o +obj-$(CONFIG_MXS_HAVE_PLATFORM_GPMI_NAND) += platform-gpmi-nand.o obj-$(CONFIG_MXS_HAVE_PLATFORM_MXS_I2C) += platform-mxs-i2c.o obj-$(CONFIG_MXS_HAVE_PLATFORM_MXS_MMC) += platform-mxs-mmc.o obj-$(CONFIG_MXS_HAVE_PLATFORM_MXS_PWM) += platform-mxs-pwm.o diff --git a/arch/arm/mach-mxs/devices/platform-gpmi-nand.c b/arch/arm/mach-mxs/devices/platform-gpmi-nand.c new file mode 100644 index 0000000..3e22df5 --- /dev/null +++ b/arch/arm/mach-mxs/devices/platform-gpmi-nand.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. 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; 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include <asm/sizes.h> +#include <mach/mx23.h> +#include <mach/mx28.h> +#include <mach/devices-common.h> +#include <linux/dma-mapping.h> + +#ifdef CONFIG_SOC_IMX23 +const struct mxs_gpmi_nand_data mx23_gpmi_nand_data __initconst = { + .devid = "imx23-gpmi-nand", + .res = { + /* GPMI */ + DEFINE_RES_MEM_NAMED(MX23_GPMI_BASE_ADDR, SZ_8K, + GPMI_NAND_GPMI_REGS_ADDR_RES_NAME), + DEFINE_RES_IRQ_NAMED(MX23_INT_GPMI_ATTENTION, + GPMI_NAND_GPMI_INTERRUPT_RES_NAME), + /* BCH */ + DEFINE_RES_MEM_NAMED(MX23_BCH_BASE_ADDR, SZ_8K, + GPMI_NAND_BCH_REGS_ADDR_RES_NAME), + DEFINE_RES_IRQ_NAMED(MX23_INT_BCH, + GPMI_NAND_BCH_INTERRUPT_RES_NAME), + /* DMA */ + DEFINE_RES_NAMED(MX23_DMA_GPMI0, + MX23_DMA_GPMI3 - MX23_DMA_GPMI0 + 1, + GPMI_NAND_DMA_CHANNELS_RES_NAME, + IORESOURCE_DMA), + DEFINE_RES_IRQ_NAMED(MX23_INT_GPMI_DMA, + GPMI_NAND_DMA_INTERRUPT_RES_NAME), + }, +}; +#endif + +#ifdef CONFIG_SOC_IMX28 +const struct mxs_gpmi_nand_data mx28_gpmi_nand_data __initconst = { + .devid = "imx28-gpmi-nand", + .res = { + /* GPMI */ + DEFINE_RES_MEM_NAMED(MX28_GPMI_BASE_ADDR, SZ_8K, + GPMI_NAND_GPMI_REGS_ADDR_RES_NAME), + DEFINE_RES_IRQ_NAMED(MX28_INT_GPMI, + GPMI_NAND_GPMI_INTERRUPT_RES_NAME), + /* BCH */ + DEFINE_RES_MEM_NAMED(MX28_BCH_BASE_ADDR, SZ_8K, + GPMI_NAND_BCH_REGS_ADDR_RES_NAME), + DEFINE_RES_IRQ_NAMED(MX28_INT_BCH, + GPMI_NAND_BCH_INTERRUPT_RES_NAME), + /* DMA */ + DEFINE_RES_NAMED(MX28_DMA_GPMI0, + MX28_DMA_GPMI7 - MX28_DMA_GPMI0 + 1, + GPMI_NAND_DMA_CHANNELS_RES_NAME, + IORESOURCE_DMA), + DEFINE_RES_IRQ_NAMED(MX28_INT_GPMI_DMA, + GPMI_NAND_DMA_INTERRUPT_RES_NAME), + }, +}; +#endif + +struct platform_device *__init +mxs_add_gpmi_nand(const struct gpmi_nand_platform_data *pdata, + const struct mxs_gpmi_nand_data *data) +{ + return mxs_add_platform_device_dmamask(data->devid, -1, + data->res, GPMI_NAND_RES_SIZE, + pdata, sizeof(*pdata), DMA_BIT_MASK(32)); +} diff --git a/arch/arm/mach-mxs/include/mach/devices-common.h b/arch/arm/mach-mxs/include/mach/devices-common.h index dc369c1..f2e3839 100644 --- a/arch/arm/mach-mxs/include/mach/devices-common.h +++ b/arch/arm/mach-mxs/include/mach/devices-common.h @@ -66,6 +66,16 @@ struct platform_device *__init mxs_add_flexcan( const struct mxs_flexcan_data *data, const struct flexcan_platform_data *pdata); +/* gpmi-nand */ +#include <linux/mtd/gpmi-nand.h> +struct mxs_gpmi_nand_data { + const char *devid; + const struct resource res[GPMI_NAND_RES_SIZE]; +}; +struct platform_device *__init +mxs_add_gpmi_nand(const struct gpmi_nand_platform_data *pdata, + const struct mxs_gpmi_nand_data *data); + /* i2c */ struct mxs_mxs_i2c_data { int id; diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index 3c8dd92..34b9766d 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -29,6 +29,7 @@ #include "omap_hwmod_common_data.h" +#include "smartreflex.h" #include "prm-regbits-34xx.h" #include "cm-regbits-34xx.h" #include "wd_timer.h" @@ -376,6 +377,16 @@ static struct omap_hwmod_ocp_if omap3_l4_core__i2c3 = { .user = OCP_USER_MPU | OCP_USER_SDMA, }; +static struct omap_hwmod_irq_info omap3_smartreflex_mpu_irqs[] = { + { .irq = 18}, + { .irq = -1 } +}; + +static struct omap_hwmod_irq_info omap3_smartreflex_core_irqs[] = { + { .irq = 19}, + { .irq = -1 } +}; + /* L4 CORE -> SR1 interface */ static struct omap_hwmod_addr_space omap3_sr1_addr_space[] = { { @@ -2664,6 +2675,10 @@ static struct omap_hwmod_class omap36xx_smartreflex_hwmod_class = { }; /* SR1 */ +static struct omap_smartreflex_dev_attr sr1_dev_attr = { + .sensor_voltdm_name = "mpu_iva", +}; + static struct omap_hwmod_ocp_if *omap3_sr1_slaves[] = { &omap3_l4_core__sr1, }; @@ -2672,7 +2687,6 @@ static struct omap_hwmod omap34xx_sr1_hwmod = { .name = "sr1_hwmod", .class = &omap34xx_smartreflex_hwmod_class, .main_clk = "sr1_fck", - .vdd_name = "mpu_iva", .prcm = { .omap2 = { .prcm_reg_id = 1, @@ -2684,6 +2698,8 @@ static struct omap_hwmod omap34xx_sr1_hwmod = { }, .slaves = omap3_sr1_slaves, .slaves_cnt = ARRAY_SIZE(omap3_sr1_slaves), + .dev_attr = &sr1_dev_attr, + .mpu_irqs = omap3_smartreflex_mpu_irqs, .flags = HWMOD_SET_DEFAULT_CLOCKACT, }; @@ -2691,7 +2707,6 @@ static struct omap_hwmod omap36xx_sr1_hwmod = { .name = "sr1_hwmod", .class = &omap36xx_smartreflex_hwmod_class, .main_clk = "sr1_fck", - .vdd_name = "mpu_iva", .prcm = { .omap2 = { .prcm_reg_id = 1, @@ -2703,9 +2718,15 @@ static struct omap_hwmod omap36xx_sr1_hwmod = { }, .slaves = omap3_sr1_slaves, .slaves_cnt = ARRAY_SIZE(omap3_sr1_slaves), + .dev_attr = &sr1_dev_attr, + .mpu_irqs = omap3_smartreflex_mpu_irqs, }; /* SR2 */ +static struct omap_smartreflex_dev_attr sr2_dev_attr = { + .sensor_voltdm_name = "core", +}; + static struct omap_hwmod_ocp_if *omap3_sr2_slaves[] = { &omap3_l4_core__sr2, }; @@ -2714,7 +2735,6 @@ static struct omap_hwmod omap34xx_sr2_hwmod = { .name = "sr2_hwmod", .class = &omap34xx_smartreflex_hwmod_class, .main_clk = "sr2_fck", - .vdd_name = "core", .prcm = { .omap2 = { .prcm_reg_id = 1, @@ -2726,6 +2746,8 @@ static struct omap_hwmod omap34xx_sr2_hwmod = { }, .slaves = omap3_sr2_slaves, .slaves_cnt = ARRAY_SIZE(omap3_sr2_slaves), + .dev_attr = &sr2_dev_attr, + .mpu_irqs = omap3_smartreflex_core_irqs, .flags = HWMOD_SET_DEFAULT_CLOCKACT, }; @@ -2733,7 +2755,6 @@ static struct omap_hwmod omap36xx_sr2_hwmod = { .name = "sr2_hwmod", .class = &omap36xx_smartreflex_hwmod_class, .main_clk = "sr2_fck", - .vdd_name = "core", .prcm = { .omap2 = { .prcm_reg_id = 1, @@ -2745,6 +2766,8 @@ static struct omap_hwmod omap36xx_sr2_hwmod = { }, .slaves = omap3_sr2_slaves, .slaves_cnt = ARRAY_SIZE(omap3_sr2_slaves), + .dev_attr = &sr2_dev_attr, + .mpu_irqs = omap3_smartreflex_core_irqs, }; /* diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index acb561e..08daa5e 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -33,6 +33,7 @@ #include "omap_hwmod_common_data.h" +#include "smartreflex.h" #include "cm1_44xx.h" #include "cm2_44xx.h" #include "prm44xx.h" @@ -3962,6 +3963,10 @@ static struct omap_hwmod_class omap44xx_smartreflex_hwmod_class = { }; /* smartreflex_core */ +static struct omap_smartreflex_dev_attr smartreflex_core_dev_attr = { + .sensor_voltdm_name = "core", +}; + static struct omap_hwmod omap44xx_smartreflex_core_hwmod; static struct omap_hwmod_irq_info omap44xx_smartreflex_core_irqs[] = { { .irq = 19 + OMAP44XX_IRQ_GIC_START }, @@ -3998,7 +4003,6 @@ static struct omap_hwmod omap44xx_smartreflex_core_hwmod = { .mpu_irqs = omap44xx_smartreflex_core_irqs, .main_clk = "smartreflex_core_fck", - .vdd_name = "core", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_ALWON_SR_CORE_CLKCTRL_OFFSET, @@ -4008,9 +4012,14 @@ static struct omap_hwmod omap44xx_smartreflex_core_hwmod = { }, .slaves = omap44xx_smartreflex_core_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_smartreflex_core_slaves), + .dev_attr = &smartreflex_core_dev_attr, }; /* smartreflex_iva */ +static struct omap_smartreflex_dev_attr smartreflex_iva_dev_attr = { + .sensor_voltdm_name = "iva", +}; + static struct omap_hwmod omap44xx_smartreflex_iva_hwmod; static struct omap_hwmod_irq_info omap44xx_smartreflex_iva_irqs[] = { { .irq = 102 + OMAP44XX_IRQ_GIC_START }, @@ -4046,7 +4055,6 @@ static struct omap_hwmod omap44xx_smartreflex_iva_hwmod = { .clkdm_name = "l4_ao_clkdm", .mpu_irqs = omap44xx_smartreflex_iva_irqs, .main_clk = "smartreflex_iva_fck", - .vdd_name = "iva", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_ALWON_SR_IVA_CLKCTRL_OFFSET, @@ -4056,9 +4064,14 @@ static struct omap_hwmod omap44xx_smartreflex_iva_hwmod = { }, .slaves = omap44xx_smartreflex_iva_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_smartreflex_iva_slaves), + .dev_attr = &smartreflex_iva_dev_attr, }; /* smartreflex_mpu */ +static struct omap_smartreflex_dev_attr smartreflex_mpu_dev_attr = { + .sensor_voltdm_name = "mpu", +}; + static struct omap_hwmod omap44xx_smartreflex_mpu_hwmod; static struct omap_hwmod_irq_info omap44xx_smartreflex_mpu_irqs[] = { { .irq = 18 + OMAP44XX_IRQ_GIC_START }, @@ -4094,7 +4107,6 @@ static struct omap_hwmod omap44xx_smartreflex_mpu_hwmod = { .clkdm_name = "l4_ao_clkdm", .mpu_irqs = omap44xx_smartreflex_mpu_irqs, .main_clk = "smartreflex_mpu_fck", - .vdd_name = "mpu", .prcm = { .omap4 = { .clkctrl_offs = OMAP4_CM_ALWON_SR_MPU_CLKCTRL_OFFSET, @@ -4104,6 +4116,7 @@ static struct omap_hwmod omap44xx_smartreflex_mpu_hwmod = { }, .slaves = omap44xx_smartreflex_mpu_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_smartreflex_mpu_slaves), + .dev_attr = &smartreflex_mpu_dev_attr, }; /* diff --git a/arch/arm/mach-omap2/smartreflex-class3.c b/arch/arm/mach-omap2/smartreflex-class3.c index 53d9d0a..955566ee 100644 --- a/arch/arm/mach-omap2/smartreflex-class3.c +++ b/arch/arm/mach-omap2/smartreflex-class3.c @@ -29,6 +29,7 @@ static int sr_class3_enable(struct voltagedomain *voltdm) static int sr_class3_disable(struct voltagedomain *voltdm, int is_volt_reset) { + sr_disable_errgen(voltdm); omap_vp_disable(voltdm); sr_disable(voltdm); if (is_volt_reset) diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c index 47c77a1..008fbd7 100644 --- a/arch/arm/mach-omap2/smartreflex.c +++ b/arch/arm/mach-omap2/smartreflex.c @@ -36,6 +36,12 @@ #define SR_DISABLE_TIMEOUT 200 struct omap_sr { + struct list_head node; + struct platform_device *pdev; + struct omap_sr_nvalue_table *nvalue_table; + struct voltagedomain *voltdm; + struct dentry *dbg_dir; + unsigned int irq; int srid; int ip_type; int nvalue_count; @@ -49,13 +55,7 @@ struct omap_sr { u32 senp_avgweight; u32 senp_mod; u32 senn_mod; - unsigned int irq; void __iomem *base; - struct platform_device *pdev; - struct list_head node; - struct omap_sr_nvalue_table *nvalue_table; - struct voltagedomain *voltdm; - struct dentry *dbg_dir; }; /* sr_list contains all the instances of smartreflex module */ @@ -74,10 +74,6 @@ static inline void sr_modify_reg(struct omap_sr *sr, unsigned offset, u32 mask, u32 value) { u32 reg_val; - u32 errconfig_offs = 0, errconfig_mask = 0; - - reg_val = __raw_readl(sr->base + offset); - reg_val &= ~mask; /* * Smartreflex error config register is special as it contains @@ -88,16 +84,15 @@ static inline void sr_modify_reg(struct omap_sr *sr, unsigned offset, u32 mask, * if they are currently set, but does allow the caller to write * those bits. */ - if (sr->ip_type == SR_TYPE_V1) { - errconfig_offs = ERRCONFIG_V1; - errconfig_mask = ERRCONFIG_STATUS_V1_MASK; - } else if (sr->ip_type == SR_TYPE_V2) { - errconfig_offs = ERRCONFIG_V2; - errconfig_mask = ERRCONFIG_VPBOUNDINTST_V2; - } + if (sr->ip_type == SR_TYPE_V1 && offset == ERRCONFIG_V1) + mask |= ERRCONFIG_STATUS_V1_MASK; + else if (sr->ip_type == SR_TYPE_V2 && offset == ERRCONFIG_V2) + mask |= ERRCONFIG_VPBOUNDINTST_V2; + + reg_val = __raw_readl(sr->base + offset); + reg_val &= ~mask; - if (offset == errconfig_offs) - reg_val &= ~errconfig_mask; + value &= mask; reg_val |= value; @@ -128,21 +123,28 @@ static struct omap_sr *_sr_lookup(struct voltagedomain *voltdm) static irqreturn_t sr_interrupt(int irq, void *data) { - struct omap_sr *sr_info = (struct omap_sr *)data; + struct omap_sr *sr_info = data; u32 status = 0; - if (sr_info->ip_type == SR_TYPE_V1) { + switch (sr_info->ip_type) { + case SR_TYPE_V1: /* Read the status bits */ status = sr_read_reg(sr_info, ERRCONFIG_V1); /* Clear them by writing back */ sr_write_reg(sr_info, ERRCONFIG_V1, status); - } else if (sr_info->ip_type == SR_TYPE_V2) { + break; + case SR_TYPE_V2: /* Read the status bits */ status = sr_read_reg(sr_info, IRQSTATUS); /* Clear them by writing back */ sr_write_reg(sr_info, IRQSTATUS, status); + break; + default: + dev_err(&sr_info->pdev->dev, "UNKNOWN IP type %d\n", + sr_info->ip_type); + return IRQ_NONE; } if (sr_class->notify) @@ -166,6 +168,7 @@ static void sr_set_clk_length(struct omap_sr *sr) __func__); return; } + sys_clk_speed = clk_get_rate(sys_ck); clk_put(sys_ck); @@ -267,7 +270,7 @@ static int sr_late_init(struct omap_sr *sr_info) goto error; } ret = request_irq(sr_info->irq, sr_interrupt, - 0, name, (void *)sr_info); + 0, name, sr_info); if (ret) goto error; disable_irq(sr_info->irq); @@ -288,12 +291,15 @@ error: "not function as desired\n", __func__); kfree(name); kfree(sr_info); + return ret; } static void sr_v1_disable(struct omap_sr *sr) { int timeout = 0; + int errconf_val = ERRCONFIG_MCUACCUMINTST | ERRCONFIG_MCUVALIDINTST | + ERRCONFIG_MCUBOUNDINTST; /* Enable MCUDisableAcknowledge interrupt */ sr_modify_reg(sr, ERRCONFIG_V1, @@ -302,13 +308,13 @@ static void sr_v1_disable(struct omap_sr *sr) /* SRCONFIG - disable SR */ sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0); - /* Disable all other SR interrupts and clear the status */ + /* Disable all other SR interrupts and clear the status as needed */ + if (sr_read_reg(sr, ERRCONFIG_V1) & ERRCONFIG_VPBOUNDINTST_V1) + errconf_val |= ERRCONFIG_VPBOUNDINTST_V1; sr_modify_reg(sr, ERRCONFIG_V1, (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN | ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_VPBOUNDINTEN_V1), - (ERRCONFIG_MCUACCUMINTST | ERRCONFIG_MCUVALIDINTST | - ERRCONFIG_MCUBOUNDINTST | - ERRCONFIG_VPBOUNDINTST_V1)); + errconf_val); /* * Wait for SR to be disabled. @@ -337,9 +343,17 @@ static void sr_v2_disable(struct omap_sr *sr) /* SRCONFIG - disable SR */ sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0); - /* Disable all other SR interrupts and clear the status */ - sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2, + /* + * Disable all other SR interrupts and clear the status + * write to status register ONLY on need basis - only if status + * is set. + */ + if (sr_read_reg(sr, ERRCONFIG_V2) & ERRCONFIG_VPBOUNDINTST_V2) + sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2, ERRCONFIG_VPBOUNDINTST_V2); + else + sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2, + 0x0); sr_write_reg(sr, IRQENABLE_CLR, (IRQENABLE_MCUACCUMINT | IRQENABLE_MCUVALIDINT | IRQENABLE_MCUBOUNDSINT)); @@ -398,15 +412,16 @@ static u32 sr_retrieve_nvalue(struct omap_sr *sr, u32 efuse_offs) */ int sr_configure_errgen(struct voltagedomain *voltdm) { - u32 sr_config, sr_errconfig, errconfig_offs, vpboundint_en; - u32 vpboundint_st, senp_en = 0, senn_en = 0; + u32 sr_config, sr_errconfig, errconfig_offs; + u32 vpboundint_en, vpboundint_st; + u32 senp_en = 0, senn_en = 0; u8 senp_shift, senn_shift; struct omap_sr *sr = _sr_lookup(voltdm); if (IS_ERR(sr)) { pr_warning("%s: omap_sr struct for sr_%s not found\n", __func__, voltdm->name); - return -EINVAL; + return PTR_ERR(sr); } if (!sr->clk_length) @@ -418,20 +433,23 @@ int sr_configure_errgen(struct voltagedomain *voltdm) sr_config = (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) | SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN; - if (sr->ip_type == SR_TYPE_V1) { + switch (sr->ip_type) { + case SR_TYPE_V1: sr_config |= SRCONFIG_DELAYCTRL; senn_shift = SRCONFIG_SENNENABLE_V1_SHIFT; senp_shift = SRCONFIG_SENPENABLE_V1_SHIFT; errconfig_offs = ERRCONFIG_V1; vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V1; vpboundint_st = ERRCONFIG_VPBOUNDINTST_V1; - } else if (sr->ip_type == SR_TYPE_V2) { + break; + case SR_TYPE_V2: senn_shift = SRCONFIG_SENNENABLE_V2_SHIFT; senp_shift = SRCONFIG_SENPENABLE_V2_SHIFT; errconfig_offs = ERRCONFIG_V2; vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V2; vpboundint_st = ERRCONFIG_VPBOUNDINTST_V2; - } else { + break; + default: dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex" "module without specifying the ip\n", __func__); return -EINVAL; @@ -447,8 +465,55 @@ int sr_configure_errgen(struct voltagedomain *voltdm) sr_errconfig); /* Enabling the interrupts if the ERROR module is used */ - sr_modify_reg(sr, errconfig_offs, - vpboundint_en, (vpboundint_en | vpboundint_st)); + sr_modify_reg(sr, errconfig_offs, (vpboundint_en | vpboundint_st), + vpboundint_en); + + return 0; +} + +/** + * sr_disable_errgen() - Disables SmartReflex AVS module's errgen component + * @voltdm: VDD pointer to which the SR module to be configured belongs to. + * + * This API is to be called from the smartreflex class driver to + * disable the error generator module inside the smartreflex module. + * + * Returns 0 on success and error value in case of failure. + */ +int sr_disable_errgen(struct voltagedomain *voltdm) +{ + u32 errconfig_offs; + u32 vpboundint_en, vpboundint_st; + struct omap_sr *sr = _sr_lookup(voltdm); + + if (IS_ERR(sr)) { + pr_warning("%s: omap_sr struct for sr_%s not found\n", + __func__, voltdm->name); + return PTR_ERR(sr); + } + + switch (sr->ip_type) { + case SR_TYPE_V1: + errconfig_offs = ERRCONFIG_V1; + vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V1; + vpboundint_st = ERRCONFIG_VPBOUNDINTST_V1; + break; + case SR_TYPE_V2: + errconfig_offs = ERRCONFIG_V2; + vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V2; + vpboundint_st = ERRCONFIG_VPBOUNDINTST_V2; + break; + default: + dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex" + "module without specifying the ip\n", __func__); + return -EINVAL; + } + + /* Disable the interrupts of ERROR module */ + sr_modify_reg(sr, errconfig_offs, vpboundint_en | vpboundint_st, 0); + + /* Disable the Sensor and errorgen */ + sr_modify_reg(sr, SRCONFIG, SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN, 0); return 0; } @@ -475,7 +540,7 @@ int sr_configure_minmax(struct voltagedomain *voltdm) if (IS_ERR(sr)) { pr_warning("%s: omap_sr struct for sr_%s not found\n", __func__, voltdm->name); - return -EINVAL; + return PTR_ERR(sr); } if (!sr->clk_length) @@ -488,14 +553,17 @@ int sr_configure_minmax(struct voltagedomain *voltdm) SRCONFIG_SENENABLE | (sr->accum_data << SRCONFIG_ACCUMDATA_SHIFT); - if (sr->ip_type == SR_TYPE_V1) { + switch (sr->ip_type) { + case SR_TYPE_V1: sr_config |= SRCONFIG_DELAYCTRL; senn_shift = SRCONFIG_SENNENABLE_V1_SHIFT; senp_shift = SRCONFIG_SENPENABLE_V1_SHIFT; - } else if (sr->ip_type == SR_TYPE_V2) { + break; + case SR_TYPE_V2: senn_shift = SRCONFIG_SENNENABLE_V2_SHIFT; senp_shift = SRCONFIG_SENPENABLE_V2_SHIFT; - } else { + break; + default: dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex" "module without specifying the ip\n", __func__); return -EINVAL; @@ -511,20 +579,27 @@ int sr_configure_minmax(struct voltagedomain *voltdm) * Enabling the interrupts if MINMAXAVG module is used. * TODO: check if all the interrupts are mandatory */ - if (sr->ip_type == SR_TYPE_V1) { + switch (sr->ip_type) { + case SR_TYPE_V1: sr_modify_reg(sr, ERRCONFIG_V1, (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN | ERRCONFIG_MCUBOUNDINTEN), (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUACCUMINTST | ERRCONFIG_MCUVALIDINTEN | ERRCONFIG_MCUVALIDINTST | ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_MCUBOUNDINTST)); - } else if (sr->ip_type == SR_TYPE_V2) { + break; + case SR_TYPE_V2: sr_write_reg(sr, IRQSTATUS, IRQSTATUS_MCUACCUMINT | IRQSTATUS_MCVALIDINT | IRQSTATUS_MCBOUNDSINT | IRQSTATUS_MCUDISABLEACKINT); sr_write_reg(sr, IRQENABLE_SET, IRQENABLE_MCUACCUMINT | IRQENABLE_MCUVALIDINT | IRQENABLE_MCUBOUNDSINT | IRQENABLE_MCUDISABLEACKINT); + break; + default: + dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex" + "module without specifying the ip\n", __func__); + return -EINVAL; } return 0; @@ -543,15 +618,15 @@ int sr_configure_minmax(struct voltagedomain *voltdm) */ int sr_enable(struct voltagedomain *voltdm, unsigned long volt) { - u32 nvalue_reciprocal; struct omap_volt_data *volt_data; struct omap_sr *sr = _sr_lookup(voltdm); + u32 nvalue_reciprocal; int ret; if (IS_ERR(sr)) { pr_warning("%s: omap_sr struct for sr_%s not found\n", __func__, voltdm->name); - return -EINVAL; + return PTR_ERR(sr); } volt_data = omap_voltage_get_voltdata(sr->voltdm, volt); @@ -559,7 +634,7 @@ int sr_enable(struct voltagedomain *voltdm, unsigned long volt) if (IS_ERR(volt_data)) { dev_warn(&sr->pdev->dev, "%s: Unable to get voltage table" "for nominal voltage %ld\n", __func__, volt); - return -ENODATA; + return PTR_ERR(volt_data); } nvalue_reciprocal = sr_retrieve_nvalue(sr, volt_data->sr_efuse_offs); @@ -617,10 +692,17 @@ void sr_disable(struct voltagedomain *voltdm) * disable the clocks. */ if (sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE) { - if (sr->ip_type == SR_TYPE_V1) + switch (sr->ip_type) { + case SR_TYPE_V1: sr_v1_disable(sr); - else if (sr->ip_type == SR_TYPE_V2) + break; + case SR_TYPE_V2: sr_v2_disable(sr); + break; + default: + dev_err(&sr->pdev->dev, "UNKNOWN IP type %d\n", + sr->ip_type); + } } pm_runtime_put_sync_suspend(&sr->pdev->dev); @@ -779,10 +861,10 @@ void omap_sr_register_pmic(struct omap_sr_pmic_data *pmic_data) sr_pmic_data = pmic_data; } -/* PM Debug Fs enteries to enable disable smartreflex. */ +/* PM Debug FS entries to enable and disable smartreflex. */ static int omap_sr_autocomp_show(void *data, u64 *val) { - struct omap_sr *sr_info = (struct omap_sr *) data; + struct omap_sr *sr_info = data; if (!sr_info) { pr_warning("%s: omap_sr struct not found\n", __func__); @@ -796,7 +878,7 @@ static int omap_sr_autocomp_show(void *data, u64 *val) static int omap_sr_autocomp_store(void *data, u64 val) { - struct omap_sr *sr_info = (struct omap_sr *) data; + struct omap_sr *sr_info = data; if (!sr_info) { pr_warning("%s: omap_sr struct not found\n", __func__); @@ -804,7 +886,7 @@ static int omap_sr_autocomp_store(void *data, u64 val) } /* Sanity check */ - if (val && (val != 1)) { + if (val > 1) { pr_warning("%s: Invalid argument %lld\n", __func__, val); return -EINVAL; } @@ -821,11 +903,11 @@ static int omap_sr_autocomp_store(void *data, u64 val) } DEFINE_SIMPLE_ATTRIBUTE(pm_sr_fops, omap_sr_autocomp_show, - omap_sr_autocomp_store, "%llu\n"); + omap_sr_autocomp_store, "%llu\n"); static int __init omap_sr_probe(struct platform_device *pdev) { - struct omap_sr *sr_info = kzalloc(sizeof(struct omap_sr), GFP_KERNEL); + struct omap_sr *sr_info; struct omap_sr_data *pdata = pdev->dev.platform_data; struct resource *mem, *irq; struct dentry *nvalue_dir; @@ -833,12 +915,15 @@ static int __init omap_sr_probe(struct platform_device *pdev) int i, ret = 0; char *name; + sr_info = kzalloc(sizeof(struct omap_sr), GFP_KERNEL); if (!sr_info) { dev_err(&pdev->dev, "%s: unable to allocate sr_info\n", __func__); return -ENOMEM; } + platform_set_drvdata(pdev, sr_info); + if (!pdata) { dev_err(&pdev->dev, "%s: platform data missing\n", __func__); ret = -EINVAL; @@ -904,7 +989,7 @@ static int __init omap_sr_probe(struct platform_device *pdev) dev_info(&pdev->dev, "%s: SmartReflex driver initialized\n", __func__); if (!sr_dbg_dir) { sr_dbg_dir = debugfs_create_dir("smartreflex", NULL); - if (!sr_dbg_dir) { + if (IS_ERR_OR_NULL(sr_dbg_dir)) { ret = PTR_ERR(sr_dbg_dir); pr_err("%s:sr debugfs dir creation failed(%d)\n", __func__, ret); @@ -921,7 +1006,7 @@ static int __init omap_sr_probe(struct platform_device *pdev) } sr_info->dbg_dir = debugfs_create_dir(name, sr_dbg_dir); kfree(name); - if (IS_ERR(sr_info->dbg_dir)) { + if (IS_ERR_OR_NULL(sr_info->dbg_dir)) { dev_err(&pdev->dev, "%s: Unable to create debugfs directory\n", __func__); ret = PTR_ERR(sr_info->dbg_dir); @@ -938,7 +1023,7 @@ static int __init omap_sr_probe(struct platform_device *pdev) &sr_info->err_minlimit); nvalue_dir = debugfs_create_dir("nvalue", sr_info->dbg_dir); - if (IS_ERR(nvalue_dir)) { + if (IS_ERR_OR_NULL(nvalue_dir)) { dev_err(&pdev->dev, "%s: Unable to create debugfs directory" "for n-values\n", __func__); ret = PTR_ERR(nvalue_dir); @@ -994,7 +1079,7 @@ static int __devexit omap_sr_remove(struct platform_device *pdev) if (IS_ERR(sr_info)) { dev_warn(&pdev->dev, "%s: omap_sr struct not found\n", __func__); - return -EINVAL; + return PTR_ERR(sr_info); } if (sr_info->autocomp_active) @@ -1011,8 +1096,32 @@ static int __devexit omap_sr_remove(struct platform_device *pdev) return 0; } +static void __devexit omap_sr_shutdown(struct platform_device *pdev) +{ + struct omap_sr_data *pdata = pdev->dev.platform_data; + struct omap_sr *sr_info; + + if (!pdata) { + dev_err(&pdev->dev, "%s: platform data missing\n", __func__); + return; + } + + sr_info = _sr_lookup(pdata->voltdm); + if (IS_ERR(sr_info)) { + dev_warn(&pdev->dev, "%s: omap_sr struct not found\n", + __func__); + return; + } + + if (sr_info->autocomp_active) + sr_stop_vddautocomp(sr_info); + + return; +} + static struct platform_driver smartreflex_driver = { .remove = __devexit_p(omap_sr_remove), + .shutdown = __devexit_p(omap_sr_shutdown), .driver = { .name = "smartreflex", }, @@ -1042,12 +1151,12 @@ static int __init sr_init(void) return 0; } +late_initcall(sr_init); static void __exit sr_exit(void) { platform_driver_unregister(&smartreflex_driver); } -late_initcall(sr_init); module_exit(sr_exit); MODULE_DESCRIPTION("OMAP Smartreflex Driver"); diff --git a/arch/arm/mach-omap2/smartreflex.h b/arch/arm/mach-omap2/smartreflex.h index 5f35b9e..5809141 100644 --- a/arch/arm/mach-omap2/smartreflex.h +++ b/arch/arm/mach-omap2/smartreflex.h @@ -152,6 +152,15 @@ struct omap_sr_pmic_data { void (*sr_pmic_init) (void); }; +/** + * struct omap_smartreflex_dev_attr - Smartreflex Device attribute. + * + * @sensor_voltdm_name: Name of voltdomain of SR instance + */ +struct omap_smartreflex_dev_attr { + const char *sensor_voltdm_name; +}; + #ifdef CONFIG_OMAP_SMARTREFLEX /* * The smart reflex driver supports CLASS1 CLASS2 and CLASS3 SR. @@ -231,6 +240,7 @@ void omap_sr_register_pmic(struct omap_sr_pmic_data *pmic_data); int sr_enable(struct voltagedomain *voltdm, unsigned long volt); void sr_disable(struct voltagedomain *voltdm); int sr_configure_errgen(struct voltagedomain *voltdm); +int sr_disable_errgen(struct voltagedomain *voltdm); int sr_configure_minmax(struct voltagedomain *voltdm); /* API to register the smartreflex class driver with the smartreflex driver */ diff --git a/arch/arm/mach-omap2/sr_device.c b/arch/arm/mach-omap2/sr_device.c index 78c9437..a503e1e 100644 --- a/arch/arm/mach-omap2/sr_device.c +++ b/arch/arm/mach-omap2/sr_device.c @@ -74,6 +74,7 @@ static int __init sr_dev_init(struct omap_hwmod *oh, void *user) struct omap_sr_data *sr_data; struct platform_device *pdev; struct omap_volt_data *volt_data; + struct omap_smartreflex_dev_attr *sr_dev_attr; char *name = "smartreflex"; static int i; @@ -84,9 +85,11 @@ static int __init sr_dev_init(struct omap_hwmod *oh, void *user) return -ENOMEM; } - if (!oh->vdd_name) { + sr_dev_attr = (struct omap_smartreflex_dev_attr *)oh->dev_attr; + if (!sr_dev_attr || !sr_dev_attr->sensor_voltdm_name) { pr_err("%s: No voltage domain specified for %s." - "Cannot initialize\n", __func__, oh->name); + "Cannot initialize\n", __func__, + oh->name); goto exit; } @@ -94,10 +97,10 @@ static int __init sr_dev_init(struct omap_hwmod *oh, void *user) sr_data->senn_mod = 0x1; sr_data->senp_mod = 0x1; - sr_data->voltdm = voltdm_lookup(oh->vdd_name); + sr_data->voltdm = voltdm_lookup(sr_dev_attr->sensor_voltdm_name); if (IS_ERR(sr_data->voltdm)) { pr_err("%s: Unable to get voltage domain pointer for VDD %s\n", - __func__, oh->vdd_name); + __func__, sr_dev_attr->sensor_voltdm_name); goto exit; } diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c index 5bc1312..84f2d701 100644 --- a/arch/arm/mach-pxa/devices.c +++ b/arch/arm/mach-pxa/devices.c @@ -406,20 +406,17 @@ static struct resource pxa_rtc_resources[] = { [1] = { .start = IRQ_RTC1Hz, .end = IRQ_RTC1Hz, + .name = "rtc 1Hz", .flags = IORESOURCE_IRQ, }, [2] = { .start = IRQ_RTCAlrm, .end = IRQ_RTCAlrm, + .name = "rtc alarm", .flags = IORESOURCE_IRQ, }, }; -struct platform_device sa1100_device_rtc = { - .name = "sa1100-rtc", - .id = -1, -}; - struct platform_device pxa_device_rtc = { .name = "pxa-rtc", .id = -1, @@ -427,6 +424,27 @@ struct platform_device pxa_device_rtc = { .resource = pxa_rtc_resources, }; +static struct resource sa1100_rtc_resources[] = { + { + .start = IRQ_RTC1Hz, + .end = IRQ_RTC1Hz, + .name = "rtc 1Hz", + .flags = IORESOURCE_IRQ, + }, { + .start = IRQ_RTCAlrm, + .end = IRQ_RTCAlrm, + .name = "rtc alarm", + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device sa1100_device_rtc = { + .name = "sa1100-rtc", + .id = -1, + .num_resources = ARRAY_SIZE(sa1100_rtc_resources), + .resource = sa1100_rtc_resources, +}; + static struct resource pxa_ac97_resources[] = { [0] = { .start = 0x40500000, diff --git a/arch/arm/mach-pxa/hx4700.c b/arch/arm/mach-pxa/hx4700.c index f309bf9..3fa929d 100644 --- a/arch/arm/mach-pxa/hx4700.c +++ b/arch/arm/mach-pxa/hx4700.c @@ -28,7 +28,8 @@ #include <linux/mtd/physmap.h> #include <linux/pda_power.h> #include <linux/pwm_backlight.h> -#include <linux/regulator/bq24022.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/gpio-regulator.h> #include <linux/regulator/machine.h> #include <linux/regulator/max1586.h> #include <linux/spi/ads7846.h> @@ -698,14 +699,34 @@ static struct regulator_init_data bq24022_init_data = { .consumer_supplies = bq24022_consumers, }; -static struct bq24022_mach_info bq24022_info = { - .gpio_nce = GPIO72_HX4700_BQ24022_nCHARGE_EN, - .gpio_iset2 = GPIO96_HX4700_BQ24022_ISET2, - .init_data = &bq24022_init_data, +static struct gpio bq24022_gpios[] = { + { GPIO96_HX4700_BQ24022_ISET2, GPIOF_OUT_INIT_LOW, "bq24022_iset2" }, +}; + +static struct gpio_regulator_state bq24022_states[] = { + { .value = 100000, .gpios = (0 << 0) }, + { .value = 500000, .gpios = (1 << 0) }, +}; + +static struct gpio_regulator_config bq24022_info = { + .supply_name = "bq24022", + + .enable_gpio = GPIO72_HX4700_BQ24022_nCHARGE_EN, + .enable_high = 0, + .enabled_at_boot = 0, + + .gpios = bq24022_gpios, + .nr_gpios = ARRAY_SIZE(bq24022_gpios), + + .states = bq24022_states, + .nr_states = ARRAY_SIZE(bq24022_states), + + .type = REGULATOR_CURRENT, + .init_data = &bq24022_init_data, }; static struct platform_device bq24022 = { - .name = "bq24022", + .name = "gpio-regulator", .id = -1, .dev = { .platform_data = &bq24022_info, diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c index 3d6baf9..5e26f3e 100644 --- a/arch/arm/mach-pxa/magician.c +++ b/arch/arm/mach-pxa/magician.c @@ -25,7 +25,8 @@ #include <linux/mtd/physmap.h> #include <linux/pda_power.h> #include <linux/pwm_backlight.h> -#include <linux/regulator/bq24022.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/gpio-regulator.h> #include <linux/regulator/machine.h> #include <linux/usb/gpio_vbus.h> #include <linux/i2c/pxa-i2c.h> @@ -596,14 +597,34 @@ static struct regulator_init_data bq24022_init_data = { .consumer_supplies = bq24022_consumers, }; -static struct bq24022_mach_info bq24022_info = { - .gpio_nce = GPIO30_MAGICIAN_BQ24022_nCHARGE_EN, - .gpio_iset2 = EGPIO_MAGICIAN_BQ24022_ISET2, - .init_data = &bq24022_init_data, +static struct gpio bq24022_gpios[] = { + { EGPIO_MAGICIAN_BQ24022_ISET2, GPIOF_OUT_INIT_LOW, "bq24022_iset2" }, +}; + +static struct gpio_regulator_state bq24022_states[] = { + { .value = 100000, .gpios = (0 << 0) }, + { .value = 500000, .gpios = (1 << 0) }, +}; + +static struct gpio_regulator_config bq24022_info = { + .supply_name = "bq24022", + + .enable_gpio = GPIO30_MAGICIAN_BQ24022_nCHARGE_EN, + .enable_high = 0, + .enabled_at_boot = 0, + + .gpios = bq24022_gpios, + .nr_gpios = ARRAY_SIZE(bq24022_gpios), + + .states = bq24022_states, + .nr_states = ARRAY_SIZE(bq24022_states), + + .type = REGULATOR_CURRENT, + .init_data = &bq24022_init_data, }; static struct platform_device bq24022 = { - .name = "bq24022", + .name = "gpio-regulator", .id = -1, .dev = { .platform_data = &bq24022_info, diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c index 3918a67..1570d45 100644 --- a/arch/arm/mach-pxa/pxa3xx.c +++ b/arch/arm/mach-pxa/pxa3xx.c @@ -89,6 +89,7 @@ static struct clk_lookup pxa3xx_clkregs[] = { INIT_CLKREG(&clk_pxa3xx_mmc2, "pxa2xx-mci.1", NULL), INIT_CLKREG(&clk_pxa3xx_smemc, "pxa2xx-pcmcia", NULL), INIT_CLKREG(&clk_pxa3xx_gpio, "pxa-gpio", NULL), + INIT_CLKREG(&clk_dummy, "sa1100-rtc", NULL), }; #ifdef CONFIG_PM diff --git a/arch/arm/mach-pxa/pxa95x.c b/arch/arm/mach-pxa/pxa95x.c index 5ce434b..47601f8 100644 --- a/arch/arm/mach-pxa/pxa95x.c +++ b/arch/arm/mach-pxa/pxa95x.c @@ -231,6 +231,7 @@ static struct clk_lookup pxa95x_clkregs[] = { INIT_CLKREG(&clk_pxa95x_pwm0, "pxa27x-pwm.0", NULL), INIT_CLKREG(&clk_pxa95x_pwm1, "pxa27x-pwm.1", NULL), INIT_CLKREG(&clk_pxa95x_gpio, "pxa-gpio", NULL), + INIT_CLKREG(&clk_dummy, "sa1100-rtc", NULL), }; void __init pxa95x_init_irq(void) diff --git a/arch/arm/mach-s3c24xx/s3c2416.c b/arch/arm/mach-s3c24xx/s3c2416.c index 08bb035..0e9a71c 100644 --- a/arch/arm/mach-s3c24xx/s3c2416.c +++ b/arch/arm/mach-s3c24xx/s3c2416.c @@ -59,6 +59,7 @@ #include <plat/fb-core.h> #include <plat/nand-core.h> #include <plat/adc-core.h> +#include <plat/rtc-core.h> static struct map_desc s3c2416_iodesc[] __initdata = { IODESC_ENT(WATCHDOG), @@ -98,6 +99,7 @@ int __init s3c2416_init(void) s3c_fb_setname("s3c2443-fb"); s3c_adc_setname("s3c2416-adc"); + s3c_rtc_setname("s3c2416-rtc"); #ifdef CONFIG_PM register_syscore_ops(&s3c2416_pm_syscore_ops); diff --git a/arch/arm/mach-s3c24xx/s3c2443.c b/arch/arm/mach-s3c24xx/s3c2443.c index b9deaeb..b7778a9 100644 --- a/arch/arm/mach-s3c24xx/s3c2443.c +++ b/arch/arm/mach-s3c24xx/s3c2443.c @@ -41,6 +41,7 @@ #include <plat/fb-core.h> #include <plat/nand-core.h> #include <plat/adc-core.h> +#include <plat/rtc-core.h> static struct map_desc s3c2443_iodesc[] __initdata = { IODESC_ENT(WATCHDOG), @@ -73,6 +74,7 @@ int __init s3c2443_init(void) s3c_fb_setname("s3c2443-fb"); s3c_adc_setname("s3c2443-adc"); + s3c_rtc_setname("s3c2443-rtc"); /* change WDT IRQ number */ s3c_device_wdt.resource[1].start = IRQ_S3C2443_WDT; diff --git a/arch/arm/mach-sa1100/clock.c b/arch/arm/mach-sa1100/clock.c index dab3c63..172ebd0 100644 --- a/arch/arm/mach-sa1100/clock.c +++ b/arch/arm/mach-sa1100/clock.c @@ -11,17 +11,29 @@ #include <linux/clk.h> #include <linux/spinlock.h> #include <linux/mutex.h> +#include <linux/io.h> +#include <linux/clkdev.h> #include <mach/hardware.h> -/* - * Very simple clock implementation - we only have one clock to deal with. - */ +struct clkops { + void (*enable)(struct clk *); + void (*disable)(struct clk *); +}; + struct clk { + const struct clkops *ops; unsigned int enabled; }; -static void clk_gpio27_enable(void) +#define DEFINE_CLK(_name, _ops) \ +struct clk clk_##_name = { \ + .ops = _ops, \ + } + +static DEFINE_SPINLOCK(clocks_lock); + +static void clk_gpio27_enable(struct clk *clk) { /* * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111: @@ -32,38 +44,24 @@ static void clk_gpio27_enable(void) TUCR = TUCR_3_6864MHz; } -static void clk_gpio27_disable(void) +static void clk_gpio27_disable(struct clk *clk) { TUCR = 0; GPDR &= ~GPIO_32_768kHz; GAFR &= ~GPIO_32_768kHz; } -static struct clk clk_gpio27; - -static DEFINE_SPINLOCK(clocks_lock); - -struct clk *clk_get(struct device *dev, const char *id) -{ - const char *devname = dev_name(dev); - - return strcmp(devname, "sa1111.0") ? ERR_PTR(-ENOENT) : &clk_gpio27; -} -EXPORT_SYMBOL(clk_get); - -void clk_put(struct clk *clk) -{ -} -EXPORT_SYMBOL(clk_put); - int clk_enable(struct clk *clk) { unsigned long flags; - spin_lock_irqsave(&clocks_lock, flags); - if (clk->enabled++ == 0) - clk_gpio27_enable(); - spin_unlock_irqrestore(&clocks_lock, flags); + if (clk) { + spin_lock_irqsave(&clocks_lock, flags); + if (clk->enabled++ == 0) + clk->ops->enable(clk); + spin_unlock_irqrestore(&clocks_lock, flags); + } + return 0; } EXPORT_SYMBOL(clk_enable); @@ -72,17 +70,31 @@ void clk_disable(struct clk *clk) { unsigned long flags; - WARN_ON(clk->enabled == 0); - - spin_lock_irqsave(&clocks_lock, flags); - if (--clk->enabled == 0) - clk_gpio27_disable(); - spin_unlock_irqrestore(&clocks_lock, flags); + if (clk) { + WARN_ON(clk->enabled == 0); + spin_lock_irqsave(&clocks_lock, flags); + if (--clk->enabled == 0) + clk->ops->disable(clk); + spin_unlock_irqrestore(&clocks_lock, flags); + } } EXPORT_SYMBOL(clk_disable); -unsigned long clk_get_rate(struct clk *clk) +const struct clkops clk_gpio27_ops = { + .enable = clk_gpio27_enable, + .disable = clk_gpio27_disable, +}; + +static DEFINE_CLK(gpio27, &clk_gpio27_ops); + +static struct clk_lookup sa11xx_clkregs[] = { + CLKDEV_INIT("sa1111.0", NULL, &clk_gpio27), + CLKDEV_INIT("sa1100-rtc", NULL, NULL), +}; + +static int __init sa11xx_clk_init(void) { - return 3686400; + clkdev_add_table(sa11xx_clkregs, ARRAY_SIZE(sa11xx_clkregs)); + return 0; } -EXPORT_SYMBOL(clk_get_rate); +core_initcall(sa11xx_clk_init); diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index bb10ee2..7c1ebf4 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c @@ -345,9 +345,17 @@ void sa11x0_register_irda(struct irda_platform_data *irda) sa11x0_register_device(&sa11x0ir_device, irda); } +static struct resource sa1100_rtc_resources[] = { + DEFINE_RES_MEM(0x90010000, 0x9001003f), + DEFINE_RES_IRQ_NAMED(IRQ_RTC1Hz, "rtc 1Hz"), + DEFINE_RES_IRQ_NAMED(IRQ_RTCAlrm, "rtc alarm"), +}; + static struct platform_device sa11x0rtc_device = { .name = "sa1100-rtc", .id = -1, + .num_resources = ARRAY_SIZE(sa1100_rtc_resources), + .resource = sa1100_rtc_resources, }; static struct platform_device *sa11x0_devices[] __initdata = { diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index 76a79b8..1dd2726 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -7,6 +7,7 @@ obj-y += clock.o obj-y += timer.o obj-y += pinmux.o obj-y += fuse.o +obj-y += pmc.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_CPU_IDLE) += sleep.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += powergate.o @@ -18,7 +19,7 @@ obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += board-dt-tegra30.o obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o -obj-$(CONFIG_TEGRA_SYSTEM_DMA) += dma.o +obj-$(CONFIG_TEGRA_SYSTEM_DMA) += dma.o apbio.o obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o obj-$(CONFIG_TEGRA_PCI) += pcie.o obj-$(CONFIG_USB_SUPPORT) += usb_phy.o diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c new file mode 100644 index 0000000..e75451e --- /dev/null +++ b/arch/arm/mach-tegra/apbio.c @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2010 NVIDIA Corporation. + * Copyright (C) 2010 Google, Inc. + * + * 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/io.h> +#include <linux/dma-mapping.h> +#include <linux/spinlock.h> +#include <linux/completion.h> +#include <linux/sched.h> +#include <linux/mutex.h> + +#include <mach/dma.h> +#include <mach/iomap.h> + +#include "apbio.h" + +static DEFINE_MUTEX(tegra_apb_dma_lock); + +static struct tegra_dma_channel *tegra_apb_dma; +static u32 *tegra_apb_bb; +static dma_addr_t tegra_apb_bb_phys; +static DECLARE_COMPLETION(tegra_apb_wait); + +bool tegra_apb_init(void) +{ + struct tegra_dma_channel *ch; + + mutex_lock(&tegra_apb_dma_lock); + + /* Check to see if we raced to setup */ + if (tegra_apb_dma) + goto out; + + ch = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT | + TEGRA_DMA_SHARED); + + if (!ch) + goto out_fail; + + tegra_apb_bb = dma_alloc_coherent(NULL, sizeof(u32), + &tegra_apb_bb_phys, GFP_KERNEL); + if (!tegra_apb_bb) { + pr_err("%s: can not allocate bounce buffer\n", __func__); + tegra_dma_free_channel(ch); + goto out_fail; + } + + tegra_apb_dma = ch; +out: + mutex_unlock(&tegra_apb_dma_lock); + return true; + +out_fail: + mutex_unlock(&tegra_apb_dma_lock); + return false; +} + +static void apb_dma_complete(struct tegra_dma_req *req) +{ + complete(&tegra_apb_wait); +} + +u32 tegra_apb_readl(unsigned long offset) +{ + struct tegra_dma_req req; + int ret; + + if (!tegra_apb_dma && !tegra_apb_init()) + return readl(IO_TO_VIRT(offset)); + + mutex_lock(&tegra_apb_dma_lock); + req.complete = apb_dma_complete; + req.to_memory = 1; + req.dest_addr = tegra_apb_bb_phys; + req.dest_bus_width = 32; + req.dest_wrap = 1; + req.source_addr = offset; + req.source_bus_width = 32; + req.source_wrap = 4; + req.req_sel = TEGRA_DMA_REQ_SEL_CNTR; + req.size = 4; + + INIT_COMPLETION(tegra_apb_wait); + + tegra_dma_enqueue_req(tegra_apb_dma, &req); + + ret = wait_for_completion_timeout(&tegra_apb_wait, + msecs_to_jiffies(50)); + + if (WARN(ret == 0, "apb read dma timed out")) { + tegra_dma_dequeue_req(tegra_apb_dma, &req); + *(u32 *)tegra_apb_bb = 0; + } + + mutex_unlock(&tegra_apb_dma_lock); + return *((u32 *)tegra_apb_bb); +} + +void tegra_apb_writel(u32 value, unsigned long offset) +{ + struct tegra_dma_req req; + int ret; + + if (!tegra_apb_dma && !tegra_apb_init()) { + writel(value, IO_TO_VIRT(offset)); + return; + } + + mutex_lock(&tegra_apb_dma_lock); + *((u32 *)tegra_apb_bb) = value; + req.complete = apb_dma_complete; + req.to_memory = 0; + req.dest_addr = offset; + req.dest_wrap = 4; + req.dest_bus_width = 32; + req.source_addr = tegra_apb_bb_phys; + req.source_bus_width = 32; + req.source_wrap = 1; + req.req_sel = TEGRA_DMA_REQ_SEL_CNTR; + req.size = 4; + + INIT_COMPLETION(tegra_apb_wait); + + tegra_dma_enqueue_req(tegra_apb_dma, &req); + + ret = wait_for_completion_timeout(&tegra_apb_wait, + msecs_to_jiffies(50)); + + if (WARN(ret == 0, "apb write dma timed out")) + tegra_dma_dequeue_req(tegra_apb_dma, &req); + + mutex_unlock(&tegra_apb_dma_lock); +} diff --git a/arch/arm/mach-tegra/apbio.h b/arch/arm/mach-tegra/apbio.h new file mode 100644 index 0000000..8b49e8c --- /dev/null +++ b/arch/arm/mach-tegra/apbio.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2010 NVIDIA Corporation. + * Copyright (C) 2010 Google, Inc. + * + * 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. + * + */ + +#ifndef __MACH_TEGRA_APBIO_H +#define __MACH_TEGRA_APBIO_H + +#ifdef CONFIG_TEGRA_SYSTEM_DMA + +u32 tegra_apb_readl(unsigned long offset); +void tegra_apb_writel(u32 value, unsigned long offset); + +#else +#include <asm/io.h> +#include <mach/io.h> + +static inline u32 tegra_apb_readl(unsigned long offset) +{ + return readl(IO_TO_VIRT(offset)); +} + +static inline void tegra_apb_writel(u32 value, unsigned long offset) +{ + writel(value, IO_TO_VIRT(offset)); +} +#endif + +#endif diff --git a/arch/arm/mach-tegra/board-harmony-power.c b/arch/arm/mach-tegra/board-harmony-power.c index c0298b3..82f32300 100644 --- a/arch/arm/mach-tegra/board-harmony-power.c +++ b/arch/arm/mach-tegra/board-harmony-power.c @@ -18,18 +18,13 @@ #include <linux/i2c.h> #include <linux/platform_device.h> #include <linux/gpio.h> -#include <linux/io.h> #include <linux/regulator/machine.h> #include <linux/mfd/tps6586x.h> -#include <mach/iomap.h> #include <mach/irqs.h> #include "board-harmony.h" -#define PMC_CTRL 0x0 -#define PMC_CTRL_INTR_LOW (1 << 17) - static struct regulator_consumer_supply tps658621_ldo0_supply[] = { REGULATOR_SUPPLY("pex_clk", NULL), }; @@ -115,16 +110,6 @@ static struct i2c_board_info __initdata harmony_regulators[] = { int __init harmony_regulator_init(void) { - void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); - u32 pmc_ctrl; - - /* - * Configure the power management controller to trigger PMU - * interrupts when low - */ - pmc_ctrl = readl(pmc + PMC_CTRL); - writel(pmc_ctrl | PMC_CTRL_INTR_LOW, pmc + PMC_CTRL); - i2c_register_board_info(3, harmony_regulators, 1); return 0; diff --git a/arch/arm/mach-tegra/board-harmony.c b/arch/arm/mach-tegra/board-harmony.c index 789bdc9..c00aadb 100644 --- a/arch/arm/mach-tegra/board-harmony.c +++ b/arch/arm/mach-tegra/board-harmony.c @@ -101,7 +101,6 @@ static struct wm8903_platform_data harmony_wm8903_pdata = { static struct i2c_board_info __initdata wm8903_board_info = { I2C_BOARD_INFO("wm8903", 0x1a), .platform_data = &harmony_wm8903_pdata, - .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_CDC_IRQ), }; static void __init harmony_i2c_init(void) @@ -111,6 +110,7 @@ static void __init harmony_i2c_init(void) platform_device_register(&tegra_i2c_device3); platform_device_register(&tegra_i2c_device4); + wm8903_board_info.irq = gpio_to_irq(TEGRA_GPIO_CDC_IRQ); i2c_register_board_info(0, &wm8903_board_info, 1); } diff --git a/arch/arm/mach-tegra/board-seaboard.c b/arch/arm/mach-tegra/board-seaboard.c index ebac65f..d669847 100644 --- a/arch/arm/mach-tegra/board-seaboard.c +++ b/arch/arm/mach-tegra/board-seaboard.c @@ -159,7 +159,6 @@ static struct platform_device *seaboard_devices[] __initdata = { static struct i2c_board_info __initdata isl29018_device = { I2C_BOARD_INFO("isl29018", 0x44), - .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_ISL29018_IRQ), }; static struct i2c_board_info __initdata adt7461_device = { @@ -183,7 +182,6 @@ static struct wm8903_platform_data wm8903_pdata = { static struct i2c_board_info __initdata wm8903_device = { I2C_BOARD_INFO("wm8903", 0x1a), .platform_data = &wm8903_pdata, - .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_CDC_IRQ), }; static int seaboard_ehci_init(void) @@ -214,7 +212,10 @@ static void __init seaboard_i2c_init(void) gpio_request(TEGRA_GPIO_ISL29018_IRQ, "isl29018"); gpio_direction_input(TEGRA_GPIO_ISL29018_IRQ); + isl29018_device.irq = gpio_to_irq(TEGRA_GPIO_ISL29018_IRQ); i2c_register_board_info(0, &isl29018_device, 1); + + wm8903_device.irq = gpio_to_irq(TEGRA_GPIO_CDC_IRQ); i2c_register_board_info(0, &wm8903_device, 1); i2c_register_board_info(3, &adt7461_device, 1); diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index 6c93cd0..2f86fcc 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c @@ -31,6 +31,24 @@ #include "board.h" #include "clock.h" #include "fuse.h" +#include "pmc.h" + +/* + * Storage for debug-macro.S's state. + * + * This must be in .data not .bss so that it gets initialized each time the + * kernel is loaded. The data is declared here rather than debug-macro.S so + * that multiple inclusions of debug-macro.S point at the same data. + */ +#define TEGRA_DEBUG_UART_OFFSET (TEGRA_DEBUG_UART_BASE & 0xFFFF) +u32 tegra_uart_config[3] = { + /* Debug UART initialization required */ + 1, + /* Debug UART physical address */ + (u32)(IO_APB_PHYS + TEGRA_DEBUG_UART_OFFSET), + /* Debug UART virtual address */ + (u32)(IO_APB_VIRT + TEGRA_DEBUG_UART_OFFSET), +}; #ifdef CONFIG_OF static const struct of_device_id tegra_dt_irq_match[] __initconst = { @@ -99,6 +117,7 @@ void __init tegra20_init_early(void) tegra2_init_clocks(); tegra_clk_init_from_table(tegra20_clk_init_table); tegra_init_cache(0x331, 0x441); + tegra_pmc_init(); } #endif #ifdef CONFIG_ARCH_TEGRA_3x_SOC @@ -106,5 +125,6 @@ void __init tegra30_init_early(void) { tegra30_init_clocks(); tegra_init_cache(0x441, 0x551); + tegra_pmc_init(); } #endif diff --git a/arch/arm/mach-tegra/dma.c b/arch/arm/mach-tegra/dma.c index c0cf967..abea4f6 100644 --- a/arch/arm/mach-tegra/dma.c +++ b/arch/arm/mach-tegra/dma.c @@ -33,6 +33,8 @@ #include <mach/iomap.h> #include <mach/suspend.h> +#include "apbio.h" + #define APB_DMA_GEN 0x000 #define GEN_ENABLE (1<<31) @@ -50,8 +52,6 @@ #define CSR_ONCE (1<<27) #define CSR_FLOW (1<<21) #define CSR_REQ_SEL_SHIFT 16 -#define CSR_REQ_SEL_MASK (0x1F<<CSR_REQ_SEL_SHIFT) -#define CSR_REQ_SEL_INVALID (31<<CSR_REQ_SEL_SHIFT) #define CSR_WCOUNT_SHIFT 2 #define CSR_WCOUNT_MASK 0xFFFC @@ -133,6 +133,7 @@ struct tegra_dma_channel { static bool tegra_dma_initialized; static DEFINE_MUTEX(tegra_dma_lock); +static DEFINE_SPINLOCK(enable_lock); static DECLARE_BITMAP(channel_usage, NV_DMA_MAX_CHANNELS); static struct tegra_dma_channel dma_channels[NV_DMA_MAX_CHANNELS]; @@ -180,36 +181,94 @@ static void tegra_dma_stop(struct tegra_dma_channel *ch) static int tegra_dma_cancel(struct tegra_dma_channel *ch) { - u32 csr; unsigned long irq_flags; spin_lock_irqsave(&ch->lock, irq_flags); while (!list_empty(&ch->list)) list_del(ch->list.next); - csr = readl(ch->addr + APB_DMA_CHAN_CSR); - csr &= ~CSR_REQ_SEL_MASK; - csr |= CSR_REQ_SEL_INVALID; - writel(csr, ch->addr + APB_DMA_CHAN_CSR); - tegra_dma_stop(ch); spin_unlock_irqrestore(&ch->lock, irq_flags); return 0; } +static unsigned int get_channel_status(struct tegra_dma_channel *ch, + struct tegra_dma_req *req, bool is_stop_dma) +{ + void __iomem *addr = IO_ADDRESS(TEGRA_APB_DMA_BASE); + unsigned int status; + + if (is_stop_dma) { + /* + * STOP the DMA and get the transfer count. + * Getting the transfer count is tricky. + * - Globally disable DMA on all channels + * - Read the channel's status register to know the number + * of pending bytes to be transfered. + * - Stop the dma channel + * - Globally re-enable DMA to resume other transfers + */ + spin_lock(&enable_lock); + writel(0, addr + APB_DMA_GEN); + udelay(20); + status = readl(ch->addr + APB_DMA_CHAN_STA); + tegra_dma_stop(ch); + writel(GEN_ENABLE, addr + APB_DMA_GEN); + spin_unlock(&enable_lock); + if (status & STA_ISE_EOC) { + pr_err("Got Dma Int here clearing"); + writel(status, ch->addr + APB_DMA_CHAN_STA); + } + req->status = TEGRA_DMA_REQ_ERROR_ABORTED; + } else { + status = readl(ch->addr + APB_DMA_CHAN_STA); + } + return status; +} + +/* should be called with the channel lock held */ +static unsigned int dma_active_count(struct tegra_dma_channel *ch, + struct tegra_dma_req *req, unsigned int status) +{ + unsigned int to_transfer; + unsigned int req_transfer_count; + unsigned int bytes_transferred; + + to_transfer = ((status & STA_COUNT_MASK) >> STA_COUNT_SHIFT) + 1; + req_transfer_count = ch->req_transfer_count + 1; + bytes_transferred = req_transfer_count; + if (status & STA_BUSY) + bytes_transferred -= to_transfer; + /* + * In continuous transfer mode, DMA only tracks the count of the + * half DMA buffer. So, if the DMA already finished half the DMA + * then add the half buffer to the completed count. + */ + if (ch->mode & TEGRA_DMA_MODE_CONTINOUS) { + if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL) + bytes_transferred += req_transfer_count; + if (status & STA_ISE_EOC) + bytes_transferred += req_transfer_count; + } + bytes_transferred *= 4; + return bytes_transferred; +} + int tegra_dma_dequeue_req(struct tegra_dma_channel *ch, struct tegra_dma_req *_req) { - unsigned int csr; unsigned int status; struct tegra_dma_req *req = NULL; int found = 0; unsigned long irq_flags; - int to_transfer; - int req_transfer_count; + int stop = 0; spin_lock_irqsave(&ch->lock, irq_flags); + + if (list_entry(ch->list.next, struct tegra_dma_req, node) == _req) + stop = 1; + list_for_each_entry(req, &ch->list, node) { if (req == _req) { list_del(&req->node); @@ -222,47 +281,12 @@ int tegra_dma_dequeue_req(struct tegra_dma_channel *ch, return 0; } - /* STOP the DMA and get the transfer count. - * Getting the transfer count is tricky. - * - Change the source selector to invalid to stop the DMA from - * FIFO to memory. - * - Read the status register to know the number of pending - * bytes to be transferred. - * - Finally stop or program the DMA to the next buffer in the - * list. - */ - csr = readl(ch->addr + APB_DMA_CHAN_CSR); - csr &= ~CSR_REQ_SEL_MASK; - csr |= CSR_REQ_SEL_INVALID; - writel(csr, ch->addr + APB_DMA_CHAN_CSR); - - /* Get the transfer count */ - status = readl(ch->addr + APB_DMA_CHAN_STA); - to_transfer = (status & STA_COUNT_MASK) >> STA_COUNT_SHIFT; - req_transfer_count = ch->req_transfer_count; - req_transfer_count += 1; - to_transfer += 1; - - req->bytes_transferred = req_transfer_count; - - if (status & STA_BUSY) - req->bytes_transferred -= to_transfer; - - /* In continuous transfer mode, DMA only tracks the count of the - * half DMA buffer. So, if the DMA already finished half the DMA - * then add the half buffer to the completed count. - * - * FIXME: There can be a race here. What if the req to - * dequue happens at the same time as the DMA just moved to - * the new buffer and SW didn't yet received the interrupt? - */ - if (ch->mode & TEGRA_DMA_MODE_CONTINOUS) - if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL) - req->bytes_transferred += req_transfer_count; + if (!stop) + goto skip_stop_dma; - req->bytes_transferred *= 4; + status = get_channel_status(ch, req, true); + req->bytes_transferred = dma_active_count(ch, req, status); - tegra_dma_stop(ch); if (!list_empty(&ch->list)) { /* if the list is not empty, queue the next request */ struct tegra_dma_req *next_req; @@ -270,6 +294,8 @@ int tegra_dma_dequeue_req(struct tegra_dma_channel *ch, typeof(*next_req), node); tegra_dma_update_hw(ch, next_req); } + +skip_stop_dma: req->status = -TEGRA_DMA_REQ_ERROR_ABORTED; spin_unlock_irqrestore(&ch->lock, irq_flags); @@ -357,7 +383,7 @@ struct tegra_dma_channel *tegra_dma_allocate_channel(int mode) int channel; struct tegra_dma_channel *ch = NULL; - if (WARN_ON(!tegra_dma_initialized)) + if (!tegra_dma_initialized) return NULL; mutex_lock(&tegra_dma_lock); diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c index ea49bd9..c1afb27 100644 --- a/arch/arm/mach-tegra/fuse.c +++ b/arch/arm/mach-tegra/fuse.c @@ -19,25 +19,75 @@ #include <linux/kernel.h> #include <linux/io.h> -#include <linux/module.h> +#include <linux/export.h> #include <mach/iomap.h> #include "fuse.h" +#include "apbio.h" #define FUSE_UID_LOW 0x108 #define FUSE_UID_HIGH 0x10c #define FUSE_SKU_INFO 0x110 #define FUSE_SPARE_BIT 0x200 -static inline u32 fuse_readl(unsigned long offset) +int tegra_sku_id; +int tegra_cpu_process_id; +int tegra_core_process_id; +enum tegra_revision tegra_revision; + +/* The BCT to use at boot is specified by board straps that can be read + * through a APB misc register and decoded. 2 bits, i.e. 4 possible BCTs. + */ +int tegra_bct_strapping; + +#define STRAP_OPT 0x008 +#define GMI_AD0 (1 << 4) +#define GMI_AD1 (1 << 5) +#define RAM_ID_MASK (GMI_AD0 | GMI_AD1) +#define RAM_CODE_SHIFT 4 + +static const char *tegra_revision_name[TEGRA_REVISION_MAX] = { + [TEGRA_REVISION_UNKNOWN] = "unknown", + [TEGRA_REVISION_A01] = "A01", + [TEGRA_REVISION_A02] = "A02", + [TEGRA_REVISION_A03] = "A03", + [TEGRA_REVISION_A03p] = "A03 prime", + [TEGRA_REVISION_A04] = "A04", +}; + +static inline u32 tegra_fuse_readl(unsigned long offset) +{ + return tegra_apb_readl(TEGRA_FUSE_BASE + offset); +} + +static inline bool get_spare_fuse(int bit) { - return readl(IO_TO_VIRT(TEGRA_FUSE_BASE + offset)); + return tegra_fuse_readl(FUSE_SPARE_BIT + bit * 4); } -static inline void fuse_writel(u32 value, unsigned long offset) +static enum tegra_revision tegra_get_revision(void) { - writel(value, IO_TO_VIRT(TEGRA_FUSE_BASE + offset)); + void __iomem *chip_id = IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804; + u32 id = readl(chip_id); + u32 minor_rev = (id >> 16) & 0xf; + u32 chipid = (id >> 8) & 0xff; + + switch (minor_rev) { + case 1: + return TEGRA_REVISION_A01; + case 2: + return TEGRA_REVISION_A02; + case 3: + if (chipid == 0x20 && (get_spare_fuse(18) || get_spare_fuse(19))) + return TEGRA_REVISION_A03p; + else + return TEGRA_REVISION_A03; + case 4: + return TEGRA_REVISION_A04; + default: + return TEGRA_REVISION_UNKNOWN; + } } void tegra_init_fuse(void) @@ -46,41 +96,32 @@ void tegra_init_fuse(void) reg |= 1 << 28; writel(reg, IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48)); - pr_info("Tegra SKU: %d CPU Process: %d Core Process: %d\n", - tegra_sku_id(), tegra_cpu_process_id(), - tegra_core_process_id()); + reg = tegra_fuse_readl(FUSE_SKU_INFO); + tegra_sku_id = reg & 0xFF; + + reg = tegra_fuse_readl(FUSE_SPARE_BIT); + tegra_cpu_process_id = (reg >> 6) & 3; + + reg = tegra_fuse_readl(FUSE_SPARE_BIT); + tegra_core_process_id = (reg >> 12) & 3; + + reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT); + tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT; + + tegra_revision = tegra_get_revision(); + + pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n", + tegra_revision_name[tegra_get_revision()], + tegra_sku_id, tegra_cpu_process_id, + tegra_core_process_id); } unsigned long long tegra_chip_uid(void) { unsigned long long lo, hi; - lo = fuse_readl(FUSE_UID_LOW); - hi = fuse_readl(FUSE_UID_HIGH); + lo = tegra_fuse_readl(FUSE_UID_LOW); + hi = tegra_fuse_readl(FUSE_UID_HIGH); return (hi << 32ull) | lo; } EXPORT_SYMBOL(tegra_chip_uid); - -int tegra_sku_id(void) -{ - int sku_id; - u32 reg = fuse_readl(FUSE_SKU_INFO); - sku_id = reg & 0xFF; - return sku_id; -} - -int tegra_cpu_process_id(void) -{ - int cpu_process_id; - u32 reg = fuse_readl(FUSE_SPARE_BIT); - cpu_process_id = (reg >> 6) & 3; - return cpu_process_id; -} - -int tegra_core_process_id(void) -{ - int core_process_id; - u32 reg = fuse_readl(FUSE_SPARE_BIT); - core_process_id = (reg >> 12) & 3; - return core_process_id; -} diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h index 584b2e2..d65d2ab 100644 --- a/arch/arm/mach-tegra/fuse.h +++ b/arch/arm/mach-tegra/fuse.h @@ -1,6 +1,4 @@ /* - * arch/arm/mach-tegra/fuse.c - * * Copyright (C) 2010 Google, Inc. * * Author: @@ -17,8 +15,34 @@ * */ +#ifndef __MACH_TEGRA_FUSE_H +#define __MACH_TEGRA_FUSE_H + +enum tegra_revision { + TEGRA_REVISION_UNKNOWN = 0, + TEGRA_REVISION_A01, + TEGRA_REVISION_A02, + TEGRA_REVISION_A03, + TEGRA_REVISION_A03p, + TEGRA_REVISION_A04, + TEGRA_REVISION_MAX, +}; + +#define SKU_ID_T20 8 +#define SKU_ID_T25SE 20 +#define SKU_ID_AP25 23 +#define SKU_ID_T25 24 +#define SKU_ID_AP25E 27 +#define SKU_ID_T25E 28 + +extern int tegra_sku_id; +extern int tegra_cpu_process_id; +extern int tegra_core_process_id; +extern enum tegra_revision tegra_revision; + +extern int tegra_bct_strapping; + unsigned long long tegra_chip_uid(void); -int tegra_sku_id(void); -int tegra_cpu_process_id(void); -int tegra_core_process_id(void); void tegra_init_fuse(void); + +#endif diff --git a/arch/arm/mach-tegra/include/mach/debug-macro.S b/arch/arm/mach-tegra/include/mach/debug-macro.S index 619abc6..90069ab 100644 --- a/arch/arm/mach-tegra/include/mach/debug-macro.S +++ b/arch/arm/mach-tegra/include/mach/debug-macro.S @@ -1,11 +1,17 @@ /* * arch/arm/mach-tegra/include/mach/debug-macro.S * - * Copyright (C) 2010 Google, Inc. + * Copyright (C) 2010,2011 Google, Inc. + * Copyright (C) 2011-2012 NVIDIA CORPORATION. All Rights Reserved. * * Author: * Colin Cross <ccross@google.com> * Erik Gilling <konkers@google.com> + * Doug Anderson <dianders@chromium.org> + * Stephen Warren <swarren@nvidia.com> + * + * Portions based on mach-omap2's debug-macro.S + * Copyright (C) 1994-1999 Russell King * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -18,18 +24,78 @@ * */ +#include <linux/serial_reg.h> + #include <mach/io.h> #include <mach/iomap.h> +#include <mach/irammap.h> + + .macro addruart, rp, rv, tmp + adr \rp, 99f @ actual addr of 99f + ldr \rv, [\rp] @ linked addr is stored there + sub \rv, \rv, \rp @ offset between the two + ldr \rp, [\rp, #4] @ linked tegra_uart_config + sub \tmp, \rp, \rv @ actual tegra_uart_config + ldr \rp, [\tmp] @ Load tegra_uart_config + cmp \rp, #1 @ needs intitialization? + bne 100f @ no; go load the addresses + mov \rv, #0 @ yes; record init is done + str \rv, [\tmp] + mov \rp, #TEGRA_IRAM_BASE @ See if cookie is in IRAM + ldr \rv, [\rp, #TEGRA_IRAM_DEBUG_UART_OFFSET] + movw \rp, #TEGRA_IRAM_DEBUG_UART_COOKIE & 0xffff + movt \rp, #TEGRA_IRAM_DEBUG_UART_COOKIE >> 16 + cmp \rv, \rp @ Cookie present? + bne 100f @ No, use default UART + mov \rp, #TEGRA_IRAM_BASE @ Load UART address from IRAM + ldr \rv, [\rp, #TEGRA_IRAM_DEBUG_UART_OFFSET + 4] + str \rv, [\tmp, #4] @ Store in tegra_uart_phys + sub \rv, \rv, #IO_APB_PHYS @ Calculate virt address + add \rv, \rv, #IO_APB_VIRT + str \rv, [\tmp, #8] @ Store in tegra_uart_virt + b 100f + + .align +99: .word . + .word tegra_uart_config + .ltorg + +100: ldr \rp, [\tmp, #4] @ Load tegra_uart_phys + ldr \rv, [\tmp, #8] @ Load tegra_uart_virt + .endm + +#define UART_SHIFT 2 + +/* + * Code below is swiped from <asm/hardware/debug-8250.S>, but add an extra + * check to make sure that we aren't in the CONFIG_TEGRA_DEBUG_UART_NONE case. + * We use the fact that all 5 valid UART addresses all have something in the + * 2nd-to-lowest byte. + */ - .macro addruart, rp, rv, tmp - ldr \rp, =IO_APB_PHYS @ physical - ldr \rv, =IO_APB_VIRT @ virtual - orr \rp, \rp, #(TEGRA_DEBUG_UART_BASE & 0xFF) - orr \rp, \rp, #(TEGRA_DEBUG_UART_BASE & 0xFF00) - orr \rv, \rv, #(TEGRA_DEBUG_UART_BASE & 0xFF) - orr \rv, \rv, #(TEGRA_DEBUG_UART_BASE & 0xFF00) - .endm + .macro senduart, rd, rx + tst \rx, #0x0000ff00 + strneb \rd, [\rx, #UART_TX << UART_SHIFT] +1001: + .endm -#define UART_SHIFT 2 -#include <asm/hardware/debug-8250.S> + .macro busyuart, rd, rx + tst \rx, #0x0000ff00 + beq 1002f +1001: ldrb \rd, [\rx, #UART_LSR << UART_SHIFT] + and \rd, \rd, #UART_LSR_TEMT | UART_LSR_THRE + teq \rd, #UART_LSR_TEMT | UART_LSR_THRE + bne 1001b +1002: + .endm + .macro waituart, rd, rx +#ifdef FLOW_CONTROL + tst \rx, #0x0000ff00 + beq 1002f +1001: ldrb \rd, [\rx, #UART_MSR << UART_SHIFT] + tst \rd, #UART_MSR_CTS + beq 1001b +1002: +#endif + .endm diff --git a/arch/arm/mach-tegra/include/mach/gpio-tegra.h b/arch/arm/mach-tegra/include/mach/gpio-tegra.h index 87d37fd..6140820 100644 --- a/arch/arm/mach-tegra/include/mach/gpio-tegra.h +++ b/arch/arm/mach-tegra/include/mach/gpio-tegra.h @@ -25,8 +25,6 @@ #define TEGRA_NR_GPIOS INT_GPIO_NR -#define TEGRA_GPIO_TO_IRQ(gpio) (INT_GPIO_BASE + (gpio)) - struct tegra_gpio_table { int gpio; /* GPIO number */ bool enable; /* Enable for GPIO at init? */ diff --git a/arch/arm/mach-tegra/include/mach/irammap.h b/arch/arm/mach-tegra/include/mach/irammap.h new file mode 100644 index 0000000..0cbe632 --- /dev/null +++ b/arch/arm/mach-tegra/include/mach/irammap.h @@ -0,0 +1,35 @@ +/* + * 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_TEGRA_IRAMMAP_H +#define __MACH_TEGRA_IRAMMAP_H + +#include <asm/sizes.h> + +/* The first 1K of IRAM is permanently reserved for the CPU reset handler */ +#define TEGRA_IRAM_RESET_HANDLER_OFFSET 0 +#define TEGRA_IRAM_RESET_HANDLER_SIZE SZ_1K + +/* + * These locations are written to by uncompress.h, and read by debug-macro.S. + * The first word holds the cookie value if the data is valid. The second + * word holds the UART physical address. + */ +#define TEGRA_IRAM_DEBUG_UART_OFFSET SZ_1K +#define TEGRA_IRAM_DEBUG_UART_SIZE 8 +#define TEGRA_IRAM_DEBUG_UART_COOKIE 0x55415254 + +#endif diff --git a/arch/arm/mach-tegra/include/mach/uncompress.h b/arch/arm/mach-tegra/include/mach/uncompress.h index 4e83237..5a440f3 100644 --- a/arch/arm/mach-tegra/include/mach/uncompress.h +++ b/arch/arm/mach-tegra/include/mach/uncompress.h @@ -2,10 +2,14 @@ * arch/arm/mach-tegra/include/mach/uncompress.h * * Copyright (C) 2010 Google, Inc. + * Copyright (C) 2011 Google, Inc. + * Copyright (C) 2011-2012 NVIDIA CORPORATION. All Rights Reserved. * * Author: * Colin Cross <ccross@google.com> * Erik Gilling <konkers@google.com> + * Doug Anderson <dianders@chromium.org> + * Stephen Warren <swarren@nvidia.com> * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -25,36 +29,130 @@ #include <linux/serial_reg.h> #include <mach/iomap.h> +#include <mach/irammap.h> + +#define BIT(x) (1 << (x)) +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +#define DEBUG_UART_SHIFT 2 + +volatile u8 *uart; static void putc(int c) { - volatile u8 *uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE; - int shift = 2; - if (uart == NULL) return; - while (!(uart[UART_LSR << shift] & UART_LSR_THRE)) + while (!(uart[UART_LSR << DEBUG_UART_SHIFT] & UART_LSR_THRE)) barrier(); - uart[UART_TX << shift] = c; + uart[UART_TX << DEBUG_UART_SHIFT] = c; } static inline void flush(void) { } +static inline void save_uart_address(void) +{ + u32 *buf = (u32 *)(TEGRA_IRAM_BASE + TEGRA_IRAM_DEBUG_UART_OFFSET); + + if (uart) { + buf[0] = TEGRA_IRAM_DEBUG_UART_COOKIE; + buf[1] = (u32)uart; + } else + buf[0] = 0; +} + +/* + * Setup before decompression. This is where we do UART selection for + * earlyprintk and init the uart_base register. + */ static inline void arch_decomp_setup(void) { - volatile u8 *uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE; - int shift = 2; + static const struct { + u32 base; + u32 reset_reg; + u32 clock_reg; + u32 bit; + } uarts[] = { + { + TEGRA_UARTA_BASE, + TEGRA_CLK_RESET_BASE + 0x04, + TEGRA_CLK_RESET_BASE + 0x10, + 6, + }, + { + TEGRA_UARTB_BASE, + TEGRA_CLK_RESET_BASE + 0x04, + TEGRA_CLK_RESET_BASE + 0x10, + 7, + }, + { + TEGRA_UARTC_BASE, + TEGRA_CLK_RESET_BASE + 0x08, + TEGRA_CLK_RESET_BASE + 0x14, + 23, + }, + { + TEGRA_UARTD_BASE, + TEGRA_CLK_RESET_BASE + 0x0c, + TEGRA_CLK_RESET_BASE + 0x18, + 1, + }, + { + TEGRA_UARTE_BASE, + TEGRA_CLK_RESET_BASE + 0x0c, + TEGRA_CLK_RESET_BASE + 0x18, + 2, + }, + }; + int i; + volatile u32 *apb_misc = (volatile u32 *)TEGRA_APB_MISC_BASE; + u32 chip, div; + + /* + * Look for the first UART that: + * a) Is not in reset. + * b) Is clocked. + * c) Has a 'D' in the scratchpad register. + * + * Note that on Tegra30, the first two conditions are required, since + * if not true, accesses to the UART scratch register will hang. + * Tegra20 doesn't have this issue. + * + * The intent is that the bootloader will tell the kernel which UART + * to use by setting up those conditions. If nothing found, we'll fall + * back to what's specified in TEGRA_DEBUG_UART_BASE. + */ + for (i = 0; i < ARRAY_SIZE(uarts); i++) { + if (*(u8 *)uarts[i].reset_reg & BIT(uarts[i].bit)) + continue; + if (!(*(u8 *)uarts[i].clock_reg & BIT(uarts[i].bit))) + continue; + + uart = (volatile u8 *)uarts[i].base; + if (uart[UART_SCR << DEBUG_UART_SHIFT] != 'D') + continue; + + break; + } + if (i == ARRAY_SIZE(uarts)) + uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE; + save_uart_address(); if (uart == NULL) return; - uart[UART_LCR << shift] |= UART_LCR_DLAB; - uart[UART_DLL << shift] = 0x75; - uart[UART_DLM << shift] = 0x0; - uart[UART_LCR << shift] = 3; + chip = (apb_misc[0x804 / 4] >> 8) & 0xff; + if (chip == 0x20) + div = 0x0075; + else + div = 0x00dd; + + uart[UART_LCR << DEBUG_UART_SHIFT] |= UART_LCR_DLAB; + uart[UART_DLL << DEBUG_UART_SHIFT] = div & 0xff; + uart[UART_DLM << DEBUG_UART_SHIFT] = div >> 8; + uart[UART_LCR << DEBUG_UART_SHIFT] = 3; } static inline void arch_decomp_wdog(void) diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c new file mode 100644 index 0000000..7af6a54 --- /dev/null +++ b/arch/arm/mach-tegra/pmc.c @@ -0,0 +1,76 @@ +/* + * 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/>. + * + */ + +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/of.h> + +#include <mach/iomap.h> + +#define PMC_CTRL 0x0 +#define PMC_CTRL_INTR_LOW (1 << 17) + +static inline u32 tegra_pmc_readl(u32 reg) +{ + return readl(IO_ADDRESS(TEGRA_PMC_BASE + reg)); +} + +static inline void tegra_pmc_writel(u32 val, u32 reg) +{ + writel(val, IO_ADDRESS(TEGRA_PMC_BASE + reg)); +} + +#ifdef CONFIG_OF +static const struct of_device_id matches[] __initconst = { + { .compatible = "nvidia,tegra20-pmc" }, + { } +}; +#endif + +void __init tegra_pmc_init(void) +{ + /* + * For now, Harmony is the only board that uses the PMC, and it wants + * the signal inverted. Seaboard would too if it used the PMC. + * Hopefully by the time other boards want to use the PMC, everything + * will be device-tree, or they also want it inverted. + */ + bool invert_interrupt = true; + u32 val; + +#ifdef CONFIG_OF + if (of_have_populated_dt()) { + struct device_node *np; + + invert_interrupt = false; + + np = of_find_matching_node(NULL, matches); + if (np) { + if (of_find_property(np, "nvidia,invert-interrupt", + NULL)) + invert_interrupt = true; + } + } +#endif + + val = tegra_pmc_readl(PMC_CTRL); + if (invert_interrupt) + val |= PMC_CTRL_INTR_LOW; + else + val &= ~PMC_CTRL_INTR_LOW; + tegra_pmc_writel(val, PMC_CTRL); +} diff --git a/arch/arm/mach-tegra/pmc.h b/arch/arm/mach-tegra/pmc.h new file mode 100644 index 0000000..8995ee4 --- /dev/null +++ b/arch/arm/mach-tegra/pmc.h @@ -0,0 +1,23 @@ +/* + * 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_TEGRA_PMC_H +#define __MACH_TEGRA_PMC_H + +void tegra_pmc_init(void); + +#endif diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c index 1976e93..592a4ee 100644 --- a/arch/arm/mach-tegra/tegra2_clocks.c +++ b/arch/arm/mach-tegra/tegra2_clocks.c @@ -720,7 +720,7 @@ static void tegra2_pllx_clk_init(struct clk *c) { tegra2_pll_clk_init(c); - if (tegra_sku_id() == 7) + if (tegra_sku_id == 7) c->max_rate = 750000000; } diff --git a/arch/arm/mach-tegra/tegra2_emc.c b/arch/arm/mach-tegra/tegra2_emc.c index 0f7ae6e..5070d83 100644 --- a/arch/arm/mach-tegra/tegra2_emc.c +++ b/arch/arm/mach-tegra/tegra2_emc.c @@ -16,14 +16,19 @@ */ #include <linux/kernel.h> +#include <linux/device.h> #include <linux/clk.h> #include <linux/err.h> #include <linux/io.h> #include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/platform_data/tegra_emc.h> #include <mach/iomap.h> #include "tegra2_emc.h" +#include "fuse.h" #ifdef CONFIG_TEGRA_EMC_SCALING_ENABLE static bool emc_enable = true; @@ -32,18 +37,17 @@ static bool emc_enable; #endif module_param(emc_enable, bool, 0644); -static void __iomem *emc = IO_ADDRESS(TEGRA_EMC_BASE); -static const struct tegra_emc_table *tegra_emc_table; -static int tegra_emc_table_size; +static struct platform_device *emc_pdev; +static void __iomem *emc_regbase; static inline void emc_writel(u32 val, unsigned long addr) { - writel(val, emc + addr); + writel(val, emc_regbase + addr); } static inline u32 emc_readl(unsigned long addr) { - return readl(emc + addr); + return readl(emc_regbase + addr); } static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = { @@ -98,15 +102,15 @@ static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = { /* Select the closest EMC rate that is higher than the requested rate */ long tegra_emc_round_rate(unsigned long rate) { + struct tegra_emc_pdata *pdata; int i; int best = -1; unsigned long distance = ULONG_MAX; - if (!tegra_emc_table) + if (!emc_pdev) return -EINVAL; - if (!emc_enable) - return -EINVAL; + pdata = emc_pdev->dev.platform_data; pr_debug("%s: %lu\n", __func__, rate); @@ -116,10 +120,10 @@ long tegra_emc_round_rate(unsigned long rate) */ rate = rate / 2 / 1000; - for (i = 0; i < tegra_emc_table_size; i++) { - if (tegra_emc_table[i].rate >= rate && - (tegra_emc_table[i].rate - rate) < distance) { - distance = tegra_emc_table[i].rate - rate; + for (i = 0; i < pdata->num_tables; i++) { + if (pdata->tables[i].rate >= rate && + (pdata->tables[i].rate - rate) < distance) { + distance = pdata->tables[i].rate - rate; best = i; } } @@ -127,9 +131,9 @@ long tegra_emc_round_rate(unsigned long rate) if (best < 0) return -EINVAL; - pr_debug("%s: using %lu\n", __func__, tegra_emc_table[best].rate); + pr_debug("%s: using %lu\n", __func__, pdata->tables[best].rate); - return tegra_emc_table[best].rate * 2 * 1000; + return pdata->tables[best].rate * 2 * 1000; } /* @@ -142,37 +146,211 @@ long tegra_emc_round_rate(unsigned long rate) */ int tegra_emc_set_rate(unsigned long rate) { + struct tegra_emc_pdata *pdata; int i; int j; - if (!tegra_emc_table) + if (!emc_pdev) return -EINVAL; + pdata = emc_pdev->dev.platform_data; + /* * The EMC clock rate is twice the bus rate, and the bus rate is * measured in kHz */ rate = rate / 2 / 1000; - for (i = 0; i < tegra_emc_table_size; i++) - if (tegra_emc_table[i].rate == rate) + for (i = 0; i < pdata->num_tables; i++) + if (pdata->tables[i].rate == rate) break; - if (i >= tegra_emc_table_size) + if (i >= pdata->num_tables) return -EINVAL; pr_debug("%s: setting to %lu\n", __func__, rate); for (j = 0; j < TEGRA_EMC_NUM_REGS; j++) - emc_writel(tegra_emc_table[i].regs[j], emc_reg_addr[j]); + emc_writel(pdata->tables[i].regs[j], emc_reg_addr[j]); - emc_readl(tegra_emc_table[i].regs[TEGRA_EMC_NUM_REGS - 1]); + emc_readl(pdata->tables[i].regs[TEGRA_EMC_NUM_REGS - 1]); return 0; } -void tegra_init_emc(const struct tegra_emc_table *table, int table_size) +#ifdef CONFIG_OF +static struct device_node *tegra_emc_ramcode_devnode(struct device_node *np) +{ + struct device_node *iter; + u32 reg; + + for_each_child_of_node(np, iter) { + if (of_property_read_u32(np, "nvidia,ram-code", ®)) + continue; + if (reg == tegra_bct_strapping) + return of_node_get(iter); + } + + return NULL; +} + +static struct tegra_emc_pdata *tegra_emc_dt_parse_pdata( + struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *tnp, *iter; + struct tegra_emc_pdata *pdata; + int ret, i, num_tables; + + if (!np) + return NULL; + + if (of_find_property(np, "nvidia,use-ram-code", NULL)) { + tnp = tegra_emc_ramcode_devnode(np); + if (!tnp) + dev_warn(&pdev->dev, + "can't find emc table for ram-code 0x%02x\n", + tegra_bct_strapping); + } else + tnp = of_node_get(np); + + if (!tnp) + return NULL; + + num_tables = 0; + for_each_child_of_node(tnp, iter) + if (of_device_is_compatible(iter, "nvidia,tegra20-emc-table")) + num_tables++; + + if (!num_tables) { + pdata = NULL; + goto out; + } + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + pdata->tables = devm_kzalloc(&pdev->dev, + sizeof(*pdata->tables) * num_tables, + GFP_KERNEL); + + i = 0; + for_each_child_of_node(tnp, iter) { + u32 prop; + + ret = of_property_read_u32(iter, "clock-frequency", &prop); + if (ret) { + dev_err(&pdev->dev, "no clock-frequency in %s\n", + iter->full_name); + continue; + } + pdata->tables[i].rate = prop; + + ret = of_property_read_u32_array(iter, "nvidia,emc-registers", + pdata->tables[i].regs, + TEGRA_EMC_NUM_REGS); + if (ret) { + dev_err(&pdev->dev, + "malformed emc-registers property in %s\n", + iter->full_name); + continue; + } + + i++; + } + pdata->num_tables = i; + +out: + of_node_put(tnp); + return pdata; +} +#else +static struct tegra_emc_pdata *tegra_emc_dt_parse_pdata( + struct platform_device *pdev) +{ + return NULL; +} +#endif + +static struct tegra_emc_pdata __devinit *tegra_emc_fill_pdata(struct platform_device *pdev) +{ + struct clk *c = clk_get_sys(NULL, "emc"); + struct tegra_emc_pdata *pdata; + unsigned long khz; + int i; + + WARN_ON(pdev->dev.platform_data); + BUG_ON(IS_ERR_OR_NULL(c)); + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + pdata->tables = devm_kzalloc(&pdev->dev, sizeof(*pdata->tables), + GFP_KERNEL); + + pdata->tables[0].rate = clk_get_rate(c) / 2 / 1000; + + for (i = 0; i < TEGRA_EMC_NUM_REGS; i++) + pdata->tables[0].regs[i] = emc_readl(emc_reg_addr[i]); + + pdata->num_tables = 1; + + khz = pdata->tables[0].rate; + dev_info(&pdev->dev, "no tables provided, using %ld kHz emc, " + "%ld kHz mem\n", khz * 2, khz); + + return pdata; +} + +static int __devinit tegra_emc_probe(struct platform_device *pdev) +{ + struct tegra_emc_pdata *pdata; + struct resource *res; + + if (!emc_enable) { + dev_err(&pdev->dev, "disabled per module parameter\n"); + return -ENODEV; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "missing register base\n"); + return -ENOMEM; + } + + emc_regbase = devm_request_and_ioremap(&pdev->dev, res); + if (!emc_regbase) { + dev_err(&pdev->dev, "failed to remap registers\n"); + return -ENOMEM; + } + + pdata = pdev->dev.platform_data; + + if (!pdata) + pdata = tegra_emc_dt_parse_pdata(pdev); + + if (!pdata) + pdata = tegra_emc_fill_pdata(pdev); + + pdev->dev.platform_data = pdata; + + emc_pdev = pdev; + + return 0; +} + +static struct of_device_id tegra_emc_of_match[] __devinitdata = { + { .compatible = "nvidia,tegra20-emc", }, + { }, +}; + +static struct platform_driver tegra_emc_driver = { + .driver = { + .name = "tegra-emc", + .owner = THIS_MODULE, + .of_match_table = tegra_emc_of_match, + }, + .probe = tegra_emc_probe, +}; + +static int __init tegra_emc_init(void) { - tegra_emc_table = table; - tegra_emc_table_size = table_size; + return platform_driver_register(&tegra_emc_driver); } +device_initcall(tegra_emc_init); diff --git a/arch/arm/mach-tegra/tegra2_emc.h b/arch/arm/mach-tegra/tegra2_emc.h index 19f08cb..f61409b 100644 --- a/arch/arm/mach-tegra/tegra2_emc.h +++ b/arch/arm/mach-tegra/tegra2_emc.h @@ -15,13 +15,10 @@ * */ -#define TEGRA_EMC_NUM_REGS 46 - -struct tegra_emc_table { - unsigned long rate; - u32 regs[TEGRA_EMC_NUM_REGS]; -}; +#ifndef __MACH_TEGRA_TEGRA2_EMC_H_ +#define __MACH_TEGRA_TEGRA2_EMC_H int tegra_emc_set_rate(unsigned long rate); long tegra_emc_round_rate(unsigned long rate); -void tegra_init_emc(const struct tegra_emc_table *table, int table_size); + +#endif diff --git a/arch/arm/plat-mxc/devices/platform-ahci-imx.c b/arch/arm/plat-mxc/devices/platform-ahci-imx.c index d8a56ae..ade4a1c 100644 --- a/arch/arm/plat-mxc/devices/platform-ahci-imx.c +++ b/arch/arm/plat-mxc/devices/platform-ahci-imx.c @@ -60,9 +60,9 @@ static int imx_sata_init(struct device *dev, void __iomem *addr) dev_err(dev, "no sata clock.\n"); return PTR_ERR(sata_clk); } - ret = clk_enable(sata_clk); + ret = clk_prepare_enable(sata_clk); if (ret) { - dev_err(dev, "can't enable sata clock.\n"); + dev_err(dev, "can't prepare/enable sata clock.\n"); goto put_sata_clk; } @@ -73,9 +73,9 @@ static int imx_sata_init(struct device *dev, void __iomem *addr) ret = PTR_ERR(sata_ref_clk); goto release_sata_clk; } - ret = clk_enable(sata_ref_clk); + ret = clk_prepare_enable(sata_ref_clk); if (ret) { - dev_err(dev, "can't enable sata ref clock.\n"); + dev_err(dev, "can't prepare/enable sata ref clock.\n"); goto put_sata_ref_clk; } @@ -104,11 +104,11 @@ static int imx_sata_init(struct device *dev, void __iomem *addr) return 0; release_sata_ref_clk: - clk_disable(sata_ref_clk); + clk_disable_unprepare(sata_ref_clk); put_sata_ref_clk: clk_put(sata_ref_clk); release_sata_clk: - clk_disable(sata_clk); + clk_disable_unprepare(sata_clk); put_sata_clk: clk_put(sata_clk); @@ -117,10 +117,10 @@ put_sata_clk: static void imx_sata_exit(struct device *dev) { - clk_disable(sata_ref_clk); + clk_disable_unprepare(sata_ref_clk); clk_put(sata_ref_clk); - clk_disable(sata_clk); + clk_disable_unprepare(sata_clk); clk_put(sata_clk); } diff --git a/arch/arm/plat-mxc/epit.c b/arch/arm/plat-mxc/epit.c index d3467f8..9129c9e 100644 --- a/arch/arm/plat-mxc/epit.c +++ b/arch/arm/plat-mxc/epit.c @@ -203,7 +203,7 @@ static int __init epit_clockevent_init(struct clk *timer_clk) void __init epit_timer_init(struct clk *timer_clk, void __iomem *base, int irq) { - clk_enable(timer_clk); + clk_prepare_enable(timer_clk); timer_base = base; diff --git a/arch/arm/plat-mxc/include/mach/board-mx31ads.h b/arch/arm/plat-mxc/include/mach/board-mx31ads.h deleted file mode 100644 index 94b60dd4..0000000 --- a/arch/arm/plat-mxc/include/mach/board-mx31ads.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2005-2007 Freescale Semiconductor, Inc. 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 version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __ASM_ARCH_MXC_BOARD_MX31ADS_H__ -#define __ASM_ARCH_MXC_BOARD_MX31ADS_H__ - -#include <mach/hardware.h> - -/* - * These symbols are used by drivers/net/cs89x0.c. - * This is ugly as hell, but we have to provide them until - * someone fixed the driver. - */ - -/* Base address of PBC controller */ -#define PBC_BASE_ADDRESS MX31_CS4_BASE_ADDR_VIRT -/* Offsets for the PBC Controller register */ - -/* Ethernet Controller IO base address */ -#define PBC_CS8900A_IOBASE 0x020000 - -#define MXC_EXP_IO_BASE (MXC_BOARD_IRQ_START) - -#define EXPIO_INT_ENET_INT (MXC_EXP_IO_BASE + 8) - -#endif /* __ASM_ARCH_MXC_BOARD_MX31ADS_H__ */ diff --git a/arch/arm/plat-mxc/include/mach/debug-macro.S b/arch/arm/plat-mxc/include/mach/debug-macro.S index 6e192c4..8ddda36 100644 --- a/arch/arm/plat-mxc/include/mach/debug-macro.S +++ b/arch/arm/plat-mxc/include/mach/debug-macro.S @@ -24,7 +24,7 @@ #define UART_PADDR MX51_UART1_BASE_ADDR #elif defined (CONFIG_DEBUG_IMX50_IMX53_UART) #define UART_PADDR MX53_UART1_BASE_ADDR -#elif defined (CONFIG_DEBUG_IMX6Q_UART) +#elif defined (CONFIG_DEBUG_IMX6Q_UART4) #define UART_PADDR MX6Q_UART4_BASE_ADDR #endif diff --git a/arch/arm/plat-mxc/include/mach/dma.h b/arch/arm/plat-mxc/include/mach/dma.h index 233d0a5..1b90803 100644 --- a/arch/arm/plat-mxc/include/mach/dma.h +++ b/arch/arm/plat-mxc/include/mach/dma.h @@ -60,8 +60,7 @@ static inline int imx_dma_is_ipu(struct dma_chan *chan) static inline int imx_dma_is_general_purpose(struct dma_chan *chan) { - return !strcmp(dev_name(chan->device->dev), "imx31-sdma") || - !strcmp(dev_name(chan->device->dev), "imx35-sdma") || + return strstr(dev_name(chan->device->dev), "sdma") || !strcmp(dev_name(chan->device->dev), "imx-dma"); } diff --git a/arch/arm/plat-mxc/pwm.c b/arch/arm/plat-mxc/pwm.c index e032717..c0cab22 100644 --- a/arch/arm/plat-mxc/pwm.c +++ b/arch/arm/plat-mxc/pwm.c @@ -132,7 +132,7 @@ int pwm_enable(struct pwm_device *pwm) int rc = 0; if (!pwm->clk_enabled) { - rc = clk_enable(pwm->clk); + rc = clk_prepare_enable(pwm->clk); if (!rc) pwm->clk_enabled = 1; } @@ -145,7 +145,7 @@ void pwm_disable(struct pwm_device *pwm) writel(0, pwm->mmio_base + MX3_PWMCR); if (pwm->clk_enabled) { - clk_disable(pwm->clk); + clk_disable_unprepare(pwm->clk); pwm->clk_enabled = 0; } } diff --git a/arch/arm/plat-mxc/system.c b/arch/arm/plat-mxc/system.c index 3599bf2..f30dcac 100644 --- a/arch/arm/plat-mxc/system.c +++ b/arch/arm/plat-mxc/system.c @@ -48,7 +48,7 @@ void mxc_restart(char mode, const char *cmd) clk = clk_get_sys("imx2-wdt.0", NULL); if (!IS_ERR(clk)) - clk_enable(clk); + clk_prepare_enable(clk); wcr_enable = (1 << 2); } diff --git a/arch/arm/plat-mxc/time.c b/arch/arm/plat-mxc/time.c index 1c96cdb..7daf7c9 100644 --- a/arch/arm/plat-mxc/time.c +++ b/arch/arm/plat-mxc/time.c @@ -283,7 +283,7 @@ void __init mxc_timer_init(struct clk *timer_clk, void __iomem *base, int irq) { uint32_t tctl_val; - clk_enable(timer_clk); + clk_prepare_enable(timer_clk); timer_base = base; diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index 6470101..9e8e63d 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -484,7 +484,6 @@ struct omap_hwmod_class { * @main_clk: main clock: OMAP clock name * @_clk: pointer to the main struct clk (filled in at runtime) * @opt_clks: other device clocks that drivers can request (0..*) - * @vdd_name: voltage domain name * @voltdm: pointer to voltage domain (filled in at runtime) * @masters: ptr to array of OCP ifs that this hwmod can initiate on * @slaves: ptr to array of OCP ifs that this hwmod can respond on @@ -528,7 +527,6 @@ struct omap_hwmod { struct omap_hwmod_opt_clk *opt_clks; char *clkdm_name; struct clockdomain *clkdm; - char *vdd_name; struct omap_hwmod_ocp_if **masters; /* connect to *_IA */ struct omap_hwmod_ocp_if **slaves; /* connect to *_TA */ void *dev_attr; diff --git a/arch/arm/plat-samsung/include/plat/dma-pl330.h b/arch/arm/plat-samsung/include/plat/dma-pl330.h index c5eaad5..0670f37 100644 --- a/arch/arm/plat-samsung/include/plat/dma-pl330.h +++ b/arch/arm/plat-samsung/include/plat/dma-pl330.h @@ -82,6 +82,22 @@ enum dma_ch { DMACH_SLIMBUS4_TX, DMACH_SLIMBUS5_RX, DMACH_SLIMBUS5_TX, + DMACH_MIPI_HSI0, + DMACH_MIPI_HSI1, + DMACH_MIPI_HSI2, + DMACH_MIPI_HSI3, + DMACH_MIPI_HSI4, + DMACH_MIPI_HSI5, + DMACH_MIPI_HSI6, + DMACH_MIPI_HSI7, + DMACH_MTOM_0, + DMACH_MTOM_1, + DMACH_MTOM_2, + DMACH_MTOM_3, + DMACH_MTOM_4, + DMACH_MTOM_5, + DMACH_MTOM_6, + DMACH_MTOM_7, /* END Marker, also used to denote a reserved channel */ DMACH_MAX, }; diff --git a/arch/arm/plat-samsung/include/plat/regs-rtc.h b/arch/arm/plat-samsung/include/plat/regs-rtc.h index 30b7cc1..0f8263e 100644 --- a/arch/arm/plat-samsung/include/plat/regs-rtc.h +++ b/arch/arm/plat-samsung/include/plat/regs-rtc.h @@ -18,51 +18,54 @@ #define S3C2410_INTP_ALM (1 << 1) #define S3C2410_INTP_TIC (1 << 0) -#define S3C2410_RTCCON S3C2410_RTCREG(0x40) -#define S3C2410_RTCCON_RTCEN (1<<0) -#define S3C2410_RTCCON_CLKSEL (1<<1) -#define S3C2410_RTCCON_CNTSEL (1<<2) -#define S3C2410_RTCCON_CLKRST (1<<3) -#define S3C64XX_RTCCON_TICEN (1<<8) +#define S3C2410_RTCCON S3C2410_RTCREG(0x40) +#define S3C2410_RTCCON_RTCEN (1 << 0) +#define S3C2410_RTCCON_CNTSEL (1 << 2) +#define S3C2410_RTCCON_CLKRST (1 << 3) +#define S3C2443_RTCCON_TICSEL (1 << 4) +#define S3C64XX_RTCCON_TICEN (1 << 8) -#define S3C64XX_RTCCON_TICMSK (0xF<<7) -#define S3C64XX_RTCCON_TICSHT (7) +#define S3C2410_TICNT S3C2410_RTCREG(0x44) +#define S3C2410_TICNT_ENABLE (1 << 7) -#define S3C2410_TICNT S3C2410_RTCREG(0x44) -#define S3C2410_TICNT_ENABLE (1<<7) +/* S3C2443: tick count is 15 bit wide + * TICNT[6:0] contains upper 7 bits + * TICNT1[7:0] contains lower 8 bits + */ +#define S3C2443_TICNT_PART(x) ((x & 0x7f00) >> 8) +#define S3C2443_TICNT1 S3C2410_RTCREG(0x4C) +#define S3C2443_TICNT1_PART(x) (x & 0xff) -#define S3C2410_RTCALM S3C2410_RTCREG(0x50) -#define S3C2410_RTCALM_ALMEN (1<<6) -#define S3C2410_RTCALM_YEAREN (1<<5) -#define S3C2410_RTCALM_MONEN (1<<4) -#define S3C2410_RTCALM_DAYEN (1<<3) -#define S3C2410_RTCALM_HOUREN (1<<2) -#define S3C2410_RTCALM_MINEN (1<<1) -#define S3C2410_RTCALM_SECEN (1<<0) +/* S3C2416: tick count is 32 bit wide + * TICNT[6:0] contains bits [14:8] + * TICNT1[7:0] contains lower 8 bits + * TICNT2[16:0] contains upper 17 bits + */ +#define S3C2416_TICNT2 S3C2410_RTCREG(0x48) +#define S3C2416_TICNT2_PART(x) ((x & 0xffff8000) >> 15) -#define S3C2410_RTCALM_ALL \ - S3C2410_RTCALM_ALMEN | S3C2410_RTCALM_YEAREN | S3C2410_RTCALM_MONEN |\ - S3C2410_RTCALM_DAYEN | S3C2410_RTCALM_HOUREN | S3C2410_RTCALM_MINEN |\ - S3C2410_RTCALM_SECEN +#define S3C2410_RTCALM S3C2410_RTCREG(0x50) +#define S3C2410_RTCALM_ALMEN (1 << 6) +#define S3C2410_RTCALM_YEAREN (1 << 5) +#define S3C2410_RTCALM_MONEN (1 << 4) +#define S3C2410_RTCALM_DAYEN (1 << 3) +#define S3C2410_RTCALM_HOUREN (1 << 2) +#define S3C2410_RTCALM_MINEN (1 << 1) +#define S3C2410_RTCALM_SECEN (1 << 0) +#define S3C2410_ALMSEC S3C2410_RTCREG(0x54) +#define S3C2410_ALMMIN S3C2410_RTCREG(0x58) +#define S3C2410_ALMHOUR S3C2410_RTCREG(0x5c) -#define S3C2410_ALMSEC S3C2410_RTCREG(0x54) -#define S3C2410_ALMMIN S3C2410_RTCREG(0x58) -#define S3C2410_ALMHOUR S3C2410_RTCREG(0x5c) - -#define S3C2410_ALMDATE S3C2410_RTCREG(0x60) -#define S3C2410_ALMMON S3C2410_RTCREG(0x64) -#define S3C2410_ALMYEAR S3C2410_RTCREG(0x68) - -#define S3C2410_RTCRST S3C2410_RTCREG(0x6c) - -#define S3C2410_RTCSEC S3C2410_RTCREG(0x70) -#define S3C2410_RTCMIN S3C2410_RTCREG(0x74) -#define S3C2410_RTCHOUR S3C2410_RTCREG(0x78) -#define S3C2410_RTCDATE S3C2410_RTCREG(0x7c) -#define S3C2410_RTCDAY S3C2410_RTCREG(0x80) -#define S3C2410_RTCMON S3C2410_RTCREG(0x84) -#define S3C2410_RTCYEAR S3C2410_RTCREG(0x88) +#define S3C2410_ALMDATE S3C2410_RTCREG(0x60) +#define S3C2410_ALMMON S3C2410_RTCREG(0x64) +#define S3C2410_ALMYEAR S3C2410_RTCREG(0x68) +#define S3C2410_RTCSEC S3C2410_RTCREG(0x70) +#define S3C2410_RTCMIN S3C2410_RTCREG(0x74) +#define S3C2410_RTCHOUR S3C2410_RTCREG(0x78) +#define S3C2410_RTCDATE S3C2410_RTCREG(0x7c) +#define S3C2410_RTCMON S3C2410_RTCREG(0x84) +#define S3C2410_RTCYEAR S3C2410_RTCREG(0x88) #endif /* __ASM_ARCH_REGS_RTC_H */ diff --git a/arch/arm/plat-samsung/include/plat/rtc-core.h b/arch/arm/plat-samsung/include/plat/rtc-core.h new file mode 100644 index 0000000..21d8594 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/rtc-core.h @@ -0,0 +1,27 @@ +/* linux/arch/arm/plat-samsung/include/plat/rtc-core.h + * + * Copyright (c) 2011 Heiko Stuebner <heiko@sntech.de> + * + * Samsung RTC Controller core functions + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#ifndef __ASM_PLAT_RTC_CORE_H +#define __ASM_PLAT_RTC_CORE_H __FILE__ + +/* These functions are only for use with the core support code, such as + * the cpu specific initialisation code + */ + +/* re-define device name depending on support. */ +static inline void s3c_rtc_setname(char *name) +{ +#if defined(CONFIG_SAMSUNG_DEV_RTC) || defined(CONFIG_PLAT_S3C24XX) + s3c_device_rtc.name = name; +#endif +} + +#endif /* __ASM_PLAT_RTC_CORE_H */ diff --git a/arch/arm/plat-samsung/include/plat/sdhci.h b/arch/arm/plat-samsung/include/plat/sdhci.h index f82f888..317e246 100644 --- a/arch/arm/plat-samsung/include/plat/sdhci.h +++ b/arch/arm/plat-samsung/include/plat/sdhci.h @@ -40,6 +40,7 @@ enum clk_types { * struct s3c_sdhci_platdata() - Platform device data for Samsung SDHCI * @max_width: The maximum number of data bits supported. * @host_caps: Standard MMC host capabilities bit field. + * @host_caps2: The second standard MMC host capabilities bit field. * @cd_type: Type of Card Detection method (see cd_types enum above) * @clk_type: Type of clock divider method (see clk_types enum above) * @ext_cd_init: Initialize external card detect subsystem. Called on @@ -63,6 +64,7 @@ enum clk_types { struct s3c_sdhci_platdata { unsigned int max_width; unsigned int host_caps; + unsigned int host_caps2; unsigned int pm_caps; enum cd_types cd_type; enum clk_types clk_type; diff --git a/arch/arm/plat-samsung/platformdata.c b/arch/arm/plat-samsung/platformdata.c index 0f70718..fa78aa7 100644 --- a/arch/arm/plat-samsung/platformdata.c +++ b/arch/arm/plat-samsung/platformdata.c @@ -53,6 +53,8 @@ void s3c_sdhci_set_platdata(struct s3c_sdhci_platdata *pd, set->cfg_gpio = pd->cfg_gpio; if (pd->host_caps) set->host_caps |= pd->host_caps; + if (pd->host_caps2) + set->host_caps2 |= pd->host_caps2; if (pd->pm_caps) set->pm_caps |= pd->pm_caps; if (pd->clk_type) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index bdc2937..6f17671 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -25,6 +25,7 @@ #include <linux/of.h> #include <linux/platform_device.h> #include <linux/module.h> +#include <linux/irqdomain.h> #include <asm/mach/irq.h> @@ -74,9 +75,10 @@ struct tegra_gpio_bank { #endif }; - +static struct irq_domain *irq_domain; static void __iomem *regs; -static struct tegra_gpio_bank tegra_gpio_banks[7]; +static u32 tegra_gpio_bank_count; +static struct tegra_gpio_bank *tegra_gpio_banks; static inline void tegra_gpio_writel(u32 val, u32 reg) { @@ -139,7 +141,7 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset, static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { - return TEGRA_GPIO_TO_IRQ(offset); + return irq_find_mapping(irq_domain, offset); } static struct gpio_chip tegra_gpio_chip = { @@ -155,28 +157,28 @@ static struct gpio_chip tegra_gpio_chip = { static void tegra_gpio_irq_ack(struct irq_data *d) { - int gpio = d->irq - INT_GPIO_BASE; + int gpio = d->hwirq; tegra_gpio_writel(1 << GPIO_BIT(gpio), GPIO_INT_CLR(gpio)); } static void tegra_gpio_irq_mask(struct irq_data *d) { - int gpio = d->irq - INT_GPIO_BASE; + int gpio = d->hwirq; tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 0); } static void tegra_gpio_irq_unmask(struct irq_data *d) { - int gpio = d->irq - INT_GPIO_BASE; + int gpio = d->hwirq; tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 1); } static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) { - int gpio = d->irq - INT_GPIO_BASE; + int gpio = d->hwirq; struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); int port = GPIO_PORT(gpio); int lvl_type; @@ -273,7 +275,7 @@ void tegra_gpio_resume(void) local_irq_save(flags); - for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) { + for (b = 0; b < tegra_gpio_bank_count; b++) { struct tegra_gpio_bank *bank = &tegra_gpio_banks[b]; for (p = 0; p < ARRAY_SIZE(bank->oe); p++) { @@ -296,7 +298,7 @@ void tegra_gpio_suspend(void) int p; local_irq_save(flags); - for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) { + for (b = 0; b < tegra_gpio_bank_count; b++) { struct tegra_gpio_bank *bank = &tegra_gpio_banks[b]; for (p = 0; p < ARRAY_SIZE(bank->oe); p++) { @@ -337,13 +339,44 @@ static struct lock_class_key gpio_lock_class; static int __devinit tegra_gpio_probe(struct platform_device *pdev) { + int irq_base; struct resource *res; struct tegra_gpio_bank *bank; int gpio; int i; int j; - for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) { + for (;;) { + res = platform_get_resource(pdev, IORESOURCE_IRQ, tegra_gpio_bank_count); + if (!res) + break; + tegra_gpio_bank_count++; + } + if (!tegra_gpio_bank_count) { + dev_err(&pdev->dev, "Missing IRQ resource\n"); + return -ENODEV; + } + + tegra_gpio_chip.ngpio = tegra_gpio_bank_count * 32; + + tegra_gpio_banks = devm_kzalloc(&pdev->dev, + tegra_gpio_bank_count * sizeof(*tegra_gpio_banks), + GFP_KERNEL); + if (!tegra_gpio_banks) { + dev_err(&pdev->dev, "Couldn't allocate bank structure\n"); + return -ENODEV; + } + + irq_base = irq_alloc_descs(-1, 0, tegra_gpio_chip.ngpio, 0); + if (irq_base < 0) { + dev_err(&pdev->dev, "Couldn't allocate IRQ numbers\n"); + return -ENODEV; + } + irq_domain = irq_domain_add_legacy(pdev->dev.of_node, + tegra_gpio_chip.ngpio, irq_base, 0, + &irq_domain_simple_ops, NULL); + + for (i = 0; i < tegra_gpio_bank_count; i++) { res = platform_get_resource(pdev, IORESOURCE_IRQ, i); if (!res) { dev_err(&pdev->dev, "Missing IRQ resource\n"); @@ -380,8 +413,8 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) gpiochip_add(&tegra_gpio_chip); - for (gpio = 0; gpio < TEGRA_NR_GPIOS; gpio++) { - int irq = TEGRA_GPIO_TO_IRQ(gpio); + for (gpio = 0; gpio < tegra_gpio_chip.ngpio; gpio++) { + int irq = irq_find_mapping(irq_domain, gpio); /* No validity check; all Tegra GPIOs are valid IRQs */ bank = &tegra_gpio_banks[GPIO_BANK(gpio)]; @@ -393,7 +426,7 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) set_irq_flags(irq, IRQF_VALID); } - for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) { + for (i = 0; i < tegra_gpio_bank_count; i++) { bank = &tegra_gpio_banks[i]; irq_set_chained_handler(bank->irq, tegra_gpio_irq_handler); diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 124d9c5..dfb84b7 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -191,7 +191,7 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx) dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__); - clk_enable(i2c_imx->clk); + clk_prepare_enable(i2c_imx->clk); writeb(i2c_imx->ifdr, i2c_imx->base + IMX_I2C_IFDR); /* Enable I2C controller */ writeb(0, i2c_imx->base + IMX_I2C_I2SR); @@ -240,7 +240,7 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx) /* Disable I2C controller */ writeb(0, i2c_imx->base + IMX_I2C_I2CR); - clk_disable(i2c_imx->clk); + clk_disable_unprepare(i2c_imx->clk); } static void __init i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx, diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 0be4e20..6193a0d 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -464,7 +464,7 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) err = PTR_ERR(clk); goto err_clk_get; } - clk_enable(clk); + clk_prepare_enable(clk); pltfm_host->clk = clk; if (!is_imx25_esdhc(imx_data)) @@ -559,7 +559,7 @@ no_card_detect_irq: gpio_free(boarddata->wp_gpio); no_card_detect_pin: no_board_data: - clk_disable(pltfm_host->clk); + clk_disable_unprepare(pltfm_host->clk); clk_put(pltfm_host->clk); err_clk_get: kfree(imx_data); @@ -586,7 +586,7 @@ static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev) gpio_free(boarddata->cd_gpio); } - clk_disable(pltfm_host->clk); + clk_disable_unprepare(pltfm_host->clk); clk_put(pltfm_host->clk); kfree(imx_data); diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 1af756e..b19e7d4 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -518,9 +518,6 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) if (pdata->cd_type == S3C_SDHCI_CD_PERMANENT) host->mmc->caps = MMC_CAP_NONREMOVABLE; - if (pdata->host_caps) - host->mmc->caps |= pdata->host_caps; - if (pdata->pm_caps) host->mmc->pm_caps |= pdata->pm_caps; @@ -544,6 +541,9 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) if (pdata->host_caps) host->mmc->caps |= pdata->host_caps; + if (pdata->host_caps2) + host->mmc->caps2 |= pdata->host_caps2; + ret = sdhci_add_host(host); if (ret) { dev_err(dev, "sdhci_add_host() failed\n"); diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 068c356..88bbd8f 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -190,8 +190,10 @@ static struct devprobe2 isa_probes[] __initdata = { {seeq8005_probe, 0}, #endif #ifdef CONFIG_CS89x0 +#ifndef CONFIG_CS89x0_PLATFORM {cs89x0_probe, 0}, #endif +#endif #ifdef CONFIG_AT1700 {at1700_probe, 0}, #endif diff --git a/drivers/net/ethernet/cirrus/Kconfig b/drivers/net/ethernet/cirrus/Kconfig index 1f8648f..8388e36 100644 --- a/drivers/net/ethernet/cirrus/Kconfig +++ b/drivers/net/ethernet/cirrus/Kconfig @@ -5,8 +5,7 @@ config NET_VENDOR_CIRRUS bool "Cirrus devices" default y - depends on ISA || EISA || MACH_IXDP2351 || ARCH_IXDP2X01 \ - || MACH_MX31ADS || MACH_QQ2440 || (ARM && ARCH_EP93XX) || MAC + depends on ISA || EISA || ARM || MAC ---help--- If you have a network (Ethernet) card belonging to this class, say Y and read the Ethernet-HOWTO, available from @@ -21,8 +20,7 @@ if NET_VENDOR_CIRRUS config CS89x0 tristate "CS89x0 support" - depends on (ISA || EISA || MACH_IXDP2351 \ - || ARCH_IXDP2X01 || MACH_MX31ADS || MACH_QQ2440) + depends on ISA || EISA || ARM ---help--- Support for CS89x0 chipset based Ethernet cards. If you have a network (Ethernet) card of this type, say Y and read the @@ -33,10 +31,15 @@ config CS89x0 To compile this driver as a module, choose M here. The module will be called cs89x0. -config CS89x0_NONISA_IRQ - def_bool y - depends on CS89x0 != n - depends on MACH_IXDP2351 || ARCH_IXDP2X01 || MACH_MX31ADS || MACH_QQ2440 +config CS89x0_PLATFORM + bool "CS89x0 platform driver support" + depends on CS89x0 + help + Say Y to compile the cs89x0 driver as a platform driver. This + makes this driver suitable for use on certain evaluation boards + such as the iMX21ADS. + + If you are unsure, say N. config EP93XX_ETH tristate "EP93xx Ethernet support" diff --git a/drivers/net/ethernet/cirrus/cs89x0.c b/drivers/net/ethernet/cirrus/cs89x0.c index d5ff936..30fee42 100644 --- a/drivers/net/ethernet/cirrus/cs89x0.c +++ b/drivers/net/ethernet/cirrus/cs89x0.c @@ -100,9 +100,6 @@ */ -/* Always include 'config.h' first in case the user wants to turn on - or override something. */ -#include <linux/module.h> /* * Set this to zero to disable DMA code @@ -131,9 +128,12 @@ */ +#include <linux/module.h> +#include <linux/printk.h> #include <linux/errno.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> +#include <linux/platform_device.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/fcntl.h> @@ -151,6 +151,7 @@ #include <asm/system.h> #include <asm/io.h> #include <asm/irq.h> +#include <linux/atomic.h> #if ALLOW_DMA #include <asm/dma.h> #endif @@ -174,26 +175,20 @@ static char version[] __initdata = them to system IRQ numbers. This mapping is card specific and is set to the configuration of the Cirrus Eval board for this chip. */ #if defined(CONFIG_MACH_IXDP2351) +#define CS89x0_NONISA_IRQ static unsigned int netcard_portlist[] __used __initdata = {IXDP2351_VIRT_CS8900_BASE, 0}; static unsigned int cs8900_irq_map[] = {IRQ_IXDP2351_CS8900, 0, 0, 0}; #elif defined(CONFIG_ARCH_IXDP2X01) +#define CS89x0_NONISA_IRQ static unsigned int netcard_portlist[] __used __initdata = {IXDP2X01_CS8900_VIRT_BASE, 0}; static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0}; -#elif defined(CONFIG_MACH_QQ2440) -#include <mach/qq2440.h> -static unsigned int netcard_portlist[] __used __initdata = { QQ2440_CS8900_VIRT_BASE + 0x300, 0 }; -static unsigned int cs8900_irq_map[] = { QQ2440_CS8900_IRQ, 0, 0, 0 }; -#elif defined(CONFIG_MACH_MX31ADS) -#include <mach/board-mx31ads.h> -static unsigned int netcard_portlist[] __used __initdata = { - PBC_BASE_ADDRESS + PBC_CS8900A_IOBASE + 0x300, 0 -}; -static unsigned cs8900_irq_map[] = {EXPIO_INT_ENET_INT, 0, 0, 0}; #else +#ifndef CONFIG_CS89x0_PLATFORM static unsigned int netcard_portlist[] __used __initdata = { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0}; static unsigned int cs8900_irq_map[] = {10,11,12,5}; #endif +#endif #if DEBUGGING static unsigned int net_debug = DEBUGGING; @@ -236,11 +231,16 @@ struct net_local { unsigned char *end_dma_buff; /* points to the end of the buffer */ unsigned char *rx_dma_ptr; /* points to the next packet */ #endif +#ifdef CONFIG_CS89x0_PLATFORM + void __iomem *virt_addr;/* Virtual address for accessing the CS89x0. */ + unsigned long phys_addr;/* Physical address for accessing the CS89x0. */ + unsigned long size; /* Length of CS89x0 memory region. */ +#endif }; /* Index to functions, as function prototypes. */ -static int cs89x0_probe1(struct net_device *dev, int ioaddr, int modular); +static int cs89x0_probe1(struct net_device *dev, unsigned long ioaddr, int modular); static int net_open(struct net_device *dev); static netdev_tx_t net_send_packet(struct sk_buff *skb, struct net_device *dev); static irqreturn_t net_interrupt(int irq, void *dev_id); @@ -294,6 +294,7 @@ static int __init media_fn(char *str) __setup("cs89x0_media=", media_fn); +#ifndef CONFIG_CS89x0_PLATFORM /* Check for a network adaptor of this type, and return '0' iff one exists. If dev->base_addr == 0, probe all likely locations. If dev->base_addr == 1, always return failure. @@ -343,6 +344,7 @@ out: return ERR_PTR(err); } #endif +#endif #if defined(CONFIG_MACH_IXDP2351) static u16 @@ -504,7 +506,7 @@ static const struct net_device_ops net_ops = { */ static int __init -cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) +cs89x0_probe1(struct net_device *dev, unsigned long ioaddr, int modular) { struct net_local *lp = netdev_priv(dev); static unsigned version_printed; @@ -529,15 +531,12 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) lp->force = g_cs89x0_media__force; #endif -#if defined(CONFIG_MACH_QQ2440) - lp->force |= FORCE_RJ45 | FORCE_FULL; -#endif } /* Grab the region so we can find another board if autoIRQ fails. */ /* WTF is going on here? */ if (!request_region(ioaddr & ~3, NETCARD_IO_EXTENT, DRV_NAME)) { - printk(KERN_ERR "%s: request_region(0x%x, 0x%x) failed\n", + printk(KERN_ERR "%s: request_region(0x%lx, 0x%x) failed\n", DRV_NAME, ioaddr, NETCARD_IO_EXTENT); retval = -EBUSY; goto out1; @@ -549,7 +548,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) will skip the test for the ADD_PORT. */ if (ioaddr & 1) { if (net_debug > 1) - printk(KERN_INFO "%s: odd ioaddr 0x%x\n", dev->name, ioaddr); + printk(KERN_INFO "%s: odd ioaddr 0x%lx\n", dev->name, ioaddr); if ((ioaddr & 2) != 2) if ((readword(ioaddr & ~3, ADD_PORT) & ADD_MASK) != ADD_SIG) { printk(KERN_ERR "%s: bad signature 0x%x\n", @@ -560,13 +559,13 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) } ioaddr &= ~3; - printk(KERN_DEBUG "PP_addr at %x[%x]: 0x%x\n", + printk(KERN_DEBUG "PP_addr at %lx[%x]: 0x%x\n", ioaddr, ADD_PORT, readword(ioaddr, ADD_PORT)); writeword(ioaddr, ADD_PORT, PP_ChipID); tmp = readword(ioaddr, DATA_PORT); if (tmp != CHIP_EISA_ID_SIG) { - printk(KERN_DEBUG "%s: incorrect signature at %x[%x]: 0x%x!=" + printk(KERN_DEBUG "%s: incorrect signature at %lx[%x]: 0x%x!=" CHIP_EISA_ID_SIG_STR "\n", dev->name, ioaddr, DATA_PORT, tmp); retval = -ENODEV; @@ -736,8 +735,9 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) dev->irq = i; } else { i = lp->isa_config & INT_NO_MASK; +#ifndef CONFIG_CS89x0_PLATFORM if (lp->chip_type == CS8900) { -#ifdef CONFIG_CS89x0_NONISA_IRQ +#ifdef CS89x0_NONISA_IRQ i = cs8900_irq_map[0]; #else /* Translate the IRQ using the IRQ mapping table. */ @@ -758,6 +758,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) } #endif } +#endif if (!dev->irq) dev->irq = i; } @@ -1168,6 +1169,7 @@ write_irq(struct net_device *dev, int chip_type, int irq) int i; if (chip_type == CS8900) { +#ifndef CONFIG_CS89x0_PLATFORM /* Search the mapping table for the corresponding IRQ pin. */ for (i = 0; i != ARRAY_SIZE(cs8900_irq_map); i++) if (cs8900_irq_map[i] == irq) @@ -1175,6 +1177,10 @@ write_irq(struct net_device *dev, int chip_type, int irq) /* Not found */ if (i == ARRAY_SIZE(cs8900_irq_map)) i = 3; +#else + /* INTRQ0 pin is used for interrupt generation. */ + i = 0; +#endif writereg(dev, PP_CS8900_ISAINT, i); } else { writereg(dev, PP_CS8920_ISAINT, irq); @@ -1228,7 +1234,7 @@ net_open(struct net_device *dev) } else { -#ifndef CONFIG_CS89x0_NONISA_IRQ +#if !defined(CS89x0_NONISA_IRQ) && !defined(CONFIG_CS89x0_PLATFORM) if (((1 << dev->irq) & lp->irq_map) == 0) { printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n", dev->name, dev->irq, lp->irq_map); @@ -1746,7 +1752,7 @@ static int set_mac_address(struct net_device *dev, void *p) return 0; } -#ifdef MODULE +#if defined(MODULE) && !defined(CONFIG_CS89x0_PLATFORM) static struct net_device *dev_cs89x0; @@ -1900,7 +1906,97 @@ cleanup_module(void) release_region(dev_cs89x0->base_addr, NETCARD_IO_EXTENT); free_netdev(dev_cs89x0); } -#endif /* MODULE */ +#endif /* MODULE && !CONFIG_CS89x0_PLATFORM */ + +#ifdef CONFIG_CS89x0_PLATFORM +static int __init cs89x0_platform_probe(struct platform_device *pdev) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct net_local)); + struct net_local *lp; + struct resource *mem_res; + int err; + + if (!dev) + return -ENOMEM; + + lp = netdev_priv(dev); + + mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dev->irq = platform_get_irq(pdev, 0); + if (mem_res == NULL || dev->irq <= 0) { + dev_warn(&dev->dev, "memory/interrupt resource missing.\n"); + err = -ENXIO; + goto free; + } + + lp->phys_addr = mem_res->start; + lp->size = resource_size(mem_res); + if (!request_mem_region(lp->phys_addr, lp->size, DRV_NAME)) { + dev_warn(&dev->dev, "request_mem_region() failed.\n"); + err = -EBUSY; + goto free; + } + + lp->virt_addr = ioremap(lp->phys_addr, lp->size); + if (!lp->virt_addr) { + dev_warn(&dev->dev, "ioremap() failed.\n"); + err = -ENOMEM; + goto release; + } + + err = cs89x0_probe1(dev, (unsigned long)lp->virt_addr, 0); + if (err) { + dev_warn(&dev->dev, "no cs8900 or cs8920 detected.\n"); + goto unmap; + } + + platform_set_drvdata(pdev, dev); + return 0; + +unmap: + iounmap(lp->virt_addr); +release: + release_mem_region(lp->phys_addr, lp->size); +free: + free_netdev(dev); + return err; +} + +static int cs89x0_platform_remove(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct net_local *lp = netdev_priv(dev); + + unregister_netdev(dev); + iounmap(lp->virt_addr); + release_mem_region(lp->phys_addr, lp->size); + free_netdev(dev); + return 0; +} + +static struct platform_driver cs89x0_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .remove = cs89x0_platform_remove, +}; + +static int __init cs89x0_init(void) +{ + return platform_driver_probe(&cs89x0_driver, cs89x0_platform_probe); +} + +module_init(cs89x0_init); + +static void __exit cs89x0_cleanup(void) +{ + platform_driver_unregister(&cs89x0_driver); +} + +module_exit(cs89x0_cleanup); + +#endif /* CONFIG_CS89x0_PLATFORM */ /* * Local variables: diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index a229de9..36db5a4 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -258,14 +258,6 @@ config REGULATOR_DB8500_PRCMU This driver supports the voltage domain regulators controlled by the DB8500 PRCMU -config REGULATOR_BQ24022 - tristate "TI bq24022 Dual Input 1-Cell Li-Ion Charger IC" - help - This driver controls a TI bq24022 Charger attached via - GPIOs. The provided current regulator can enable/disable - charging select between 100 mA and 500 mA charging current - limit. - config REGULATOR_TPS6105X tristate "TI TPS6105X Power regulators" depends on TPS6105X diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index b5042c8..94b5274 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -16,7 +16,6 @@ obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o -obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o obj-$(CONFIG_REGULATOR_DA903X) += da903x.o obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o diff --git a/drivers/regulator/bq24022.c b/drivers/regulator/bq24022.c deleted file mode 100644 index 9fab6d1..0000000 --- a/drivers/regulator/bq24022.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Support for TI bq24022 (bqTINY-II) Dual Input (USB/AC Adpater) - * 1-Cell Li-Ion Charger connected via GPIOs. - * - * Copyright (c) 2008 Philipp Zabel - * - * 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/kernel.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/err.h> -#include <linux/module.h> -#include <linux/gpio.h> -#include <linux/regulator/bq24022.h> -#include <linux/regulator/driver.h> - - -static int bq24022_set_current_limit(struct regulator_dev *rdev, - int min_uA, int max_uA) -{ - struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev); - - dev_dbg(rdev_get_dev(rdev), "setting current limit to %s mA\n", - max_uA >= 500000 ? "500" : "100"); - - /* REVISIT: maybe return error if min_uA != 0 ? */ - gpio_set_value(pdata->gpio_iset2, max_uA >= 500000); - return 0; -} - -static int bq24022_get_current_limit(struct regulator_dev *rdev) -{ - struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev); - - return gpio_get_value(pdata->gpio_iset2) ? 500000 : 100000; -} - -static int bq24022_enable(struct regulator_dev *rdev) -{ - struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev); - - dev_dbg(rdev_get_dev(rdev), "enabling charger\n"); - - gpio_set_value(pdata->gpio_nce, 0); - return 0; -} - -static int bq24022_disable(struct regulator_dev *rdev) -{ - struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev); - - dev_dbg(rdev_get_dev(rdev), "disabling charger\n"); - - gpio_set_value(pdata->gpio_nce, 1); - return 0; -} - -static int bq24022_is_enabled(struct regulator_dev *rdev) -{ - struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev); - - return !gpio_get_value(pdata->gpio_nce); -} - -static struct regulator_ops bq24022_ops = { - .set_current_limit = bq24022_set_current_limit, - .get_current_limit = bq24022_get_current_limit, - .enable = bq24022_enable, - .disable = bq24022_disable, - .is_enabled = bq24022_is_enabled, -}; - -static struct regulator_desc bq24022_desc = { - .name = "bq24022", - .ops = &bq24022_ops, - .type = REGULATOR_CURRENT, - .owner = THIS_MODULE, -}; - -static int __init bq24022_probe(struct platform_device *pdev) -{ - struct bq24022_mach_info *pdata = pdev->dev.platform_data; - struct regulator_dev *bq24022; - int ret; - - if (!pdata || !pdata->gpio_nce || !pdata->gpio_iset2) - return -EINVAL; - - ret = gpio_request(pdata->gpio_nce, "ncharge_en"); - if (ret) { - dev_dbg(&pdev->dev, "couldn't request nCE GPIO: %d\n", - pdata->gpio_nce); - goto err_ce; - } - ret = gpio_request(pdata->gpio_iset2, "charge_mode"); - if (ret) { - dev_dbg(&pdev->dev, "couldn't request ISET2 GPIO: %d\n", - pdata->gpio_iset2); - goto err_iset2; - } - ret = gpio_direction_output(pdata->gpio_iset2, 0); - ret = gpio_direction_output(pdata->gpio_nce, 1); - - bq24022 = regulator_register(&bq24022_desc, &pdev->dev, - pdata->init_data, pdata, NULL); - if (IS_ERR(bq24022)) { - dev_dbg(&pdev->dev, "couldn't register regulator\n"); - ret = PTR_ERR(bq24022); - goto err_reg; - } - platform_set_drvdata(pdev, bq24022); - dev_dbg(&pdev->dev, "registered regulator\n"); - - return 0; -err_reg: - gpio_free(pdata->gpio_iset2); -err_iset2: - gpio_free(pdata->gpio_nce); -err_ce: - return ret; -} - -static int __devexit bq24022_remove(struct platform_device *pdev) -{ - struct bq24022_mach_info *pdata = pdev->dev.platform_data; - struct regulator_dev *bq24022 = platform_get_drvdata(pdev); - - regulator_unregister(bq24022); - gpio_free(pdata->gpio_iset2); - gpio_free(pdata->gpio_nce); - - return 0; -} - -static struct platform_driver bq24022_driver = { - .driver = { - .name = "bq24022", - }, - .remove = __devexit_p(bq24022_remove), -}; - -static int __init bq24022_init(void) -{ - return platform_driver_probe(&bq24022_driver, bq24022_probe); -} - -static void __exit bq24022_exit(void) -{ - platform_driver_unregister(&bq24022_driver); -} - -module_init(bq24022_init); -module_exit(bq24022_exit); - -MODULE_AUTHOR("Philipp Zabel"); -MODULE_DESCRIPTION("TI bq24022 Li-Ion Charger driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 4768a9d..8c8377d 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -780,8 +780,8 @@ config RTC_DRV_EP93XX will be called rtc-ep93xx. config RTC_DRV_SA1100 - tristate "SA11x0/PXA2xx" - depends on ARCH_SA1100 || ARCH_PXA + tristate "SA11x0/PXA2xx/PXA910" + depends on ARCH_SA1100 || ARCH_PXA || ARCH_MMP help If you say Y here you will get access to the real time clock built into your SA11x0 or PXA2xx CPU. diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index c543f6f..9ccea13 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -35,6 +35,8 @@ enum s3c_cpu_type { TYPE_S3C2410, + TYPE_S3C2416, + TYPE_S3C2443, TYPE_S3C64XX, }; @@ -132,6 +134,7 @@ static int s3c_rtc_setfreq(struct device *dev, int freq) struct platform_device *pdev = to_platform_device(dev); struct rtc_device *rtc_dev = platform_get_drvdata(pdev); unsigned int tmp = 0; + int val; if (!is_power_of_2(freq)) return -EINVAL; @@ -139,12 +142,22 @@ static int s3c_rtc_setfreq(struct device *dev, int freq) clk_enable(rtc_clk); spin_lock_irq(&s3c_rtc_pie_lock); - if (s3c_rtc_cpu_type == TYPE_S3C2410) { + if (s3c_rtc_cpu_type != TYPE_S3C64XX) { tmp = readb(s3c_rtc_base + S3C2410_TICNT); tmp &= S3C2410_TICNT_ENABLE; } - tmp |= (rtc_dev->max_user_freq / freq)-1; + val = (rtc_dev->max_user_freq / freq) - 1; + + if (s3c_rtc_cpu_type == TYPE_S3C2416 || s3c_rtc_cpu_type == TYPE_S3C2443) { + tmp |= S3C2443_TICNT_PART(val); + writel(S3C2443_TICNT1_PART(val), s3c_rtc_base + S3C2443_TICNT1); + + if (s3c_rtc_cpu_type == TYPE_S3C2416) + writel(S3C2416_TICNT2_PART(val), s3c_rtc_base + S3C2416_TICNT2); + } else { + tmp |= val; + } writel(tmp, s3c_rtc_base + S3C2410_TICNT); spin_unlock_irq(&s3c_rtc_pie_lock); @@ -371,7 +384,7 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en) tmp &= ~S3C2410_RTCCON_RTCEN; writew(tmp, base + S3C2410_RTCCON); - if (s3c_rtc_cpu_type == TYPE_S3C2410) { + if (s3c_rtc_cpu_type != TYPE_S3C64XX) { tmp = readb(base + S3C2410_TICNT); tmp &= ~S3C2410_TICNT_ENABLE; writeb(tmp, base + S3C2410_TICNT); @@ -428,12 +441,27 @@ static int __devexit s3c_rtc_remove(struct platform_device *dev) return 0; } +static const struct of_device_id s3c_rtc_dt_match[]; + +static inline int s3c_rtc_get_driver_data(struct platform_device *pdev) +{ +#ifdef CONFIG_OF + if (pdev->dev.of_node) { + const struct of_device_id *match; + match = of_match_node(s3c_rtc_dt_match, pdev->dev.of_node); + return match->data; + } +#endif + return platform_get_device_id(pdev)->driver_data; +} + static int __devinit s3c_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; struct rtc_time rtc_tm; struct resource *res; int ret; + int tmp; pr_debug("%s: probe=%p\n", __func__, pdev); @@ -508,13 +536,7 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) goto err_nortc; } -#ifdef CONFIG_OF - if (pdev->dev.of_node) - s3c_rtc_cpu_type = of_device_is_compatible(pdev->dev.of_node, - "samsung,s3c6410-rtc") ? TYPE_S3C64XX : TYPE_S3C2410; - else -#endif - s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data; + s3c_rtc_cpu_type = s3c_rtc_get_driver_data(pdev); /* Check RTC Time */ @@ -533,11 +555,17 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it\n"); } - if (s3c_rtc_cpu_type == TYPE_S3C64XX) + if (s3c_rtc_cpu_type != TYPE_S3C2410) rtc->max_user_freq = 32768; else rtc->max_user_freq = 128; + if (s3c_rtc_cpu_type == TYPE_S3C2416 || s3c_rtc_cpu_type == TYPE_S3C2443) { + tmp = readw(s3c_rtc_base + S3C2410_RTCCON); + tmp |= S3C2443_RTCCON_TICSEL; + writew(tmp, s3c_rtc_base + S3C2410_RTCCON); + } + platform_set_drvdata(pdev, rtc); s3c_rtc_setfreq(&pdev->dev, 1); @@ -638,8 +666,19 @@ static int s3c_rtc_resume(struct platform_device *pdev) #ifdef CONFIG_OF static const struct of_device_id s3c_rtc_dt_match[] = { - { .compatible = "samsung,s3c2410-rtc" }, - { .compatible = "samsung,s3c6410-rtc" }, + { + .compatible = "samsung,s3c2410-rtc" + .data = TYPE_S3C2410, + }, { + .compatible = "samsung,s3c2416-rtc" + .data = TYPE_S3C2416, + }, { + .compatible = "samsung,s3c2443-rtc" + .data = TYPE_S3C2443, + }, { + .compatible = "samsung,s3c6410-rtc" + .data = TYPE_S3C64XX, + }, {}, }; MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match); @@ -652,6 +691,12 @@ static struct platform_device_id s3c_rtc_driver_ids[] = { .name = "s3c2410-rtc", .driver_data = TYPE_S3C2410, }, { + .name = "s3c2416-rtc", + .driver_data = TYPE_S3C2416, + }, { + .name = "s3c2443-rtc", + .driver_data = TYPE_S3C2443, + }, { .name = "s3c64xx-rtc", .driver_data = TYPE_S3C64XX, }, diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 44cd81c..fa512ed 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -23,35 +23,44 @@ #include <linux/platform_device.h> #include <linux/module.h> +#include <linux/clk.h> #include <linux/rtc.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/interrupt.h> +#include <linux/slab.h> #include <linux/string.h> +#include <linux/of.h> #include <linux/pm.h> #include <linux/bitops.h> #include <mach/hardware.h> #include <asm/irq.h> -#ifdef CONFIG_ARCH_PXA +#if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP) #include <mach/regs-rtc.h> #endif #define RTC_DEF_DIVIDER (32768 - 1) #define RTC_DEF_TRIM 0 - -static const unsigned long RTC_FREQ = 1024; -static DEFINE_SPINLOCK(sa1100_rtc_lock); +#define RTC_FREQ 1024 + +struct sa1100_rtc { + spinlock_t lock; + int irq_1hz; + int irq_alarm; + struct rtc_device *rtc; + struct clk *clk; +}; static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) { - struct platform_device *pdev = to_platform_device(dev_id); - struct rtc_device *rtc = platform_get_drvdata(pdev); + struct sa1100_rtc *info = dev_get_drvdata(dev_id); + struct rtc_device *rtc = info->rtc; unsigned int rtsr; unsigned long events = 0; - spin_lock(&sa1100_rtc_lock); + spin_lock(&info->lock); rtsr = RTSR; /* clear interrupt sources */ @@ -87,26 +96,28 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) rtc_update_irq(rtc, 1, events); - spin_unlock(&sa1100_rtc_lock); + spin_unlock(&info->lock); return IRQ_HANDLED; } static int sa1100_rtc_open(struct device *dev) { + struct sa1100_rtc *info = dev_get_drvdata(dev); + struct rtc_device *rtc = info->rtc; int ret; - struct platform_device *plat_dev = to_platform_device(dev); - struct rtc_device *rtc = platform_get_drvdata(plat_dev); - ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, 0, "rtc 1Hz", dev); + ret = clk_prepare_enable(info->clk); + if (ret) + goto fail_clk; + ret = request_irq(info->irq_1hz, sa1100_rtc_interrupt, 0, "rtc 1Hz", dev); if (ret) { - dev_err(dev, "IRQ %d already in use.\n", IRQ_RTC1Hz); + dev_err(dev, "IRQ %d already in use.\n", info->irq_1hz); goto fail_ui; } - ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, 0, - "rtc Alrm", dev); + ret = request_irq(info->irq_alarm, sa1100_rtc_interrupt, 0, "rtc Alrm", dev); if (ret) { - dev_err(dev, "IRQ %d already in use.\n", IRQ_RTCAlrm); + dev_err(dev, "IRQ %d already in use.\n", info->irq_alarm); goto fail_ai; } rtc->max_user_freq = RTC_FREQ; @@ -115,29 +126,36 @@ static int sa1100_rtc_open(struct device *dev) return 0; fail_ai: - free_irq(IRQ_RTC1Hz, dev); + free_irq(info->irq_1hz, dev); fail_ui: + clk_disable_unprepare(info->clk); + fail_clk: return ret; } static void sa1100_rtc_release(struct device *dev) { - spin_lock_irq(&sa1100_rtc_lock); + struct sa1100_rtc *info = dev_get_drvdata(dev); + + spin_lock_irq(&info->lock); RTSR = 0; - spin_unlock_irq(&sa1100_rtc_lock); + spin_unlock_irq(&info->lock); - free_irq(IRQ_RTCAlrm, dev); - free_irq(IRQ_RTC1Hz, dev); + free_irq(info->irq_alarm, dev); + free_irq(info->irq_1hz, dev); + clk_disable_unprepare(info->clk); } static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { - spin_lock_irq(&sa1100_rtc_lock); + struct sa1100_rtc *info = dev_get_drvdata(dev); + + spin_lock_irq(&info->lock); if (enabled) RTSR |= RTSR_ALE; else RTSR &= ~RTSR_ALE; - spin_unlock_irq(&sa1100_rtc_lock); + spin_unlock_irq(&info->lock); return 0; } @@ -170,10 +188,11 @@ static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { + struct sa1100_rtc *info = dev_get_drvdata(dev); unsigned long time; int ret; - spin_lock_irq(&sa1100_rtc_lock); + spin_lock_irq(&info->lock); ret = rtc_tm_to_time(&alrm->time, &time); if (ret != 0) goto out; @@ -184,7 +203,7 @@ static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) else RTSR &= ~RTSR_ALE; out: - spin_unlock_irq(&sa1100_rtc_lock); + spin_unlock_irq(&info->lock); return ret; } @@ -211,6 +230,27 @@ static const struct rtc_class_ops sa1100_rtc_ops = { static int sa1100_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; + struct sa1100_rtc *info; + int irq_1hz, irq_alarm, ret = 0; + + irq_1hz = platform_get_irq_byname(pdev, "rtc 1Hz"); + irq_alarm = platform_get_irq_byname(pdev, "rtc alarm"); + if (irq_1hz < 0 || irq_alarm < 0) + return -ENODEV; + + info = kzalloc(sizeof(struct sa1100_rtc), GFP_KERNEL); + if (!info) + return -ENOMEM; + info->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(info->clk)) { + dev_err(&pdev->dev, "failed to find rtc clock source\n"); + ret = PTR_ERR(info->clk); + goto err_clk; + } + info->irq_1hz = irq_1hz; + info->irq_alarm = irq_alarm; + spin_lock_init(&info->lock); + platform_set_drvdata(pdev, info); /* * According to the manual we should be able to let RTTR be zero @@ -232,10 +272,11 @@ static int sa1100_rtc_probe(struct platform_device *pdev) rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) - return PTR_ERR(rtc); - - platform_set_drvdata(pdev, rtc); + if (IS_ERR(rtc)) { + ret = PTR_ERR(rtc); + goto err_dev; + } + info->rtc = rtc; /* Fix for a nasty initialization problem the in SA11xx RTSR register. * See also the comments in sa1100_rtc_interrupt(). @@ -262,14 +303,24 @@ static int sa1100_rtc_probe(struct platform_device *pdev) RTSR = RTSR_AL | RTSR_HZ; return 0; +err_dev: + platform_set_drvdata(pdev, NULL); + clk_put(info->clk); +err_clk: + kfree(info); + return ret; } static int sa1100_rtc_remove(struct platform_device *pdev) { - struct rtc_device *rtc = platform_get_drvdata(pdev); + struct sa1100_rtc *info = platform_get_drvdata(pdev); - if (rtc) - rtc_device_unregister(rtc); + if (info) { + rtc_device_unregister(info->rtc); + clk_put(info->clk); + platform_set_drvdata(pdev, NULL); + kfree(info); + } return 0; } @@ -277,15 +328,17 @@ static int sa1100_rtc_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int sa1100_rtc_suspend(struct device *dev) { + struct sa1100_rtc *info = dev_get_drvdata(dev); if (device_may_wakeup(dev)) - enable_irq_wake(IRQ_RTCAlrm); + enable_irq_wake(info->irq_alarm); return 0; } static int sa1100_rtc_resume(struct device *dev) { + struct sa1100_rtc *info = dev_get_drvdata(dev); if (device_may_wakeup(dev)) - disable_irq_wake(IRQ_RTCAlrm); + disable_irq_wake(info->irq_alarm); return 0; } @@ -295,6 +348,13 @@ static const struct dev_pm_ops sa1100_rtc_pm_ops = { }; #endif +static struct of_device_id sa1100_rtc_dt_ids[] = { + { .compatible = "mrvl,sa1100-rtc", }, + { .compatible = "mrvl,mmp-rtc", }, + {} +}; +MODULE_DEVICE_TABLE(of, sa1100_rtc_dt_ids); + static struct platform_driver sa1100_rtc_driver = { .probe = sa1100_rtc_probe, .remove = sa1100_rtc_remove, @@ -303,6 +363,7 @@ static struct platform_driver sa1100_rtc_driver = { #ifdef CONFIG_PM .pm = &sa1100_rtc_pm_ops, #endif + .of_match_table = sa1100_rtc_dt_ids, }, }; diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 0b7fed7..e7fecee 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1508,7 +1508,7 @@ static int serial_imx_probe(struct platform_device *pdev) ret = PTR_ERR(sport->clk); goto unmap; } - clk_enable(sport->clk); + clk_prepare_enable(sport->clk); sport->port.uartclk = clk_get_rate(sport->clk); @@ -1531,8 +1531,8 @@ deinit: if (pdata && pdata->exit) pdata->exit(pdev); clkput: + clk_disable_unprepare(sport->clk); clk_put(sport->clk); - clk_disable(sport->clk); unmap: iounmap(sport->port.membase); free: @@ -1552,11 +1552,10 @@ static int serial_imx_remove(struct platform_device *pdev) if (sport) { uart_remove_one_port(&imx_reg, &sport->port); + clk_disable_unprepare(sport->clk); clk_put(sport->clk); } - clk_disable(sport->clk); - if (pdata && pdata->exit) pdata->exit(pdev); diff --git a/include/linux/platform_data/tegra_emc.h b/include/linux/platform_data/tegra_emc.h new file mode 100644 index 0000000..df67505 --- /dev/null +++ b/include/linux/platform_data/tegra_emc.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2011 Google, Inc. + * + * Author: + * Colin Cross <ccross@android.com> + * Olof Johansson <olof@lixom.net> + * + * 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. + * + */ + +#ifndef __TEGRA_EMC_H_ +#define __TEGRA_EMC_H_ + +#define TEGRA_EMC_NUM_REGS 46 + +struct tegra_emc_table { + unsigned long rate; + u32 regs[TEGRA_EMC_NUM_REGS]; +}; + +struct tegra_emc_pdata { + int num_tables; + struct tegra_emc_table *tables; +}; + +#endif diff --git a/include/linux/regulator/bq24022.h b/include/linux/regulator/bq24022.h deleted file mode 100644 index a6d0140..0000000 --- a/include/linux/regulator/bq24022.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Support for TI bq24022 (bqTINY-II) Dual Input (USB/AC Adpater) - * 1-Cell Li-Ion Charger connected via GPIOs. - * - * Copyright (c) 2008 Philipp Zabel - * - * 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. - * - */ - -struct regulator_init_data; - -/** - * bq24022_mach_info - platform data for bq24022 - * @gpio_nce: GPIO line connected to the nCE pin, used to enable / disable charging - * @gpio_iset2: GPIO line connected to the ISET2 pin, used to limit charging current to 100 mA / 500 mA - */ -struct bq24022_mach_info { - int gpio_nce; - int gpio_iset2; - struct regulator_init_data *init_data; -}; diff --git a/sound/soc/imx/imx-audmux.c b/sound/soc/imx/imx-audmux.c index a839494..601df80 100644 --- a/sound/soc/imx/imx-audmux.c +++ b/sound/soc/imx/imx-audmux.c @@ -80,13 +80,13 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf, return -ENOMEM; if (audmux_clk) - clk_enable(audmux_clk); + clk_prepare_enable(audmux_clk); ptcr = readl(audmux_base + IMX_AUDMUX_V2_PTCR(port)); pdcr = readl(audmux_base + IMX_AUDMUX_V2_PDCR(port)); if (audmux_clk) - clk_disable(audmux_clk); + clk_disable_unprepare(audmux_clk); ret = snprintf(buf, PAGE_SIZE, "PDCR: %08x\nPTCR: %08x\n", pdcr, ptcr); @@ -237,13 +237,13 @@ int imx_audmux_v2_configure_port(unsigned int port, unsigned int ptcr, return -ENOSYS; if (audmux_clk) - clk_enable(audmux_clk); + clk_prepare_enable(audmux_clk); writel(ptcr, audmux_base + IMX_AUDMUX_V2_PTCR(port)); writel(pdcr, audmux_base + IMX_AUDMUX_V2_PDCR(port)); if (audmux_clk) - clk_disable(audmux_clk); + clk_disable_unprepare(audmux_clk); return 0; } |