diff options
author | Olof Johansson <olof@lixom.net> | 2015-08-18 16:10:05 -0400 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2015-08-18 16:10:05 -0400 |
commit | 207b504a63b849519cc285c3ddb37411d67beead (patch) | |
tree | 9628c94cc7d9af0bab209c373b8f0c5bb904801f | |
parent | f9511a4fc47940c7b08ae51567bd9bddb54b8461 (diff) | |
parent | 8a0fa1843638c5078e6606114ed8bdf9ea56fab1 (diff) |
Merge tag 'imx-soc-4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux into next/soc
The i.MX SoC changes for 4.3:
- Add i.MX6 Ultralite SoC support, which is the newest addition to
i.MX6 family. It integrates a single Cortex-A7 core and a power
management module that reduces the complexity of external power
supply and simplifies power sequencing.
- Change SNVS RTC driver to use syscon interface for register access,
and add SNVS power key driver support.
- Add a second clock for mxc rtc driver, and support device tree probe
for the driver.
- Add FEC MAC reference clock and phy fixup initialization for i.MX6UL
platform.
* tag 'imx-soc-4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux:
rtc: snvs: select option REGMAP_MMIO
ARM: imx6ul: add fec MAC refrence clock and phy fixup init
ARM: imx6ul: add fec bits to GPR syscon definition
rtc: mxc: add support of device tree
dt-binding: document the binding for mxc rtc
rtc: mxc: use a second rtc clock
input: snvs_pwrkey: use "wakeup-source" as deivce tree property name
Document: devicetree: input: imx: i.mx snvs power device tree bindings
input: keyboard: imx: add snvs power key driver
Document: dt: fsl: snvs: change support syscon
rtc: snvs: use syscon to access register
ARM: imx: add low-level debug support for i.mx6ul
ARM: imx: add i.mx6ul msl support
Signed-off-by: Olof Johansson <olof@lixom.net>
-rw-r--r-- | Documentation/devicetree/bindings/crypto/fsl-sec4.txt | 91 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/input/snvs-pwrkey.txt | 1 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/rtc/rtc-mxc.txt | 26 | ||||
-rw-r--r-- | arch/arm/Kconfig.debug | 9 | ||||
-rw-r--r-- | arch/arm/include/debug/imx-uart.h | 13 | ||||
-rw-r--r-- | arch/arm/mach-imx/Kconfig | 8 | ||||
-rw-r--r-- | arch/arm/mach-imx/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-imx/cpu.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-imx/mach-imx6ul.c | 86 | ||||
-rw-r--r-- | arch/arm/mach-imx/mxc.h | 6 | ||||
-rw-r--r-- | drivers/input/keyboard/Kconfig | 11 | ||||
-rw-r--r-- | drivers/input/keyboard/Makefile | 1 | ||||
-rw-r--r-- | drivers/input/keyboard/snvs_pwrkey.c | 227 | ||||
-rw-r--r-- | drivers/rtc/Kconfig | 1 | ||||
-rw-r--r-- | drivers/rtc/rtc-mxc.c | 60 | ||||
-rw-r--r-- | drivers/rtc/rtc-snvs.c | 132 | ||||
-rw-r--r-- | include/linux/mfd/syscon/imx6q-iomuxc-gpr.h | 8 |
17 files changed, 592 insertions, 92 deletions
diff --git a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt index e4022776ac6e..f16bbd6644b8 100644 --- a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt +++ b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt | |||
@@ -288,12 +288,13 @@ Secure Non-Volatile Storage (SNVS) Node | |||
288 | Node defines address range and the associated | 288 | Node defines address range and the associated |
289 | interrupt for the SNVS function. This function | 289 | interrupt for the SNVS function. This function |
290 | monitors security state information & reports | 290 | monitors security state information & reports |
291 | security violations. | 291 | security violations. This also included rtc, |
292 | system power off and ON/OFF key. | ||
292 | 293 | ||
293 | - compatible | 294 | - compatible |
294 | Usage: required | 295 | Usage: required |
295 | Value type: <string> | 296 | Value type: <string> |
296 | Definition: Must include "fsl,sec-v4.0-mon". | 297 | Definition: Must include "fsl,sec-v4.0-mon" and "syscon". |
297 | 298 | ||
298 | - reg | 299 | - reg |
299 | Usage: required | 300 | Usage: required |
@@ -324,7 +325,7 @@ Secure Non-Volatile Storage (SNVS) Node | |||
324 | the child address, parent address, & length. | 325 | the child address, parent address, & length. |
325 | 326 | ||
326 | - interrupts | 327 | - interrupts |
327 | Usage: required | 328 | Usage: optional |
328 | Value type: <prop_encoded-array> | 329 | Value type: <prop_encoded-array> |
329 | Definition: Specifies the interrupts generated by this | 330 | Definition: Specifies the interrupts generated by this |
330 | device. The value of the interrupts property | 331 | device. The value of the interrupts property |
@@ -341,7 +342,7 @@ Secure Non-Volatile Storage (SNVS) Node | |||
341 | 342 | ||
342 | EXAMPLE | 343 | EXAMPLE |
343 | sec_mon@314000 { | 344 | sec_mon@314000 { |
344 | compatible = "fsl,sec-v4.0-mon"; | 345 | compatible = "fsl,sec-v4.0-mon", "syscon"; |
345 | reg = <0x314000 0x1000>; | 346 | reg = <0x314000 0x1000>; |
346 | ranges = <0 0x314000 0x1000>; | 347 | ranges = <0 0x314000 0x1000>; |
347 | interrupt-parent = <&mpic>; | 348 | interrupt-parent = <&mpic>; |
@@ -358,16 +359,72 @@ Secure Non-Volatile Storage (SNVS) Low Power (LP) RTC Node | |||
358 | Value type: <string> | 359 | Value type: <string> |
359 | Definition: Must include "fsl,sec-v4.0-mon-rtc-lp". | 360 | Definition: Must include "fsl,sec-v4.0-mon-rtc-lp". |
360 | 361 | ||
361 | - reg | 362 | - interrupts |
362 | Usage: required | 363 | Usage: required |
363 | Value type: <prop-encoded-array> | 364 | Value type: <prop_encoded-array> |
364 | Definition: A standard property. Specifies the physical | 365 | Definition: Specifies the interrupts generated by this |
365 | address and length of the SNVS LP configuration registers. | 366 | device. The value of the interrupts property |
367 | consists of one interrupt specifier. The format | ||
368 | of the specifier is defined by the binding document | ||
369 | describing the node's interrupt parent. | ||
370 | |||
371 | - regmap | ||
372 | Usage: required | ||
373 | Value type: <phandle> | ||
374 | Definition: this is phandle to the register map node. | ||
375 | |||
376 | - offset | ||
377 | Usage: option | ||
378 | value type: <u32> | ||
379 | Definition: LP register offset. default it is 0x34. | ||
366 | 380 | ||
367 | EXAMPLE | 381 | EXAMPLE |
368 | sec_mon_rtc_lp@314000 { | 382 | sec_mon_rtc_lp@1 { |
369 | compatible = "fsl,sec-v4.0-mon-rtc-lp"; | 383 | compatible = "fsl,sec-v4.0-mon-rtc-lp"; |
370 | reg = <0x34 0x58>; | 384 | interrupts = <93 2>; |
385 | regmap = <&snvs>; | ||
386 | offset = <0x34>; | ||
387 | }; | ||
388 | |||
389 | ===================================================================== | ||
390 | System ON/OFF key driver | ||
391 | |||
392 | The snvs-pwrkey is designed to enable POWER key function which controlled | ||
393 | by SNVS ONOFF, the driver can report the status of POWER key and wakeup | ||
394 | system if pressed after system suspend. | ||
395 | |||
396 | - compatible: | ||
397 | Usage: required | ||
398 | Value type: <string> | ||
399 | Definition: Mush include "fsl,sec-v4.0-pwrkey". | ||
400 | |||
401 | - interrupts: | ||
402 | Usage: required | ||
403 | Value type: <prop_encoded-array> | ||
404 | Definition: The SNVS ON/OFF interrupt number to the CPU(s). | ||
405 | |||
406 | - linux,keycode: | ||
407 | Usage: option | ||
408 | Value type: <int> | ||
409 | Definition: Keycode to emit, KEY_POWER by default. | ||
410 | |||
411 | - wakeup-source: | ||
412 | Usage: option | ||
413 | Value type: <boo> | ||
414 | Definition: Button can wake-up the system. | ||
415 | |||
416 | - regmap: | ||
417 | Usage: required: | ||
418 | Value type: <phandle> | ||
419 | Definition: this is phandle to the register map node. | ||
420 | |||
421 | EXAMPLE: | ||
422 | snvs-pwrkey@0x020cc000 { | ||
423 | compatible = "fsl,sec-v4.0-pwrkey"; | ||
424 | regmap = <&snvs>; | ||
425 | interrupts = <0 4 0x4> | ||
426 | linux,keycode = <116>; /* KEY_POWER */ | ||
427 | wakeup; | ||
371 | }; | 428 | }; |
372 | 429 | ||
373 | ===================================================================== | 430 | ===================================================================== |
@@ -443,12 +500,20 @@ FULL EXAMPLE | |||
443 | compatible = "fsl,sec-v4.0-mon"; | 500 | compatible = "fsl,sec-v4.0-mon"; |
444 | reg = <0x314000 0x1000>; | 501 | reg = <0x314000 0x1000>; |
445 | ranges = <0 0x314000 0x1000>; | 502 | ranges = <0 0x314000 0x1000>; |
446 | interrupt-parent = <&mpic>; | ||
447 | interrupts = <93 2>; | ||
448 | 503 | ||
449 | sec_mon_rtc_lp@34 { | 504 | sec_mon_rtc_lp@34 { |
450 | compatible = "fsl,sec-v4.0-mon-rtc-lp"; | 505 | compatible = "fsl,sec-v4.0-mon-rtc-lp"; |
451 | reg = <0x34 0x58>; | 506 | regmap = <&sec_mon>; |
507 | offset = <0x34>; | ||
508 | interrupts = <93 2>; | ||
509 | }; | ||
510 | |||
511 | snvs-pwrkey@0x020cc000 { | ||
512 | compatible = "fsl,sec-v4.0-pwrkey"; | ||
513 | regmap = <&sec_mon>; | ||
514 | interrupts = <0 4 0x4>; | ||
515 | linux,keycode = <116>; /* KEY_POWER */ | ||
516 | wakeup; | ||
452 | }; | 517 | }; |
453 | }; | 518 | }; |
454 | 519 | ||
diff --git a/Documentation/devicetree/bindings/input/snvs-pwrkey.txt b/Documentation/devicetree/bindings/input/snvs-pwrkey.txt new file mode 100644 index 000000000000..70c14250323b --- /dev/null +++ b/Documentation/devicetree/bindings/input/snvs-pwrkey.txt | |||
@@ -0,0 +1 @@ | |||
See Documentation/devicetree/bindings/crypto/fsl-sec4.txt | |||
diff --git a/Documentation/devicetree/bindings/rtc/rtc-mxc.txt b/Documentation/devicetree/bindings/rtc/rtc-mxc.txt new file mode 100644 index 000000000000..5bcd31d995b0 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/rtc-mxc.txt | |||
@@ -0,0 +1,26 @@ | |||
1 | * Real Time Clock of the i.MX SoCs | ||
2 | |||
3 | RTC controller for the i.MX SoCs | ||
4 | |||
5 | Required properties: | ||
6 | - compatible: Should be "fsl,imx1-rtc" or "fsl,imx21-rtc". | ||
7 | - reg: physical base address of the controller and length of memory mapped | ||
8 | region. | ||
9 | - interrupts: IRQ line for the RTC. | ||
10 | - clocks: should contain two entries: | ||
11 | * one for the input reference | ||
12 | * one for the the SoC RTC | ||
13 | - clock-names: should contain: | ||
14 | * "ref" for the input reference clock | ||
15 | * "ipg" for the SoC RTC clock | ||
16 | |||
17 | Example: | ||
18 | |||
19 | rtc@10007000 { | ||
20 | compatible = "fsl,imx21-rtc"; | ||
21 | reg = <0x10007000 0x1000>; | ||
22 | interrupts = <22>; | ||
23 | clocks = <&clks IMX27_CLK_CKIL>, | ||
24 | <&clks IMX27_CLK_RTC_IPG_GATE>; | ||
25 | clock-names = "ref", "ipg"; | ||
26 | }; | ||
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 946c8c0fa1fb..0cfd7f947f6b 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug | |||
@@ -417,6 +417,13 @@ choice | |||
417 | Say Y here if you want kernel low-level debugging support | 417 | Say Y here if you want kernel low-level debugging support |
418 | on i.MX6SX. | 418 | on i.MX6SX. |
419 | 419 | ||
420 | config DEBUG_IMX6UL_UART | ||
421 | bool "i.MX6UL Debug UART" | ||
422 | depends on SOC_IMX6UL | ||
423 | help | ||
424 | Say Y here if you want kernel low-level debugging support | ||
425 | on i.MX6UL. | ||
426 | |||
420 | config DEBUG_IMX7D_UART | 427 | config DEBUG_IMX7D_UART |
421 | bool "i.MX7D Debug UART" | 428 | bool "i.MX7D Debug UART" |
422 | depends on SOC_IMX7D | 429 | depends on SOC_IMX7D |
@@ -1275,6 +1282,7 @@ config DEBUG_IMX_UART_PORT | |||
1275 | DEBUG_IMX6Q_UART || \ | 1282 | DEBUG_IMX6Q_UART || \ |
1276 | DEBUG_IMX6SL_UART || \ | 1283 | DEBUG_IMX6SL_UART || \ |
1277 | DEBUG_IMX6SX_UART || \ | 1284 | DEBUG_IMX6SX_UART || \ |
1285 | DEBUG_IMX6UL_UART || \ | ||
1278 | DEBUG_IMX7D_UART | 1286 | DEBUG_IMX7D_UART |
1279 | default 1 | 1287 | default 1 |
1280 | depends on ARCH_MXC | 1288 | depends on ARCH_MXC |
@@ -1326,6 +1334,7 @@ config DEBUG_LL_INCLUDE | |||
1326 | DEBUG_IMX6Q_UART || \ | 1334 | DEBUG_IMX6Q_UART || \ |
1327 | DEBUG_IMX6SL_UART || \ | 1335 | DEBUG_IMX6SL_UART || \ |
1328 | DEBUG_IMX6SX_UART || \ | 1336 | DEBUG_IMX6SX_UART || \ |
1337 | DEBUG_IMX6UL_UART || \ | ||
1329 | DEBUG_IMX7D_UART | 1338 | DEBUG_IMX7D_UART |
1330 | default "debug/ks8695.S" if DEBUG_KS8695_UART | 1339 | default "debug/ks8695.S" if DEBUG_KS8695_UART |
1331 | default "debug/msm.S" if DEBUG_QCOM_UARTDM | 1340 | default "debug/msm.S" if DEBUG_QCOM_UARTDM |
diff --git a/arch/arm/include/debug/imx-uart.h b/arch/arm/include/debug/imx-uart.h index 66f736f74684..bce58e975ad1 100644 --- a/arch/arm/include/debug/imx-uart.h +++ b/arch/arm/include/debug/imx-uart.h | |||
@@ -90,6 +90,17 @@ | |||
90 | #define IMX6SX_UART_BASE_ADDR(n) IMX6SX_UART##n##_BASE_ADDR | 90 | #define IMX6SX_UART_BASE_ADDR(n) IMX6SX_UART##n##_BASE_ADDR |
91 | #define IMX6SX_UART_BASE(n) IMX6SX_UART_BASE_ADDR(n) | 91 | #define IMX6SX_UART_BASE(n) IMX6SX_UART_BASE_ADDR(n) |
92 | 92 | ||
93 | #define IMX6UL_UART1_BASE_ADDR 0x02020000 | ||
94 | #define IMX6UL_UART2_BASE_ADDR 0x021e8000 | ||
95 | #define IMX6UL_UART3_BASE_ADDR 0x021ec000 | ||
96 | #define IMX6UL_UART4_BASE_ADDR 0x021f0000 | ||
97 | #define IMX6UL_UART5_BASE_ADDR 0x021f4000 | ||
98 | #define IMX6UL_UART6_BASE_ADDR 0x021fc000 | ||
99 | #define IMX6UL_UART7_BASE_ADDR 0x02018000 | ||
100 | #define IMX6UL_UART8_BASE_ADDR 0x02024000 | ||
101 | #define IMX6UL_UART_BASE_ADDR(n) IMX6UL_UART##n##_BASE_ADDR | ||
102 | #define IMX6UL_UART_BASE(n) IMX6UL_UART_BASE_ADDR(n) | ||
103 | |||
93 | #define IMX7D_UART1_BASE_ADDR 0x30860000 | 104 | #define IMX7D_UART1_BASE_ADDR 0x30860000 |
94 | #define IMX7D_UART2_BASE_ADDR 0x30890000 | 105 | #define IMX7D_UART2_BASE_ADDR 0x30890000 |
95 | #define IMX7D_UART3_BASE_ADDR 0x30880000 | 106 | #define IMX7D_UART3_BASE_ADDR 0x30880000 |
@@ -124,6 +135,8 @@ | |||
124 | #define UART_PADDR IMX_DEBUG_UART_BASE(IMX6SL) | 135 | #define UART_PADDR IMX_DEBUG_UART_BASE(IMX6SL) |
125 | #elif defined(CONFIG_DEBUG_IMX6SX_UART) | 136 | #elif defined(CONFIG_DEBUG_IMX6SX_UART) |
126 | #define UART_PADDR IMX_DEBUG_UART_BASE(IMX6SX) | 137 | #define UART_PADDR IMX_DEBUG_UART_BASE(IMX6SX) |
138 | #elif defined(CONFIG_DEBUG_IMX6UL_UART) | ||
139 | #define UART_PADDR IMX_DEBUG_UART_BASE(IMX6UL) | ||
127 | #elif defined(CONFIG_DEBUG_IMX7D_UART) | 140 | #elif defined(CONFIG_DEBUG_IMX7D_UART) |
128 | #define UART_PADDR IMX_DEBUG_UART_BASE(IMX7D) | 141 | #define UART_PADDR IMX_DEBUG_UART_BASE(IMX7D) |
129 | 142 | ||
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 573536f1bb73..8ceda2844c4f 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig | |||
@@ -548,6 +548,14 @@ config SOC_IMX6SX | |||
548 | help | 548 | help |
549 | This enables support for Freescale i.MX6 SoloX processor. | 549 | This enables support for Freescale i.MX6 SoloX processor. |
550 | 550 | ||
551 | config SOC_IMX6UL | ||
552 | bool "i.MX6 UltraLite support" | ||
553 | select PINCTRL_IMX6UL | ||
554 | select SOC_IMX6 | ||
555 | |||
556 | help | ||
557 | This enables support for Freescale i.MX6 UltraLite processor. | ||
558 | |||
551 | config SOC_IMX7D | 559 | config SOC_IMX7D |
552 | bool "i.MX7 Dual support" | 560 | bool "i.MX7 Dual support" |
553 | select PINCTRL_IMX7D | 561 | select PINCTRL_IMX7D |
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 37c502ac9595..fb689d813b09 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile | |||
@@ -83,6 +83,7 @@ endif | |||
83 | obj-$(CONFIG_SOC_IMX6Q) += mach-imx6q.o | 83 | obj-$(CONFIG_SOC_IMX6Q) += mach-imx6q.o |
84 | obj-$(CONFIG_SOC_IMX6SL) += mach-imx6sl.o | 84 | obj-$(CONFIG_SOC_IMX6SL) += mach-imx6sl.o |
85 | obj-$(CONFIG_SOC_IMX6SX) += mach-imx6sx.o | 85 | obj-$(CONFIG_SOC_IMX6SX) += mach-imx6sx.o |
86 | obj-$(CONFIG_SOC_IMX6UL) += mach-imx6ul.o | ||
86 | obj-$(CONFIG_SOC_IMX7D) += mach-imx7d.o | 87 | obj-$(CONFIG_SOC_IMX7D) += mach-imx7d.o |
87 | 88 | ||
88 | ifeq ($(CONFIG_SUSPEND),y) | 89 | ifeq ($(CONFIG_SUSPEND),y) |
diff --git a/arch/arm/mach-imx/cpu.c b/arch/arm/mach-imx/cpu.c index a7fa92a7b1d7..5b0f752d5507 100644 --- a/arch/arm/mach-imx/cpu.c +++ b/arch/arm/mach-imx/cpu.c | |||
@@ -130,6 +130,9 @@ struct device * __init imx_soc_device_init(void) | |||
130 | case MXC_CPU_IMX6Q: | 130 | case MXC_CPU_IMX6Q: |
131 | soc_id = "i.MX6Q"; | 131 | soc_id = "i.MX6Q"; |
132 | break; | 132 | break; |
133 | case MXC_CPU_IMX6UL: | ||
134 | soc_id = "i.MX6UL"; | ||
135 | break; | ||
133 | case MXC_CPU_IMX7D: | 136 | case MXC_CPU_IMX7D: |
134 | soc_id = "i.MX7D"; | 137 | soc_id = "i.MX7D"; |
135 | break; | 138 | break; |
diff --git a/arch/arm/mach-imx/mach-imx6ul.c b/arch/arm/mach-imx/mach-imx6ul.c new file mode 100644 index 000000000000..db74da5b46af --- /dev/null +++ b/arch/arm/mach-imx/mach-imx6ul.c | |||
@@ -0,0 +1,86 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Freescale Semiconductor, Inc. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | #include <linux/irqchip.h> | ||
9 | #include <linux/mfd/syscon.h> | ||
10 | #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> | ||
11 | #include <linux/micrel_phy.h> | ||
12 | #include <linux/of_platform.h> | ||
13 | #include <linux/phy.h> | ||
14 | #include <linux/regmap.h> | ||
15 | #include <asm/mach/arch.h> | ||
16 | #include <asm/mach/map.h> | ||
17 | |||
18 | #include "common.h" | ||
19 | |||
20 | static void __init imx6ul_enet_clk_init(void) | ||
21 | { | ||
22 | struct regmap *gpr; | ||
23 | |||
24 | gpr = syscon_regmap_lookup_by_compatible("fsl,imx6ul-iomuxc-gpr"); | ||
25 | if (!IS_ERR(gpr)) | ||
26 | regmap_update_bits(gpr, IOMUXC_GPR1, IMX6UL_GPR1_ENET_CLK_DIR, | ||
27 | IMX6UL_GPR1_ENET_CLK_OUTPUT); | ||
28 | else | ||
29 | pr_err("failed to find fsl,imx6ul-iomux-gpr regmap\n"); | ||
30 | |||
31 | } | ||
32 | |||
33 | static int ksz8081_phy_fixup(struct phy_device *dev) | ||
34 | { | ||
35 | if (dev && dev->interface == PHY_INTERFACE_MODE_MII) { | ||
36 | phy_write(dev, 0x1f, 0x8110); | ||
37 | phy_write(dev, 0x16, 0x201); | ||
38 | } else if (dev && dev->interface == PHY_INTERFACE_MODE_RMII) { | ||
39 | phy_write(dev, 0x1f, 0x8190); | ||
40 | phy_write(dev, 0x16, 0x202); | ||
41 | } | ||
42 | |||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | static void __init imx6ul_enet_phy_init(void) | ||
47 | { | ||
48 | phy_register_fixup_for_uid(PHY_ID_KSZ8081, 0xffffffff, ksz8081_phy_fixup); | ||
49 | } | ||
50 | |||
51 | static inline void imx6ul_enet_init(void) | ||
52 | { | ||
53 | imx6ul_enet_clk_init(); | ||
54 | imx6ul_enet_phy_init(); | ||
55 | } | ||
56 | |||
57 | static void __init imx6ul_init_machine(void) | ||
58 | { | ||
59 | struct device *parent; | ||
60 | |||
61 | parent = imx_soc_device_init(); | ||
62 | if (parent == NULL) | ||
63 | pr_warn("failed to initialize soc device\n"); | ||
64 | |||
65 | of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); | ||
66 | imx6ul_enet_init(); | ||
67 | imx_anatop_init(); | ||
68 | } | ||
69 | |||
70 | static void __init imx6ul_init_irq(void) | ||
71 | { | ||
72 | imx_init_revision_from_anatop(); | ||
73 | imx_src_init(); | ||
74 | irqchip_init(); | ||
75 | } | ||
76 | |||
77 | static const char *imx6ul_dt_compat[] __initconst = { | ||
78 | "fsl,imx6ul", | ||
79 | NULL, | ||
80 | }; | ||
81 | |||
82 | DT_MACHINE_START(IMX6UL, "Freescale i.MX6 Ultralite (Device Tree)") | ||
83 | .init_irq = imx6ul_init_irq, | ||
84 | .init_machine = imx6ul_init_machine, | ||
85 | .dt_compat = imx6ul_dt_compat, | ||
86 | MACHINE_END | ||
diff --git a/arch/arm/mach-imx/mxc.h b/arch/arm/mach-imx/mxc.h index c4436d4fd6fd..a5b1af6d7441 100644 --- a/arch/arm/mach-imx/mxc.h +++ b/arch/arm/mach-imx/mxc.h | |||
@@ -38,6 +38,7 @@ | |||
38 | #define MXC_CPU_IMX6DL 0x61 | 38 | #define MXC_CPU_IMX6DL 0x61 |
39 | #define MXC_CPU_IMX6SX 0x62 | 39 | #define MXC_CPU_IMX6SX 0x62 |
40 | #define MXC_CPU_IMX6Q 0x63 | 40 | #define MXC_CPU_IMX6Q 0x63 |
41 | #define MXC_CPU_IMX6UL 0x64 | ||
41 | #define MXC_CPU_IMX7D 0x72 | 42 | #define MXC_CPU_IMX7D 0x72 |
42 | 43 | ||
43 | #define IMX_DDR_TYPE_LPDDR2 1 | 44 | #define IMX_DDR_TYPE_LPDDR2 1 |
@@ -165,6 +166,11 @@ static inline bool cpu_is_imx6sx(void) | |||
165 | return __mxc_cpu_type == MXC_CPU_IMX6SX; | 166 | return __mxc_cpu_type == MXC_CPU_IMX6SX; |
166 | } | 167 | } |
167 | 168 | ||
169 | static inline bool cpu_is_imx6ul(void) | ||
170 | { | ||
171 | return __mxc_cpu_type == MXC_CPU_IMX6UL; | ||
172 | } | ||
173 | |||
168 | static inline bool cpu_is_imx6q(void) | 174 | static inline bool cpu_is_imx6q(void) |
169 | { | 175 | { |
170 | return __mxc_cpu_type == MXC_CPU_IMX6Q; | 176 | return __mxc_cpu_type == MXC_CPU_IMX6Q; |
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 4cd94fd6cbad..82a8fb50afac 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig | |||
@@ -401,6 +401,17 @@ config KEYBOARD_MPR121 | |||
401 | To compile this driver as a module, choose M here: the | 401 | To compile this driver as a module, choose M here: the |
402 | module will be called mpr121_touchkey. | 402 | module will be called mpr121_touchkey. |
403 | 403 | ||
404 | config KEYBOARD_SNVS_PWRKEY | ||
405 | tristate "IMX SNVS Power Key Driver" | ||
406 | depends on SOC_IMX6SX | ||
407 | depends on OF | ||
408 | help | ||
409 | This is the snvs powerkey driver for the Freescale i.MX application | ||
410 | processors that are newer than i.MX6 SX. | ||
411 | |||
412 | To compile this driver as a module, choose M here; the | ||
413 | module will be called snvs_pwrkey. | ||
414 | |||
404 | config KEYBOARD_IMX | 415 | config KEYBOARD_IMX |
405 | tristate "IMX keypad support" | 416 | tristate "IMX keypad support" |
406 | depends on ARCH_MXC | 417 | depends on ARCH_MXC |
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index df28d5553c05..1d416ddf84e4 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile | |||
@@ -51,6 +51,7 @@ obj-$(CONFIG_KEYBOARD_QT1070) += qt1070.o | |||
51 | obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o | 51 | obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o |
52 | obj-$(CONFIG_KEYBOARD_SAMSUNG) += samsung-keypad.o | 52 | obj-$(CONFIG_KEYBOARD_SAMSUNG) += samsung-keypad.o |
53 | obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o | 53 | obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o |
54 | obj-$(CONFIG_KEYBOARD_SNVS_PWRKEY) += snvs_pwrkey.o | ||
54 | obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o | 55 | obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o |
55 | obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o | 56 | obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o |
56 | obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o | 57 | obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o |
diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c new file mode 100644 index 000000000000..78fd24ca3813 --- /dev/null +++ b/drivers/input/keyboard/snvs_pwrkey.c | |||
@@ -0,0 +1,227 @@ | |||
1 | /* | ||
2 | * Driver for the IMX SNVS ON/OFF Power Key | ||
3 | * Copyright (C) 2015 Freescale Semiconductor, Inc. All Rights Reserved. | ||
4 | * | ||
5 | * The code contained herein is licensed under the GNU General Public | ||
6 | * License. You may obtain a copy of the GNU General Public License | ||
7 | * Version 2 or later at the following locations: | ||
8 | * | ||
9 | * http://www.opensource.org/licenses/gpl-license.html | ||
10 | * http://www.gnu.org/copyleft/gpl.html | ||
11 | */ | ||
12 | |||
13 | #include <linux/device.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/input.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/jiffies.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/of.h> | ||
23 | #include <linux/of_address.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/mfd/syscon.h> | ||
26 | #include <linux/regmap.h> | ||
27 | |||
28 | #define SNVS_LPSR_REG 0x4C /* LP Status Register */ | ||
29 | #define SNVS_LPCR_REG 0x38 /* LP Control Register */ | ||
30 | #define SNVS_HPSR_REG 0x14 | ||
31 | #define SNVS_HPSR_BTN BIT(6) | ||
32 | #define SNVS_LPSR_SPO BIT(18) | ||
33 | #define SNVS_LPCR_DEP_EN BIT(5) | ||
34 | |||
35 | #define DEBOUNCE_TIME 30 | ||
36 | #define REPEAT_INTERVAL 60 | ||
37 | |||
38 | struct pwrkey_drv_data { | ||
39 | struct regmap *snvs; | ||
40 | int irq; | ||
41 | int keycode; | ||
42 | int keystate; /* 1:pressed */ | ||
43 | int wakeup; | ||
44 | struct timer_list check_timer; | ||
45 | struct input_dev *input; | ||
46 | }; | ||
47 | |||
48 | static void imx_imx_snvs_check_for_events(unsigned long data) | ||
49 | { | ||
50 | struct pwrkey_drv_data *pdata = (struct pwrkey_drv_data *) data; | ||
51 | struct input_dev *input = pdata->input; | ||
52 | u32 state; | ||
53 | |||
54 | regmap_read(pdata->snvs, SNVS_HPSR_REG, &state); | ||
55 | state = state & SNVS_HPSR_BTN ? 1 : 0; | ||
56 | |||
57 | /* only report new event if status changed */ | ||
58 | if (state ^ pdata->keystate) { | ||
59 | pdata->keystate = state; | ||
60 | input_event(input, EV_KEY, pdata->keycode, state); | ||
61 | input_sync(input); | ||
62 | pm_relax(pdata->input->dev.parent); | ||
63 | } | ||
64 | |||
65 | /* repeat check if pressed long */ | ||
66 | if (state) { | ||
67 | mod_timer(&pdata->check_timer, | ||
68 | jiffies + msecs_to_jiffies(REPEAT_INTERVAL)); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | static irqreturn_t imx_snvs_pwrkey_interrupt(int irq, void *dev_id) | ||
73 | { | ||
74 | struct platform_device *pdev = dev_id; | ||
75 | struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev); | ||
76 | u32 lp_status; | ||
77 | |||
78 | pm_wakeup_event(pdata->input->dev.parent, 0); | ||
79 | |||
80 | regmap_read(pdata->snvs, SNVS_LPSR_REG, &lp_status); | ||
81 | if (lp_status & SNVS_LPSR_SPO) | ||
82 | mod_timer(&pdata->check_timer, jiffies + msecs_to_jiffies(DEBOUNCE_TIME)); | ||
83 | |||
84 | /* clear SPO status */ | ||
85 | regmap_write(pdata->snvs, SNVS_LPSR_REG, SNVS_LPSR_SPO); | ||
86 | |||
87 | return IRQ_HANDLED; | ||
88 | } | ||
89 | |||
90 | static void imx_snvs_pwrkey_act(void *pdata) | ||
91 | { | ||
92 | struct pwrkey_drv_data *pd = pdata; | ||
93 | |||
94 | del_timer_sync(&pd->check_timer); | ||
95 | } | ||
96 | |||
97 | static int imx_snvs_pwrkey_probe(struct platform_device *pdev) | ||
98 | { | ||
99 | struct pwrkey_drv_data *pdata = NULL; | ||
100 | struct input_dev *input = NULL; | ||
101 | struct device_node *np; | ||
102 | int error; | ||
103 | |||
104 | /* Get SNVS register Page */ | ||
105 | np = pdev->dev.of_node; | ||
106 | if (!np) | ||
107 | return -ENODEV; | ||
108 | |||
109 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | ||
110 | if (!pdata) | ||
111 | return -ENOMEM; | ||
112 | |||
113 | pdata->snvs = syscon_regmap_lookup_by_phandle(np, "regmap");; | ||
114 | |||
115 | if (!pdata->snvs) { | ||
116 | dev_err(&pdev->dev, "Can't get snvs syscon\n"); | ||
117 | return -ENODEV; | ||
118 | } | ||
119 | |||
120 | if (of_property_read_u32(np, "linux,keycode", &pdata->keycode)) { | ||
121 | pdata->keycode = KEY_POWER; | ||
122 | dev_warn(&pdev->dev, "KEY_POWER without setting in dts\n"); | ||
123 | } | ||
124 | |||
125 | pdata->wakeup = of_property_read_bool(np, "wakeup-source"); | ||
126 | |||
127 | pdata->irq = platform_get_irq(pdev, 0); | ||
128 | if (pdata->irq < 0) { | ||
129 | dev_err(&pdev->dev, "no irq defined in platform data\n"); | ||
130 | return -EINVAL; | ||
131 | } | ||
132 | |||
133 | regmap_update_bits(pdata->snvs, SNVS_LPCR_REG, SNVS_LPCR_DEP_EN, SNVS_LPCR_DEP_EN); | ||
134 | |||
135 | /* clear the unexpected interrupt before driver ready */ | ||
136 | regmap_write(pdata->snvs, SNVS_LPSR_REG, SNVS_LPSR_SPO); | ||
137 | |||
138 | setup_timer(&pdata->check_timer, | ||
139 | imx_imx_snvs_check_for_events, (unsigned long) pdata); | ||
140 | |||
141 | input = devm_input_allocate_device(&pdev->dev); | ||
142 | if (!input) { | ||
143 | dev_err(&pdev->dev, "failed to allocate the input device\n"); | ||
144 | return -ENOMEM; | ||
145 | } | ||
146 | |||
147 | input->name = pdev->name; | ||
148 | input->phys = "snvs-pwrkey/input0"; | ||
149 | input->id.bustype = BUS_HOST; | ||
150 | |||
151 | input_set_capability(input, EV_KEY, pdata->keycode); | ||
152 | |||
153 | /* input customer action to cancel release timer */ | ||
154 | error = devm_add_action(&pdev->dev, imx_snvs_pwrkey_act, pdata); | ||
155 | if (error) { | ||
156 | dev_err(&pdev->dev, "failed to register remove action\n"); | ||
157 | return error; | ||
158 | } | ||
159 | |||
160 | error = devm_request_irq(&pdev->dev, pdata->irq, | ||
161 | imx_snvs_pwrkey_interrupt, | ||
162 | 0, pdev->name, pdev); | ||
163 | |||
164 | if (error) { | ||
165 | dev_err(&pdev->dev, "interrupt not available.\n"); | ||
166 | return error; | ||
167 | } | ||
168 | |||
169 | error = input_register_device(input); | ||
170 | if (error < 0) { | ||
171 | dev_err(&pdev->dev, "failed to register input device\n"); | ||
172 | input_free_device(input); | ||
173 | return error; | ||
174 | } | ||
175 | |||
176 | pdata->input = input; | ||
177 | platform_set_drvdata(pdev, pdata); | ||
178 | |||
179 | device_init_wakeup(&pdev->dev, pdata->wakeup); | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | static int imx_snvs_pwrkey_suspend(struct device *dev) | ||
185 | { | ||
186 | struct platform_device *pdev = to_platform_device(dev); | ||
187 | struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev); | ||
188 | |||
189 | if (device_may_wakeup(&pdev->dev)) | ||
190 | enable_irq_wake(pdata->irq); | ||
191 | |||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | static int imx_snvs_pwrkey_resume(struct device *dev) | ||
196 | { | ||
197 | struct platform_device *pdev = to_platform_device(dev); | ||
198 | struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev); | ||
199 | |||
200 | if (device_may_wakeup(&pdev->dev)) | ||
201 | disable_irq_wake(pdata->irq); | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static const struct of_device_id imx_snvs_pwrkey_ids[] = { | ||
207 | { .compatible = "fsl,sec-v4.0-pwrkey" }, | ||
208 | { /* sentinel */ } | ||
209 | }; | ||
210 | MODULE_DEVICE_TABLE(of, imx_snvs_pwrkey_ids); | ||
211 | |||
212 | static SIMPLE_DEV_PM_OPS(imx_snvs_pwrkey_pm_ops, imx_snvs_pwrkey_suspend, | ||
213 | imx_snvs_pwrkey_resume); | ||
214 | |||
215 | static struct platform_driver imx_snvs_pwrkey_driver = { | ||
216 | .driver = { | ||
217 | .name = "snvs_pwrkey", | ||
218 | .pm = &imx_snvs_pwrkey_pm_ops, | ||
219 | .of_match_table = imx_snvs_pwrkey_ids, | ||
220 | }, | ||
221 | .probe = imx_snvs_pwrkey_probe, | ||
222 | }; | ||
223 | module_platform_driver(imx_snvs_pwrkey_driver); | ||
224 | |||
225 | MODULE_AUTHOR("Freescale Semiconductor"); | ||
226 | MODULE_DESCRIPTION("i.MX snvs power key Driver"); | ||
227 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 83b4b89b9d5a..533bfa3b6039 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
@@ -1523,6 +1523,7 @@ config RTC_DRV_MXC | |||
1523 | 1523 | ||
1524 | config RTC_DRV_SNVS | 1524 | config RTC_DRV_SNVS |
1525 | tristate "Freescale SNVS RTC support" | 1525 | tristate "Freescale SNVS RTC support" |
1526 | select REGMAP_MMIO | ||
1526 | depends on HAS_IOMEM | 1527 | depends on HAS_IOMEM |
1527 | depends on OF | 1528 | depends on OF |
1528 | help | 1529 | help |
diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c index 5fc292c2dfdf..7bd89d90048f 100644 --- a/drivers/rtc/rtc-mxc.c +++ b/drivers/rtc/rtc-mxc.c | |||
@@ -16,6 +16,8 @@ | |||
16 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
17 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/clk.h> | 18 | #include <linux/clk.h> |
19 | #include <linux/of.h> | ||
20 | #include <linux/of_device.h> | ||
19 | 21 | ||
20 | #define RTC_INPUT_CLK_32768HZ (0x00 << 5) | 22 | #define RTC_INPUT_CLK_32768HZ (0x00 << 5) |
21 | #define RTC_INPUT_CLK_32000HZ (0x01 << 5) | 23 | #define RTC_INPUT_CLK_32000HZ (0x01 << 5) |
@@ -79,7 +81,8 @@ struct rtc_plat_data { | |||
79 | struct rtc_device *rtc; | 81 | struct rtc_device *rtc; |
80 | void __iomem *ioaddr; | 82 | void __iomem *ioaddr; |
81 | int irq; | 83 | int irq; |
82 | struct clk *clk; | 84 | struct clk *clk_ref; |
85 | struct clk *clk_ipg; | ||
83 | struct rtc_time g_rtc_alarm; | 86 | struct rtc_time g_rtc_alarm; |
84 | enum imx_rtc_type devtype; | 87 | enum imx_rtc_type devtype; |
85 | }; | 88 | }; |
@@ -97,6 +100,15 @@ static const struct platform_device_id imx_rtc_devtype[] = { | |||
97 | }; | 100 | }; |
98 | MODULE_DEVICE_TABLE(platform, imx_rtc_devtype); | 101 | MODULE_DEVICE_TABLE(platform, imx_rtc_devtype); |
99 | 102 | ||
103 | #ifdef CONFIG_OF | ||
104 | static const struct of_device_id imx_rtc_dt_ids[] = { | ||
105 | { .compatible = "fsl,imx1-rtc", .data = (const void *)IMX1_RTC }, | ||
106 | { .compatible = "fsl,imx21-rtc", .data = (const void *)IMX21_RTC }, | ||
107 | {} | ||
108 | }; | ||
109 | MODULE_DEVICE_TABLE(of, imx_rtc_dt_ids); | ||
110 | #endif | ||
111 | |||
100 | static inline int is_imx1_rtc(struct rtc_plat_data *data) | 112 | static inline int is_imx1_rtc(struct rtc_plat_data *data) |
101 | { | 113 | { |
102 | return data->devtype == IMX1_RTC; | 114 | return data->devtype == IMX1_RTC; |
@@ -361,29 +373,45 @@ static int mxc_rtc_probe(struct platform_device *pdev) | |||
361 | u32 reg; | 373 | u32 reg; |
362 | unsigned long rate; | 374 | unsigned long rate; |
363 | int ret; | 375 | int ret; |
376 | const struct of_device_id *of_id; | ||
364 | 377 | ||
365 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | 378 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); |
366 | if (!pdata) | 379 | if (!pdata) |
367 | return -ENOMEM; | 380 | return -ENOMEM; |
368 | 381 | ||
369 | pdata->devtype = pdev->id_entry->driver_data; | 382 | of_id = of_match_device(imx_rtc_dt_ids, &pdev->dev); |
383 | if (of_id) | ||
384 | pdata->devtype = (enum imx_rtc_type)of_id->data; | ||
385 | else | ||
386 | pdata->devtype = pdev->id_entry->driver_data; | ||
370 | 387 | ||
371 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 388 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
372 | pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res); | 389 | pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res); |
373 | if (IS_ERR(pdata->ioaddr)) | 390 | if (IS_ERR(pdata->ioaddr)) |
374 | return PTR_ERR(pdata->ioaddr); | 391 | return PTR_ERR(pdata->ioaddr); |
375 | 392 | ||
376 | pdata->clk = devm_clk_get(&pdev->dev, NULL); | 393 | pdata->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); |
377 | if (IS_ERR(pdata->clk)) { | 394 | if (IS_ERR(pdata->clk_ipg)) { |
378 | dev_err(&pdev->dev, "unable to get clock!\n"); | 395 | dev_err(&pdev->dev, "unable to get ipg clock!\n"); |
379 | return PTR_ERR(pdata->clk); | 396 | return PTR_ERR(pdata->clk_ipg); |
380 | } | 397 | } |
381 | 398 | ||
382 | ret = clk_prepare_enable(pdata->clk); | 399 | ret = clk_prepare_enable(pdata->clk_ipg); |
383 | if (ret) | 400 | if (ret) |
384 | return ret; | 401 | return ret; |
385 | 402 | ||
386 | rate = clk_get_rate(pdata->clk); | 403 | pdata->clk_ref = devm_clk_get(&pdev->dev, "ref"); |
404 | if (IS_ERR(pdata->clk_ref)) { | ||
405 | dev_err(&pdev->dev, "unable to get ref clock!\n"); | ||
406 | ret = PTR_ERR(pdata->clk_ref); | ||
407 | goto exit_put_clk_ipg; | ||
408 | } | ||
409 | |||
410 | ret = clk_prepare_enable(pdata->clk_ref); | ||
411 | if (ret) | ||
412 | goto exit_put_clk_ipg; | ||
413 | |||
414 | rate = clk_get_rate(pdata->clk_ref); | ||
387 | 415 | ||
388 | if (rate == 32768) | 416 | if (rate == 32768) |
389 | reg = RTC_INPUT_CLK_32768HZ; | 417 | reg = RTC_INPUT_CLK_32768HZ; |
@@ -394,7 +422,7 @@ static int mxc_rtc_probe(struct platform_device *pdev) | |||
394 | else { | 422 | else { |
395 | dev_err(&pdev->dev, "rtc clock is not valid (%lu)\n", rate); | 423 | dev_err(&pdev->dev, "rtc clock is not valid (%lu)\n", rate); |
396 | ret = -EINVAL; | 424 | ret = -EINVAL; |
397 | goto exit_put_clk; | 425 | goto exit_put_clk_ref; |
398 | } | 426 | } |
399 | 427 | ||
400 | reg |= RTC_ENABLE_BIT; | 428 | reg |= RTC_ENABLE_BIT; |
@@ -402,7 +430,7 @@ static int mxc_rtc_probe(struct platform_device *pdev) | |||
402 | if (((readw(pdata->ioaddr + RTC_RTCCTL)) & RTC_ENABLE_BIT) == 0) { | 430 | if (((readw(pdata->ioaddr + RTC_RTCCTL)) & RTC_ENABLE_BIT) == 0) { |
403 | dev_err(&pdev->dev, "hardware module can't be enabled!\n"); | 431 | dev_err(&pdev->dev, "hardware module can't be enabled!\n"); |
404 | ret = -EIO; | 432 | ret = -EIO; |
405 | goto exit_put_clk; | 433 | goto exit_put_clk_ref; |
406 | } | 434 | } |
407 | 435 | ||
408 | platform_set_drvdata(pdev, pdata); | 436 | platform_set_drvdata(pdev, pdata); |
@@ -424,15 +452,17 @@ static int mxc_rtc_probe(struct platform_device *pdev) | |||
424 | THIS_MODULE); | 452 | THIS_MODULE); |
425 | if (IS_ERR(rtc)) { | 453 | if (IS_ERR(rtc)) { |
426 | ret = PTR_ERR(rtc); | 454 | ret = PTR_ERR(rtc); |
427 | goto exit_put_clk; | 455 | goto exit_put_clk_ref; |
428 | } | 456 | } |
429 | 457 | ||
430 | pdata->rtc = rtc; | 458 | pdata->rtc = rtc; |
431 | 459 | ||
432 | return 0; | 460 | return 0; |
433 | 461 | ||
434 | exit_put_clk: | 462 | exit_put_clk_ref: |
435 | clk_disable_unprepare(pdata->clk); | 463 | clk_disable_unprepare(pdata->clk_ref); |
464 | exit_put_clk_ipg: | ||
465 | clk_disable_unprepare(pdata->clk_ipg); | ||
436 | 466 | ||
437 | return ret; | 467 | return ret; |
438 | } | 468 | } |
@@ -441,7 +471,8 @@ static int mxc_rtc_remove(struct platform_device *pdev) | |||
441 | { | 471 | { |
442 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | 472 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); |
443 | 473 | ||
444 | clk_disable_unprepare(pdata->clk); | 474 | clk_disable_unprepare(pdata->clk_ref); |
475 | clk_disable_unprepare(pdata->clk_ipg); | ||
445 | 476 | ||
446 | return 0; | 477 | return 0; |
447 | } | 478 | } |
@@ -473,6 +504,7 @@ static SIMPLE_DEV_PM_OPS(mxc_rtc_pm_ops, mxc_rtc_suspend, mxc_rtc_resume); | |||
473 | static struct platform_driver mxc_rtc_driver = { | 504 | static struct platform_driver mxc_rtc_driver = { |
474 | .driver = { | 505 | .driver = { |
475 | .name = "mxc_rtc", | 506 | .name = "mxc_rtc", |
507 | .of_match_table = of_match_ptr(imx_rtc_dt_ids), | ||
476 | .pm = &mxc_rtc_pm_ops, | 508 | .pm = &mxc_rtc_pm_ops, |
477 | }, | 509 | }, |
478 | .id_table = imx_rtc_devtype, | 510 | .id_table = imx_rtc_devtype, |
diff --git a/drivers/rtc/rtc-snvs.c b/drivers/rtc/rtc-snvs.c index d87a85cefb66..950c5d0b6dca 100644 --- a/drivers/rtc/rtc-snvs.c +++ b/drivers/rtc/rtc-snvs.c | |||
@@ -18,6 +18,10 @@ | |||
18 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
19 | #include <linux/rtc.h> | 19 | #include <linux/rtc.h> |
20 | #include <linux/clk.h> | 20 | #include <linux/clk.h> |
21 | #include <linux/mfd/syscon.h> | ||
22 | #include <linux/regmap.h> | ||
23 | |||
24 | #define SNVS_LPREGISTER_OFFSET 0x34 | ||
21 | 25 | ||
22 | /* These register offsets are relative to LP (Low Power) range */ | 26 | /* These register offsets are relative to LP (Low Power) range */ |
23 | #define SNVS_LPCR 0x04 | 27 | #define SNVS_LPCR 0x04 |
@@ -37,31 +41,36 @@ | |||
37 | 41 | ||
38 | struct snvs_rtc_data { | 42 | struct snvs_rtc_data { |
39 | struct rtc_device *rtc; | 43 | struct rtc_device *rtc; |
40 | void __iomem *ioaddr; | 44 | struct regmap *regmap; |
45 | int offset; | ||
41 | int irq; | 46 | int irq; |
42 | spinlock_t lock; | ||
43 | struct clk *clk; | 47 | struct clk *clk; |
44 | }; | 48 | }; |
45 | 49 | ||
46 | static u32 rtc_read_lp_counter(void __iomem *ioaddr) | 50 | static u32 rtc_read_lp_counter(struct snvs_rtc_data *data) |
47 | { | 51 | { |
48 | u64 read1, read2; | 52 | u64 read1, read2; |
53 | u32 val; | ||
49 | 54 | ||
50 | do { | 55 | do { |
51 | read1 = readl(ioaddr + SNVS_LPSRTCMR); | 56 | regmap_read(data->regmap, data->offset + SNVS_LPSRTCMR, &val); |
57 | read1 = val; | ||
52 | read1 <<= 32; | 58 | read1 <<= 32; |
53 | read1 |= readl(ioaddr + SNVS_LPSRTCLR); | 59 | regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &val); |
60 | read1 |= val; | ||
54 | 61 | ||
55 | read2 = readl(ioaddr + SNVS_LPSRTCMR); | 62 | regmap_read(data->regmap, data->offset + SNVS_LPSRTCMR, &val); |
63 | read2 = val; | ||
56 | read2 <<= 32; | 64 | read2 <<= 32; |
57 | read2 |= readl(ioaddr + SNVS_LPSRTCLR); | 65 | regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &val); |
66 | read2 |= val; | ||
58 | } while (read1 != read2); | 67 | } while (read1 != read2); |
59 | 68 | ||
60 | /* Convert 47-bit counter to 32-bit raw second count */ | 69 | /* Convert 47-bit counter to 32-bit raw second count */ |
61 | return (u32) (read1 >> CNTR_TO_SECS_SH); | 70 | return (u32) (read1 >> CNTR_TO_SECS_SH); |
62 | } | 71 | } |
63 | 72 | ||
64 | static void rtc_write_sync_lp(void __iomem *ioaddr) | 73 | static void rtc_write_sync_lp(struct snvs_rtc_data *data) |
65 | { | 74 | { |
66 | u32 count1, count2, count3; | 75 | u32 count1, count2, count3; |
67 | int i; | 76 | int i; |
@@ -69,15 +78,15 @@ static void rtc_write_sync_lp(void __iomem *ioaddr) | |||
69 | /* Wait for 3 CKIL cycles */ | 78 | /* Wait for 3 CKIL cycles */ |
70 | for (i = 0; i < 3; i++) { | 79 | for (i = 0; i < 3; i++) { |
71 | do { | 80 | do { |
72 | count1 = readl(ioaddr + SNVS_LPSRTCLR); | 81 | regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1); |
73 | count2 = readl(ioaddr + SNVS_LPSRTCLR); | 82 | regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count2); |
74 | } while (count1 != count2); | 83 | } while (count1 != count2); |
75 | 84 | ||
76 | /* Now wait until counter value changes */ | 85 | /* Now wait until counter value changes */ |
77 | do { | 86 | do { |
78 | do { | 87 | do { |
79 | count2 = readl(ioaddr + SNVS_LPSRTCLR); | 88 | regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count2); |
80 | count3 = readl(ioaddr + SNVS_LPSRTCLR); | 89 | regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count3); |
81 | } while (count2 != count3); | 90 | } while (count2 != count3); |
82 | } while (count3 == count1); | 91 | } while (count3 == count1); |
83 | } | 92 | } |
@@ -85,23 +94,14 @@ static void rtc_write_sync_lp(void __iomem *ioaddr) | |||
85 | 94 | ||
86 | static int snvs_rtc_enable(struct snvs_rtc_data *data, bool enable) | 95 | static int snvs_rtc_enable(struct snvs_rtc_data *data, bool enable) |
87 | { | 96 | { |
88 | unsigned long flags; | ||
89 | int timeout = 1000; | 97 | int timeout = 1000; |
90 | u32 lpcr; | 98 | u32 lpcr; |
91 | 99 | ||
92 | spin_lock_irqsave(&data->lock, flags); | 100 | regmap_update_bits(data->regmap, data->offset + SNVS_LPCR, SNVS_LPCR_SRTC_ENV, |
93 | 101 | enable ? SNVS_LPCR_SRTC_ENV : 0); | |
94 | lpcr = readl(data->ioaddr + SNVS_LPCR); | ||
95 | if (enable) | ||
96 | lpcr |= SNVS_LPCR_SRTC_ENV; | ||
97 | else | ||
98 | lpcr &= ~SNVS_LPCR_SRTC_ENV; | ||
99 | writel(lpcr, data->ioaddr + SNVS_LPCR); | ||
100 | |||
101 | spin_unlock_irqrestore(&data->lock, flags); | ||
102 | 102 | ||
103 | while (--timeout) { | 103 | while (--timeout) { |
104 | lpcr = readl(data->ioaddr + SNVS_LPCR); | 104 | regmap_read(data->regmap, data->offset + SNVS_LPCR, &lpcr); |
105 | 105 | ||
106 | if (enable) { | 106 | if (enable) { |
107 | if (lpcr & SNVS_LPCR_SRTC_ENV) | 107 | if (lpcr & SNVS_LPCR_SRTC_ENV) |
@@ -121,7 +121,7 @@ static int snvs_rtc_enable(struct snvs_rtc_data *data, bool enable) | |||
121 | static int snvs_rtc_read_time(struct device *dev, struct rtc_time *tm) | 121 | static int snvs_rtc_read_time(struct device *dev, struct rtc_time *tm) |
122 | { | 122 | { |
123 | struct snvs_rtc_data *data = dev_get_drvdata(dev); | 123 | struct snvs_rtc_data *data = dev_get_drvdata(dev); |
124 | unsigned long time = rtc_read_lp_counter(data->ioaddr); | 124 | unsigned long time = rtc_read_lp_counter(data); |
125 | 125 | ||
126 | rtc_time_to_tm(time, tm); | 126 | rtc_time_to_tm(time, tm); |
127 | 127 | ||
@@ -139,8 +139,8 @@ static int snvs_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
139 | snvs_rtc_enable(data, false); | 139 | snvs_rtc_enable(data, false); |
140 | 140 | ||
141 | /* Write 32-bit time to 47-bit timer, leaving 15 LSBs blank */ | 141 | /* Write 32-bit time to 47-bit timer, leaving 15 LSBs blank */ |
142 | writel(time << CNTR_TO_SECS_SH, data->ioaddr + SNVS_LPSRTCLR); | 142 | regmap_write(data->regmap, data->offset + SNVS_LPSRTCLR, time << CNTR_TO_SECS_SH); |
143 | writel(time >> (32 - CNTR_TO_SECS_SH), data->ioaddr + SNVS_LPSRTCMR); | 143 | regmap_write(data->regmap, data->offset + SNVS_LPSRTCMR, time >> (32 - CNTR_TO_SECS_SH)); |
144 | 144 | ||
145 | /* Enable RTC again */ | 145 | /* Enable RTC again */ |
146 | snvs_rtc_enable(data, true); | 146 | snvs_rtc_enable(data, true); |
@@ -153,10 +153,10 @@ static int snvs_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
153 | struct snvs_rtc_data *data = dev_get_drvdata(dev); | 153 | struct snvs_rtc_data *data = dev_get_drvdata(dev); |
154 | u32 lptar, lpsr; | 154 | u32 lptar, lpsr; |
155 | 155 | ||
156 | lptar = readl(data->ioaddr + SNVS_LPTAR); | 156 | regmap_read(data->regmap, data->offset + SNVS_LPTAR, &lptar); |
157 | rtc_time_to_tm(lptar, &alrm->time); | 157 | rtc_time_to_tm(lptar, &alrm->time); |
158 | 158 | ||
159 | lpsr = readl(data->ioaddr + SNVS_LPSR); | 159 | regmap_read(data->regmap, data->offset + SNVS_LPSR, &lpsr); |
160 | alrm->pending = (lpsr & SNVS_LPSR_LPTA) ? 1 : 0; | 160 | alrm->pending = (lpsr & SNVS_LPSR_LPTA) ? 1 : 0; |
161 | 161 | ||
162 | return 0; | 162 | return 0; |
@@ -165,21 +165,12 @@ static int snvs_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
165 | static int snvs_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) | 165 | static int snvs_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) |
166 | { | 166 | { |
167 | struct snvs_rtc_data *data = dev_get_drvdata(dev); | 167 | struct snvs_rtc_data *data = dev_get_drvdata(dev); |
168 | u32 lpcr; | ||
169 | unsigned long flags; | ||
170 | |||
171 | spin_lock_irqsave(&data->lock, flags); | ||
172 | 168 | ||
173 | lpcr = readl(data->ioaddr + SNVS_LPCR); | 169 | regmap_update_bits(data->regmap, data->offset + SNVS_LPCR, |
174 | if (enable) | 170 | (SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN), |
175 | lpcr |= (SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN); | 171 | enable ? (SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN) : 0); |
176 | else | ||
177 | lpcr &= ~(SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN); | ||
178 | writel(lpcr, data->ioaddr + SNVS_LPCR); | ||
179 | 172 | ||
180 | spin_unlock_irqrestore(&data->lock, flags); | 173 | rtc_write_sync_lp(data); |
181 | |||
182 | rtc_write_sync_lp(data->ioaddr); | ||
183 | 174 | ||
184 | return 0; | 175 | return 0; |
185 | } | 176 | } |
@@ -189,24 +180,14 @@ static int snvs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
189 | struct snvs_rtc_data *data = dev_get_drvdata(dev); | 180 | struct snvs_rtc_data *data = dev_get_drvdata(dev); |
190 | struct rtc_time *alrm_tm = &alrm->time; | 181 | struct rtc_time *alrm_tm = &alrm->time; |
191 | unsigned long time; | 182 | unsigned long time; |
192 | unsigned long flags; | ||
193 | u32 lpcr; | ||
194 | 183 | ||
195 | rtc_tm_to_time(alrm_tm, &time); | 184 | rtc_tm_to_time(alrm_tm, &time); |
196 | 185 | ||
197 | spin_lock_irqsave(&data->lock, flags); | 186 | regmap_update_bits(data->regmap, data->offset + SNVS_LPCR, SNVS_LPCR_LPTA_EN, 0); |
198 | 187 | regmap_write(data->regmap, data->offset + SNVS_LPTAR, time); | |
199 | /* Have to clear LPTA_EN before programming new alarm time in LPTAR */ | ||
200 | lpcr = readl(data->ioaddr + SNVS_LPCR); | ||
201 | lpcr &= ~SNVS_LPCR_LPTA_EN; | ||
202 | writel(lpcr, data->ioaddr + SNVS_LPCR); | ||
203 | |||
204 | spin_unlock_irqrestore(&data->lock, flags); | ||
205 | |||
206 | writel(time, data->ioaddr + SNVS_LPTAR); | ||
207 | 188 | ||
208 | /* Clear alarm interrupt status bit */ | 189 | /* Clear alarm interrupt status bit */ |
209 | writel(SNVS_LPSR_LPTA, data->ioaddr + SNVS_LPSR); | 190 | regmap_write(data->regmap, data->offset + SNVS_LPSR, SNVS_LPSR_LPTA); |
210 | 191 | ||
211 | return snvs_rtc_alarm_irq_enable(dev, alrm->enabled); | 192 | return snvs_rtc_alarm_irq_enable(dev, alrm->enabled); |
212 | } | 193 | } |
@@ -226,7 +207,7 @@ static irqreturn_t snvs_rtc_irq_handler(int irq, void *dev_id) | |||
226 | u32 lpsr; | 207 | u32 lpsr; |
227 | u32 events = 0; | 208 | u32 events = 0; |
228 | 209 | ||
229 | lpsr = readl(data->ioaddr + SNVS_LPSR); | 210 | regmap_read(data->regmap, data->offset + SNVS_LPSR, &lpsr); |
230 | 211 | ||
231 | if (lpsr & SNVS_LPSR_LPTA) { | 212 | if (lpsr & SNVS_LPSR_LPTA) { |
232 | events |= (RTC_AF | RTC_IRQF); | 213 | events |= (RTC_AF | RTC_IRQF); |
@@ -238,25 +219,48 @@ static irqreturn_t snvs_rtc_irq_handler(int irq, void *dev_id) | |||
238 | } | 219 | } |
239 | 220 | ||
240 | /* clear interrupt status */ | 221 | /* clear interrupt status */ |
241 | writel(lpsr, data->ioaddr + SNVS_LPSR); | 222 | regmap_write(data->regmap, data->offset + SNVS_LPSR, lpsr); |
242 | 223 | ||
243 | return events ? IRQ_HANDLED : IRQ_NONE; | 224 | return events ? IRQ_HANDLED : IRQ_NONE; |
244 | } | 225 | } |
245 | 226 | ||
227 | static const struct regmap_config snvs_rtc_config = { | ||
228 | .reg_bits = 32, | ||
229 | .val_bits = 32, | ||
230 | .reg_stride = 4, | ||
231 | }; | ||
232 | |||
246 | static int snvs_rtc_probe(struct platform_device *pdev) | 233 | static int snvs_rtc_probe(struct platform_device *pdev) |
247 | { | 234 | { |
248 | struct snvs_rtc_data *data; | 235 | struct snvs_rtc_data *data; |
249 | struct resource *res; | 236 | struct resource *res; |
250 | int ret; | 237 | int ret; |
238 | void __iomem *mmio; | ||
251 | 239 | ||
252 | data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); | 240 | data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); |
253 | if (!data) | 241 | if (!data) |
254 | return -ENOMEM; | 242 | return -ENOMEM; |
255 | 243 | ||
256 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 244 | data->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "regmap"); |
257 | data->ioaddr = devm_ioremap_resource(&pdev->dev, res); | 245 | |
258 | if (IS_ERR(data->ioaddr)) | 246 | if (IS_ERR(data->regmap)) { |
259 | return PTR_ERR(data->ioaddr); | 247 | dev_warn(&pdev->dev, "snvs rtc: you use old dts file, please update it\n"); |
248 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
249 | |||
250 | mmio = devm_ioremap_resource(&pdev->dev, res); | ||
251 | if (IS_ERR(mmio)) | ||
252 | return PTR_ERR(mmio); | ||
253 | |||
254 | data->regmap = devm_regmap_init_mmio(&pdev->dev, mmio, &snvs_rtc_config); | ||
255 | } else { | ||
256 | data->offset = SNVS_LPREGISTER_OFFSET; | ||
257 | of_property_read_u32(pdev->dev.of_node, "offset", &data->offset); | ||
258 | } | ||
259 | |||
260 | if (!data->regmap) { | ||
261 | dev_err(&pdev->dev, "Can't find snvs syscon\n"); | ||
262 | return -ENODEV; | ||
263 | } | ||
260 | 264 | ||
261 | data->irq = platform_get_irq(pdev, 0); | 265 | data->irq = platform_get_irq(pdev, 0); |
262 | if (data->irq < 0) | 266 | if (data->irq < 0) |
@@ -276,13 +280,11 @@ static int snvs_rtc_probe(struct platform_device *pdev) | |||
276 | 280 | ||
277 | platform_set_drvdata(pdev, data); | 281 | platform_set_drvdata(pdev, data); |
278 | 282 | ||
279 | spin_lock_init(&data->lock); | ||
280 | |||
281 | /* Initialize glitch detect */ | 283 | /* Initialize glitch detect */ |
282 | writel(SNVS_LPPGDR_INIT, data->ioaddr + SNVS_LPPGDR); | 284 | regmap_write(data->regmap, data->offset + SNVS_LPPGDR, SNVS_LPPGDR_INIT); |
283 | 285 | ||
284 | /* Clear interrupt status */ | 286 | /* Clear interrupt status */ |
285 | writel(0xffffffff, data->ioaddr + SNVS_LPSR); | 287 | regmap_write(data->regmap, data->offset + SNVS_LPSR, 0xffffffff); |
286 | 288 | ||
287 | /* Enable RTC */ | 289 | /* Enable RTC */ |
288 | snvs_rtc_enable(data, true); | 290 | snvs_rtc_enable(data, true); |
diff --git a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h index d16f4c82c568..558a485d03ab 100644 --- a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h +++ b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h | |||
@@ -435,4 +435,12 @@ | |||
435 | #define IMX6SX_GPR5_DISP_MUX_DCIC1_LVDS (0x1 << 1) | 435 | #define IMX6SX_GPR5_DISP_MUX_DCIC1_LVDS (0x1 << 1) |
436 | #define IMX6SX_GPR5_DISP_MUX_DCIC1_MASK (0x1 << 1) | 436 | #define IMX6SX_GPR5_DISP_MUX_DCIC1_MASK (0x1 << 1) |
437 | 437 | ||
438 | /* For imx6ul iomux gpr register field define */ | ||
439 | #define IMX6UL_GPR1_ENET1_CLK_DIR (0x1 << 17) | ||
440 | #define IMX6UL_GPR1_ENET2_CLK_DIR (0x1 << 18) | ||
441 | #define IMX6UL_GPR1_ENET1_CLK_OUTPUT (0x1 << 17) | ||
442 | #define IMX6UL_GPR1_ENET2_CLK_OUTPUT (0x1 << 18) | ||
443 | #define IMX6UL_GPR1_ENET_CLK_DIR (0x3 << 17) | ||
444 | #define IMX6UL_GPR1_ENET_CLK_OUTPUT (0x3 << 17) | ||
445 | |||
438 | #endif /* __LINUX_IMX6Q_IOMUXC_GPR_H */ | 446 | #endif /* __LINUX_IMX6Q_IOMUXC_GPR_H */ |