mirror of https://gitee.com/openkylin/linux.git
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. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJVyg8nAAoJEFBXWFqHsHzOQC8H/iY+cdNfAWIxYmt2CeF607su fLaycUSUPqPAERUTcHpjKyiKkRg2NWV7vFVWCkKaQ3RZ+IW6xNntkqMxzocS1sh2 +70Ckp+B0orGuo96PkEXua9fNPf8/yaGiDhuJpK966VRRSSXRD15uOuqHAJ2Jz/v HEnEm3KANSSYS1heEJRqiiCsqhADRWl2RzgfV327aXtScP9zXlbJGlEc/jUVAY65 wbqjsXdySeS3rECNMAYXnPU7IlK4NkRqrOi1JmTJCBlXqV2b6dBfjgIu9jOa91UG yRj7IEBJemqT4Ap1ee2NR3H1lDngt2JKg9XqRDL3j9alYvhAWGvhSY2UH2iPrFg= =emep -----END PGP SIGNATURE----- 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>
This commit is contained in:
commit
207b504a63
|
@ -288,12 +288,13 @@ Secure Non-Volatile Storage (SNVS) Node
|
|||
Node defines address range and the associated
|
||||
interrupt for the SNVS function. This function
|
||||
monitors security state information & reports
|
||||
security violations.
|
||||
security violations. This also included rtc,
|
||||
system power off and ON/OFF key.
|
||||
|
||||
- compatible
|
||||
Usage: required
|
||||
Value type: <string>
|
||||
Definition: Must include "fsl,sec-v4.0-mon".
|
||||
Definition: Must include "fsl,sec-v4.0-mon" and "syscon".
|
||||
|
||||
- reg
|
||||
Usage: required
|
||||
|
@ -324,7 +325,7 @@ Secure Non-Volatile Storage (SNVS) Node
|
|||
the child address, parent address, & length.
|
||||
|
||||
- interrupts
|
||||
Usage: required
|
||||
Usage: optional
|
||||
Value type: <prop_encoded-array>
|
||||
Definition: Specifies the interrupts generated by this
|
||||
device. The value of the interrupts property
|
||||
|
@ -341,7 +342,7 @@ Secure Non-Volatile Storage (SNVS) Node
|
|||
|
||||
EXAMPLE
|
||||
sec_mon@314000 {
|
||||
compatible = "fsl,sec-v4.0-mon";
|
||||
compatible = "fsl,sec-v4.0-mon", "syscon";
|
||||
reg = <0x314000 0x1000>;
|
||||
ranges = <0 0x314000 0x1000>;
|
||||
interrupt-parent = <&mpic>;
|
||||
|
@ -358,16 +359,72 @@ Secure Non-Volatile Storage (SNVS) Low Power (LP) RTC Node
|
|||
Value type: <string>
|
||||
Definition: Must include "fsl,sec-v4.0-mon-rtc-lp".
|
||||
|
||||
- reg
|
||||
- interrupts
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: A standard property. Specifies the physical
|
||||
address and length of the SNVS LP configuration registers.
|
||||
Value type: <prop_encoded-array>
|
||||
Definition: Specifies the interrupts generated by this
|
||||
device. The value of the interrupts property
|
||||
consists of one interrupt specifier. The format
|
||||
of the specifier is defined by the binding document
|
||||
describing the node's interrupt parent.
|
||||
|
||||
- regmap
|
||||
Usage: required
|
||||
Value type: <phandle>
|
||||
Definition: this is phandle to the register map node.
|
||||
|
||||
- offset
|
||||
Usage: option
|
||||
value type: <u32>
|
||||
Definition: LP register offset. default it is 0x34.
|
||||
|
||||
EXAMPLE
|
||||
sec_mon_rtc_lp@314000 {
|
||||
sec_mon_rtc_lp@1 {
|
||||
compatible = "fsl,sec-v4.0-mon-rtc-lp";
|
||||
reg = <0x34 0x58>;
|
||||
interrupts = <93 2>;
|
||||
regmap = <&snvs>;
|
||||
offset = <0x34>;
|
||||
};
|
||||
|
||||
=====================================================================
|
||||
System ON/OFF key driver
|
||||
|
||||
The snvs-pwrkey is designed to enable POWER key function which controlled
|
||||
by SNVS ONOFF, the driver can report the status of POWER key and wakeup
|
||||
system if pressed after system suspend.
|
||||
|
||||
- compatible:
|
||||
Usage: required
|
||||
Value type: <string>
|
||||
Definition: Mush include "fsl,sec-v4.0-pwrkey".
|
||||
|
||||
- interrupts:
|
||||
Usage: required
|
||||
Value type: <prop_encoded-array>
|
||||
Definition: The SNVS ON/OFF interrupt number to the CPU(s).
|
||||
|
||||
- linux,keycode:
|
||||
Usage: option
|
||||
Value type: <int>
|
||||
Definition: Keycode to emit, KEY_POWER by default.
|
||||
|
||||
- wakeup-source:
|
||||
Usage: option
|
||||
Value type: <boo>
|
||||
Definition: Button can wake-up the system.
|
||||
|
||||
- regmap:
|
||||
Usage: required:
|
||||
Value type: <phandle>
|
||||
Definition: this is phandle to the register map node.
|
||||
|
||||
EXAMPLE:
|
||||
snvs-pwrkey@0x020cc000 {
|
||||
compatible = "fsl,sec-v4.0-pwrkey";
|
||||
regmap = <&snvs>;
|
||||
interrupts = <0 4 0x4>
|
||||
linux,keycode = <116>; /* KEY_POWER */
|
||||
wakeup;
|
||||
};
|
||||
|
||||
=====================================================================
|
||||
|
@ -443,12 +500,20 @@ FULL EXAMPLE
|
|||
compatible = "fsl,sec-v4.0-mon";
|
||||
reg = <0x314000 0x1000>;
|
||||
ranges = <0 0x314000 0x1000>;
|
||||
interrupt-parent = <&mpic>;
|
||||
interrupts = <93 2>;
|
||||
|
||||
sec_mon_rtc_lp@34 {
|
||||
compatible = "fsl,sec-v4.0-mon-rtc-lp";
|
||||
reg = <0x34 0x58>;
|
||||
regmap = <&sec_mon>;
|
||||
offset = <0x34>;
|
||||
interrupts = <93 2>;
|
||||
};
|
||||
|
||||
snvs-pwrkey@0x020cc000 {
|
||||
compatible = "fsl,sec-v4.0-pwrkey";
|
||||
regmap = <&sec_mon>;
|
||||
interrupts = <0 4 0x4>;
|
||||
linux,keycode = <116>; /* KEY_POWER */
|
||||
wakeup;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
See Documentation/devicetree/bindings/crypto/fsl-sec4.txt
|
|
@ -0,0 +1,26 @@
|
|||
* Real Time Clock of the i.MX SoCs
|
||||
|
||||
RTC controller for the i.MX SoCs
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "fsl,imx1-rtc" or "fsl,imx21-rtc".
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- interrupts: IRQ line for the RTC.
|
||||
- clocks: should contain two entries:
|
||||
* one for the input reference
|
||||
* one for the the SoC RTC
|
||||
- clock-names: should contain:
|
||||
* "ref" for the input reference clock
|
||||
* "ipg" for the SoC RTC clock
|
||||
|
||||
Example:
|
||||
|
||||
rtc@10007000 {
|
||||
compatible = "fsl,imx21-rtc";
|
||||
reg = <0x10007000 0x1000>;
|
||||
interrupts = <22>;
|
||||
clocks = <&clks IMX27_CLK_CKIL>,
|
||||
<&clks IMX27_CLK_RTC_IPG_GATE>;
|
||||
clock-names = "ref", "ipg";
|
||||
};
|
|
@ -417,6 +417,13 @@ choice
|
|||
Say Y here if you want kernel low-level debugging support
|
||||
on i.MX6SX.
|
||||
|
||||
config DEBUG_IMX6UL_UART
|
||||
bool "i.MX6UL Debug UART"
|
||||
depends on SOC_IMX6UL
|
||||
help
|
||||
Say Y here if you want kernel low-level debugging support
|
||||
on i.MX6UL.
|
||||
|
||||
config DEBUG_IMX7D_UART
|
||||
bool "i.MX7D Debug UART"
|
||||
depends on SOC_IMX7D
|
||||
|
@ -1275,6 +1282,7 @@ config DEBUG_IMX_UART_PORT
|
|||
DEBUG_IMX6Q_UART || \
|
||||
DEBUG_IMX6SL_UART || \
|
||||
DEBUG_IMX6SX_UART || \
|
||||
DEBUG_IMX6UL_UART || \
|
||||
DEBUG_IMX7D_UART
|
||||
default 1
|
||||
depends on ARCH_MXC
|
||||
|
@ -1326,6 +1334,7 @@ config DEBUG_LL_INCLUDE
|
|||
DEBUG_IMX6Q_UART || \
|
||||
DEBUG_IMX6SL_UART || \
|
||||
DEBUG_IMX6SX_UART || \
|
||||
DEBUG_IMX6UL_UART || \
|
||||
DEBUG_IMX7D_UART
|
||||
default "debug/ks8695.S" if DEBUG_KS8695_UART
|
||||
default "debug/msm.S" if DEBUG_QCOM_UARTDM
|
||||
|
|
|
@ -90,6 +90,17 @@
|
|||
#define IMX6SX_UART_BASE_ADDR(n) IMX6SX_UART##n##_BASE_ADDR
|
||||
#define IMX6SX_UART_BASE(n) IMX6SX_UART_BASE_ADDR(n)
|
||||
|
||||
#define IMX6UL_UART1_BASE_ADDR 0x02020000
|
||||
#define IMX6UL_UART2_BASE_ADDR 0x021e8000
|
||||
#define IMX6UL_UART3_BASE_ADDR 0x021ec000
|
||||
#define IMX6UL_UART4_BASE_ADDR 0x021f0000
|
||||
#define IMX6UL_UART5_BASE_ADDR 0x021f4000
|
||||
#define IMX6UL_UART6_BASE_ADDR 0x021fc000
|
||||
#define IMX6UL_UART7_BASE_ADDR 0x02018000
|
||||
#define IMX6UL_UART8_BASE_ADDR 0x02024000
|
||||
#define IMX6UL_UART_BASE_ADDR(n) IMX6UL_UART##n##_BASE_ADDR
|
||||
#define IMX6UL_UART_BASE(n) IMX6UL_UART_BASE_ADDR(n)
|
||||
|
||||
#define IMX7D_UART1_BASE_ADDR 0x30860000
|
||||
#define IMX7D_UART2_BASE_ADDR 0x30890000
|
||||
#define IMX7D_UART3_BASE_ADDR 0x30880000
|
||||
|
@ -124,6 +135,8 @@
|
|||
#define UART_PADDR IMX_DEBUG_UART_BASE(IMX6SL)
|
||||
#elif defined(CONFIG_DEBUG_IMX6SX_UART)
|
||||
#define UART_PADDR IMX_DEBUG_UART_BASE(IMX6SX)
|
||||
#elif defined(CONFIG_DEBUG_IMX6UL_UART)
|
||||
#define UART_PADDR IMX_DEBUG_UART_BASE(IMX6UL)
|
||||
#elif defined(CONFIG_DEBUG_IMX7D_UART)
|
||||
#define UART_PADDR IMX_DEBUG_UART_BASE(IMX7D)
|
||||
|
||||
|
|
|
@ -548,6 +548,14 @@ config SOC_IMX6SX
|
|||
help
|
||||
This enables support for Freescale i.MX6 SoloX processor.
|
||||
|
||||
config SOC_IMX6UL
|
||||
bool "i.MX6 UltraLite support"
|
||||
select PINCTRL_IMX6UL
|
||||
select SOC_IMX6
|
||||
|
||||
help
|
||||
This enables support for Freescale i.MX6 UltraLite processor.
|
||||
|
||||
config SOC_IMX7D
|
||||
bool "i.MX7 Dual support"
|
||||
select PINCTRL_IMX7D
|
||||
|
|
|
@ -83,6 +83,7 @@ endif
|
|||
obj-$(CONFIG_SOC_IMX6Q) += mach-imx6q.o
|
||||
obj-$(CONFIG_SOC_IMX6SL) += mach-imx6sl.o
|
||||
obj-$(CONFIG_SOC_IMX6SX) += mach-imx6sx.o
|
||||
obj-$(CONFIG_SOC_IMX6UL) += mach-imx6ul.o
|
||||
obj-$(CONFIG_SOC_IMX7D) += mach-imx7d.o
|
||||
|
||||
ifeq ($(CONFIG_SUSPEND),y)
|
||||
|
|
|
@ -130,6 +130,9 @@ struct device * __init imx_soc_device_init(void)
|
|||
case MXC_CPU_IMX6Q:
|
||||
soc_id = "i.MX6Q";
|
||||
break;
|
||||
case MXC_CPU_IMX6UL:
|
||||
soc_id = "i.MX6UL";
|
||||
break;
|
||||
case MXC_CPU_IMX7D:
|
||||
soc_id = "i.MX7D";
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
|
||||
#include <linux/micrel_phy.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/map.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
static void __init imx6ul_enet_clk_init(void)
|
||||
{
|
||||
struct regmap *gpr;
|
||||
|
||||
gpr = syscon_regmap_lookup_by_compatible("fsl,imx6ul-iomuxc-gpr");
|
||||
if (!IS_ERR(gpr))
|
||||
regmap_update_bits(gpr, IOMUXC_GPR1, IMX6UL_GPR1_ENET_CLK_DIR,
|
||||
IMX6UL_GPR1_ENET_CLK_OUTPUT);
|
||||
else
|
||||
pr_err("failed to find fsl,imx6ul-iomux-gpr regmap\n");
|
||||
|
||||
}
|
||||
|
||||
static int ksz8081_phy_fixup(struct phy_device *dev)
|
||||
{
|
||||
if (dev && dev->interface == PHY_INTERFACE_MODE_MII) {
|
||||
phy_write(dev, 0x1f, 0x8110);
|
||||
phy_write(dev, 0x16, 0x201);
|
||||
} else if (dev && dev->interface == PHY_INTERFACE_MODE_RMII) {
|
||||
phy_write(dev, 0x1f, 0x8190);
|
||||
phy_write(dev, 0x16, 0x202);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __init imx6ul_enet_phy_init(void)
|
||||
{
|
||||
phy_register_fixup_for_uid(PHY_ID_KSZ8081, 0xffffffff, ksz8081_phy_fixup);
|
||||
}
|
||||
|
||||
static inline void imx6ul_enet_init(void)
|
||||
{
|
||||
imx6ul_enet_clk_init();
|
||||
imx6ul_enet_phy_init();
|
||||
}
|
||||
|
||||
static void __init imx6ul_init_machine(void)
|
||||
{
|
||||
struct device *parent;
|
||||
|
||||
parent = imx_soc_device_init();
|
||||
if (parent == NULL)
|
||||
pr_warn("failed to initialize soc device\n");
|
||||
|
||||
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
|
||||
imx6ul_enet_init();
|
||||
imx_anatop_init();
|
||||
}
|
||||
|
||||
static void __init imx6ul_init_irq(void)
|
||||
{
|
||||
imx_init_revision_from_anatop();
|
||||
imx_src_init();
|
||||
irqchip_init();
|
||||
}
|
||||
|
||||
static const char *imx6ul_dt_compat[] __initconst = {
|
||||
"fsl,imx6ul",
|
||||
NULL,
|
||||
};
|
||||
|
||||
DT_MACHINE_START(IMX6UL, "Freescale i.MX6 Ultralite (Device Tree)")
|
||||
.init_irq = imx6ul_init_irq,
|
||||
.init_machine = imx6ul_init_machine,
|
||||
.dt_compat = imx6ul_dt_compat,
|
||||
MACHINE_END
|
|
@ -38,6 +38,7 @@
|
|||
#define MXC_CPU_IMX6DL 0x61
|
||||
#define MXC_CPU_IMX6SX 0x62
|
||||
#define MXC_CPU_IMX6Q 0x63
|
||||
#define MXC_CPU_IMX6UL 0x64
|
||||
#define MXC_CPU_IMX7D 0x72
|
||||
|
||||
#define IMX_DDR_TYPE_LPDDR2 1
|
||||
|
@ -165,6 +166,11 @@ static inline bool cpu_is_imx6sx(void)
|
|||
return __mxc_cpu_type == MXC_CPU_IMX6SX;
|
||||
}
|
||||
|
||||
static inline bool cpu_is_imx6ul(void)
|
||||
{
|
||||
return __mxc_cpu_type == MXC_CPU_IMX6UL;
|
||||
}
|
||||
|
||||
static inline bool cpu_is_imx6q(void)
|
||||
{
|
||||
return __mxc_cpu_type == MXC_CPU_IMX6Q;
|
||||
|
|
|
@ -401,6 +401,17 @@ config KEYBOARD_MPR121
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called mpr121_touchkey.
|
||||
|
||||
config KEYBOARD_SNVS_PWRKEY
|
||||
tristate "IMX SNVS Power Key Driver"
|
||||
depends on SOC_IMX6SX
|
||||
depends on OF
|
||||
help
|
||||
This is the snvs powerkey driver for the Freescale i.MX application
|
||||
processors that are newer than i.MX6 SX.
|
||||
|
||||
To compile this driver as a module, choose M here; the
|
||||
module will be called snvs_pwrkey.
|
||||
|
||||
config KEYBOARD_IMX
|
||||
tristate "IMX keypad support"
|
||||
depends on ARCH_MXC
|
||||
|
|
|
@ -51,6 +51,7 @@ obj-$(CONFIG_KEYBOARD_QT1070) += qt1070.o
|
|||
obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o
|
||||
obj-$(CONFIG_KEYBOARD_SAMSUNG) += samsung-keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
|
||||
obj-$(CONFIG_KEYBOARD_SNVS_PWRKEY) += snvs_pwrkey.o
|
||||
obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o
|
||||
obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
|
||||
|
|
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
* Driver for the IMX SNVS ON/OFF Power Key
|
||||
* Copyright (C) 2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define SNVS_LPSR_REG 0x4C /* LP Status Register */
|
||||
#define SNVS_LPCR_REG 0x38 /* LP Control Register */
|
||||
#define SNVS_HPSR_REG 0x14
|
||||
#define SNVS_HPSR_BTN BIT(6)
|
||||
#define SNVS_LPSR_SPO BIT(18)
|
||||
#define SNVS_LPCR_DEP_EN BIT(5)
|
||||
|
||||
#define DEBOUNCE_TIME 30
|
||||
#define REPEAT_INTERVAL 60
|
||||
|
||||
struct pwrkey_drv_data {
|
||||
struct regmap *snvs;
|
||||
int irq;
|
||||
int keycode;
|
||||
int keystate; /* 1:pressed */
|
||||
int wakeup;
|
||||
struct timer_list check_timer;
|
||||
struct input_dev *input;
|
||||
};
|
||||
|
||||
static void imx_imx_snvs_check_for_events(unsigned long data)
|
||||
{
|
||||
struct pwrkey_drv_data *pdata = (struct pwrkey_drv_data *) data;
|
||||
struct input_dev *input = pdata->input;
|
||||
u32 state;
|
||||
|
||||
regmap_read(pdata->snvs, SNVS_HPSR_REG, &state);
|
||||
state = state & SNVS_HPSR_BTN ? 1 : 0;
|
||||
|
||||
/* only report new event if status changed */
|
||||
if (state ^ pdata->keystate) {
|
||||
pdata->keystate = state;
|
||||
input_event(input, EV_KEY, pdata->keycode, state);
|
||||
input_sync(input);
|
||||
pm_relax(pdata->input->dev.parent);
|
||||
}
|
||||
|
||||
/* repeat check if pressed long */
|
||||
if (state) {
|
||||
mod_timer(&pdata->check_timer,
|
||||
jiffies + msecs_to_jiffies(REPEAT_INTERVAL));
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t imx_snvs_pwrkey_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct platform_device *pdev = dev_id;
|
||||
struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev);
|
||||
u32 lp_status;
|
||||
|
||||
pm_wakeup_event(pdata->input->dev.parent, 0);
|
||||
|
||||
regmap_read(pdata->snvs, SNVS_LPSR_REG, &lp_status);
|
||||
if (lp_status & SNVS_LPSR_SPO)
|
||||
mod_timer(&pdata->check_timer, jiffies + msecs_to_jiffies(DEBOUNCE_TIME));
|
||||
|
||||
/* clear SPO status */
|
||||
regmap_write(pdata->snvs, SNVS_LPSR_REG, SNVS_LPSR_SPO);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void imx_snvs_pwrkey_act(void *pdata)
|
||||
{
|
||||
struct pwrkey_drv_data *pd = pdata;
|
||||
|
||||
del_timer_sync(&pd->check_timer);
|
||||
}
|
||||
|
||||
static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwrkey_drv_data *pdata = NULL;
|
||||
struct input_dev *input = NULL;
|
||||
struct device_node *np;
|
||||
int error;
|
||||
|
||||
/* Get SNVS register Page */
|
||||
np = pdev->dev.of_node;
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
|
||||
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
|
||||
pdata->snvs = syscon_regmap_lookup_by_phandle(np, "regmap");;
|
||||
|
||||
if (!pdata->snvs) {
|
||||
dev_err(&pdev->dev, "Can't get snvs syscon\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (of_property_read_u32(np, "linux,keycode", &pdata->keycode)) {
|
||||
pdata->keycode = KEY_POWER;
|
||||
dev_warn(&pdev->dev, "KEY_POWER without setting in dts\n");
|
||||
}
|
||||
|
||||
pdata->wakeup = of_property_read_bool(np, "wakeup-source");
|
||||
|
||||
pdata->irq = platform_get_irq(pdev, 0);
|
||||
if (pdata->irq < 0) {
|
||||
dev_err(&pdev->dev, "no irq defined in platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(pdata->snvs, SNVS_LPCR_REG, SNVS_LPCR_DEP_EN, SNVS_LPCR_DEP_EN);
|
||||
|
||||
/* clear the unexpected interrupt before driver ready */
|
||||
regmap_write(pdata->snvs, SNVS_LPSR_REG, SNVS_LPSR_SPO);
|
||||
|
||||
setup_timer(&pdata->check_timer,
|
||||
imx_imx_snvs_check_for_events, (unsigned long) pdata);
|
||||
|
||||
input = devm_input_allocate_device(&pdev->dev);
|
||||
if (!input) {
|
||||
dev_err(&pdev->dev, "failed to allocate the input device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
input->name = pdev->name;
|
||||
input->phys = "snvs-pwrkey/input0";
|
||||
input->id.bustype = BUS_HOST;
|
||||
|
||||
input_set_capability(input, EV_KEY, pdata->keycode);
|
||||
|
||||
/* input customer action to cancel release timer */
|
||||
error = devm_add_action(&pdev->dev, imx_snvs_pwrkey_act, pdata);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to register remove action\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
error = devm_request_irq(&pdev->dev, pdata->irq,
|
||||
imx_snvs_pwrkey_interrupt,
|
||||
0, pdev->name, pdev);
|
||||
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "interrupt not available.\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
error = input_register_device(input);
|
||||
if (error < 0) {
|
||||
dev_err(&pdev->dev, "failed to register input device\n");
|
||||
input_free_device(input);
|
||||
return error;
|
||||
}
|
||||
|
||||
pdata->input = input;
|
||||
platform_set_drvdata(pdev, pdata);
|
||||
|
||||
device_init_wakeup(&pdev->dev, pdata->wakeup);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx_snvs_pwrkey_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev);
|
||||
|
||||
if (device_may_wakeup(&pdev->dev))
|
||||
enable_irq_wake(pdata->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx_snvs_pwrkey_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev);
|
||||
|
||||
if (device_may_wakeup(&pdev->dev))
|
||||
disable_irq_wake(pdata->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id imx_snvs_pwrkey_ids[] = {
|
||||
{ .compatible = "fsl,sec-v4.0-pwrkey" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, imx_snvs_pwrkey_ids);
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(imx_snvs_pwrkey_pm_ops, imx_snvs_pwrkey_suspend,
|
||||
imx_snvs_pwrkey_resume);
|
||||
|
||||
static struct platform_driver imx_snvs_pwrkey_driver = {
|
||||
.driver = {
|
||||
.name = "snvs_pwrkey",
|
||||
.pm = &imx_snvs_pwrkey_pm_ops,
|
||||
.of_match_table = imx_snvs_pwrkey_ids,
|
||||
},
|
||||
.probe = imx_snvs_pwrkey_probe,
|
||||
};
|
||||
module_platform_driver(imx_snvs_pwrkey_driver);
|
||||
|
||||
MODULE_AUTHOR("Freescale Semiconductor");
|
||||
MODULE_DESCRIPTION("i.MX snvs power key Driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1523,6 +1523,7 @@ config RTC_DRV_MXC
|
|||
|
||||
config RTC_DRV_SNVS
|
||||
tristate "Freescale SNVS RTC support"
|
||||
select REGMAP_MMIO
|
||||
depends on HAS_IOMEM
|
||||
depends on OF
|
||||
help
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#define RTC_INPUT_CLK_32768HZ (0x00 << 5)
|
||||
#define RTC_INPUT_CLK_32000HZ (0x01 << 5)
|
||||
|
@ -79,7 +81,8 @@ struct rtc_plat_data {
|
|||
struct rtc_device *rtc;
|
||||
void __iomem *ioaddr;
|
||||
int irq;
|
||||
struct clk *clk;
|
||||
struct clk *clk_ref;
|
||||
struct clk *clk_ipg;
|
||||
struct rtc_time g_rtc_alarm;
|
||||
enum imx_rtc_type devtype;
|
||||
};
|
||||
|
@ -97,6 +100,15 @@ static const struct platform_device_id imx_rtc_devtype[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(platform, imx_rtc_devtype);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id imx_rtc_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx1-rtc", .data = (const void *)IMX1_RTC },
|
||||
{ .compatible = "fsl,imx21-rtc", .data = (const void *)IMX21_RTC },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, imx_rtc_dt_ids);
|
||||
#endif
|
||||
|
||||
static inline int is_imx1_rtc(struct rtc_plat_data *data)
|
||||
{
|
||||
return data->devtype == IMX1_RTC;
|
||||
|
@ -361,29 +373,45 @@ static int mxc_rtc_probe(struct platform_device *pdev)
|
|||
u32 reg;
|
||||
unsigned long rate;
|
||||
int ret;
|
||||
const struct of_device_id *of_id;
|
||||
|
||||
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
|
||||
pdata->devtype = pdev->id_entry->driver_data;
|
||||
of_id = of_match_device(imx_rtc_dt_ids, &pdev->dev);
|
||||
if (of_id)
|
||||
pdata->devtype = (enum imx_rtc_type)of_id->data;
|
||||
else
|
||||
pdata->devtype = pdev->id_entry->driver_data;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(pdata->ioaddr))
|
||||
return PTR_ERR(pdata->ioaddr);
|
||||
|
||||
pdata->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(pdata->clk)) {
|
||||
dev_err(&pdev->dev, "unable to get clock!\n");
|
||||
return PTR_ERR(pdata->clk);
|
||||
pdata->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
|
||||
if (IS_ERR(pdata->clk_ipg)) {
|
||||
dev_err(&pdev->dev, "unable to get ipg clock!\n");
|
||||
return PTR_ERR(pdata->clk_ipg);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(pdata->clk);
|
||||
ret = clk_prepare_enable(pdata->clk_ipg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rate = clk_get_rate(pdata->clk);
|
||||
pdata->clk_ref = devm_clk_get(&pdev->dev, "ref");
|
||||
if (IS_ERR(pdata->clk_ref)) {
|
||||
dev_err(&pdev->dev, "unable to get ref clock!\n");
|
||||
ret = PTR_ERR(pdata->clk_ref);
|
||||
goto exit_put_clk_ipg;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(pdata->clk_ref);
|
||||
if (ret)
|
||||
goto exit_put_clk_ipg;
|
||||
|
||||
rate = clk_get_rate(pdata->clk_ref);
|
||||
|
||||
if (rate == 32768)
|
||||
reg = RTC_INPUT_CLK_32768HZ;
|
||||
|
@ -394,7 +422,7 @@ static int mxc_rtc_probe(struct platform_device *pdev)
|
|||
else {
|
||||
dev_err(&pdev->dev, "rtc clock is not valid (%lu)\n", rate);
|
||||
ret = -EINVAL;
|
||||
goto exit_put_clk;
|
||||
goto exit_put_clk_ref;
|
||||
}
|
||||
|
||||
reg |= RTC_ENABLE_BIT;
|
||||
|
@ -402,7 +430,7 @@ static int mxc_rtc_probe(struct platform_device *pdev)
|
|||
if (((readw(pdata->ioaddr + RTC_RTCCTL)) & RTC_ENABLE_BIT) == 0) {
|
||||
dev_err(&pdev->dev, "hardware module can't be enabled!\n");
|
||||
ret = -EIO;
|
||||
goto exit_put_clk;
|
||||
goto exit_put_clk_ref;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, pdata);
|
||||
|
@ -424,15 +452,17 @@ static int mxc_rtc_probe(struct platform_device *pdev)
|
|||
THIS_MODULE);
|
||||
if (IS_ERR(rtc)) {
|
||||
ret = PTR_ERR(rtc);
|
||||
goto exit_put_clk;
|
||||
goto exit_put_clk_ref;
|
||||
}
|
||||
|
||||
pdata->rtc = rtc;
|
||||
|
||||
return 0;
|
||||
|
||||
exit_put_clk:
|
||||
clk_disable_unprepare(pdata->clk);
|
||||
exit_put_clk_ref:
|
||||
clk_disable_unprepare(pdata->clk_ref);
|
||||
exit_put_clk_ipg:
|
||||
clk_disable_unprepare(pdata->clk_ipg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -441,7 +471,8 @@ static int mxc_rtc_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
|
||||
|
||||
clk_disable_unprepare(pdata->clk);
|
||||
clk_disable_unprepare(pdata->clk_ref);
|
||||
clk_disable_unprepare(pdata->clk_ipg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -473,6 +504,7 @@ static SIMPLE_DEV_PM_OPS(mxc_rtc_pm_ops, mxc_rtc_suspend, mxc_rtc_resume);
|
|||
static struct platform_driver mxc_rtc_driver = {
|
||||
.driver = {
|
||||
.name = "mxc_rtc",
|
||||
.of_match_table = of_match_ptr(imx_rtc_dt_ids),
|
||||
.pm = &mxc_rtc_pm_ops,
|
||||
},
|
||||
.id_table = imx_rtc_devtype,
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define SNVS_LPREGISTER_OFFSET 0x34
|
||||
|
||||
/* These register offsets are relative to LP (Low Power) range */
|
||||
#define SNVS_LPCR 0x04
|
||||
|
@ -37,31 +41,36 @@
|
|||
|
||||
struct snvs_rtc_data {
|
||||
struct rtc_device *rtc;
|
||||
void __iomem *ioaddr;
|
||||
struct regmap *regmap;
|
||||
int offset;
|
||||
int irq;
|
||||
spinlock_t lock;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
static u32 rtc_read_lp_counter(void __iomem *ioaddr)
|
||||
static u32 rtc_read_lp_counter(struct snvs_rtc_data *data)
|
||||
{
|
||||
u64 read1, read2;
|
||||
u32 val;
|
||||
|
||||
do {
|
||||
read1 = readl(ioaddr + SNVS_LPSRTCMR);
|
||||
regmap_read(data->regmap, data->offset + SNVS_LPSRTCMR, &val);
|
||||
read1 = val;
|
||||
read1 <<= 32;
|
||||
read1 |= readl(ioaddr + SNVS_LPSRTCLR);
|
||||
regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &val);
|
||||
read1 |= val;
|
||||
|
||||
read2 = readl(ioaddr + SNVS_LPSRTCMR);
|
||||
regmap_read(data->regmap, data->offset + SNVS_LPSRTCMR, &val);
|
||||
read2 = val;
|
||||
read2 <<= 32;
|
||||
read2 |= readl(ioaddr + SNVS_LPSRTCLR);
|
||||
regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &val);
|
||||
read2 |= val;
|
||||
} while (read1 != read2);
|
||||
|
||||
/* Convert 47-bit counter to 32-bit raw second count */
|
||||
return (u32) (read1 >> CNTR_TO_SECS_SH);
|
||||
}
|
||||
|
||||
static void rtc_write_sync_lp(void __iomem *ioaddr)
|
||||
static void rtc_write_sync_lp(struct snvs_rtc_data *data)
|
||||
{
|
||||
u32 count1, count2, count3;
|
||||
int i;
|
||||
|
@ -69,15 +78,15 @@ static void rtc_write_sync_lp(void __iomem *ioaddr)
|
|||
/* Wait for 3 CKIL cycles */
|
||||
for (i = 0; i < 3; i++) {
|
||||
do {
|
||||
count1 = readl(ioaddr + SNVS_LPSRTCLR);
|
||||
count2 = readl(ioaddr + SNVS_LPSRTCLR);
|
||||
regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1);
|
||||
regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count2);
|
||||
} while (count1 != count2);
|
||||
|
||||
/* Now wait until counter value changes */
|
||||
do {
|
||||
do {
|
||||
count2 = readl(ioaddr + SNVS_LPSRTCLR);
|
||||
count3 = readl(ioaddr + SNVS_LPSRTCLR);
|
||||
regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count2);
|
||||
regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count3);
|
||||
} while (count2 != count3);
|
||||
} while (count3 == count1);
|
||||
}
|
||||
|
@ -85,23 +94,14 @@ static void rtc_write_sync_lp(void __iomem *ioaddr)
|
|||
|
||||
static int snvs_rtc_enable(struct snvs_rtc_data *data, bool enable)
|
||||
{
|
||||
unsigned long flags;
|
||||
int timeout = 1000;
|
||||
u32 lpcr;
|
||||
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
|
||||
lpcr = readl(data->ioaddr + SNVS_LPCR);
|
||||
if (enable)
|
||||
lpcr |= SNVS_LPCR_SRTC_ENV;
|
||||
else
|
||||
lpcr &= ~SNVS_LPCR_SRTC_ENV;
|
||||
writel(lpcr, data->ioaddr + SNVS_LPCR);
|
||||
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
regmap_update_bits(data->regmap, data->offset + SNVS_LPCR, SNVS_LPCR_SRTC_ENV,
|
||||
enable ? SNVS_LPCR_SRTC_ENV : 0);
|
||||
|
||||
while (--timeout) {
|
||||
lpcr = readl(data->ioaddr + SNVS_LPCR);
|
||||
regmap_read(data->regmap, data->offset + SNVS_LPCR, &lpcr);
|
||||
|
||||
if (enable) {
|
||||
if (lpcr & SNVS_LPCR_SRTC_ENV)
|
||||
|
@ -121,7 +121,7 @@ static int snvs_rtc_enable(struct snvs_rtc_data *data, bool enable)
|
|||
static int snvs_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct snvs_rtc_data *data = dev_get_drvdata(dev);
|
||||
unsigned long time = rtc_read_lp_counter(data->ioaddr);
|
||||
unsigned long time = rtc_read_lp_counter(data);
|
||||
|
||||
rtc_time_to_tm(time, tm);
|
||||
|
||||
|
@ -139,8 +139,8 @@ static int snvs_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
|||
snvs_rtc_enable(data, false);
|
||||
|
||||
/* Write 32-bit time to 47-bit timer, leaving 15 LSBs blank */
|
||||
writel(time << CNTR_TO_SECS_SH, data->ioaddr + SNVS_LPSRTCLR);
|
||||
writel(time >> (32 - CNTR_TO_SECS_SH), data->ioaddr + SNVS_LPSRTCMR);
|
||||
regmap_write(data->regmap, data->offset + SNVS_LPSRTCLR, time << CNTR_TO_SECS_SH);
|
||||
regmap_write(data->regmap, data->offset + SNVS_LPSRTCMR, time >> (32 - CNTR_TO_SECS_SH));
|
||||
|
||||
/* Enable RTC again */
|
||||
snvs_rtc_enable(data, true);
|
||||
|
@ -153,10 +153,10 @@ static int snvs_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|||
struct snvs_rtc_data *data = dev_get_drvdata(dev);
|
||||
u32 lptar, lpsr;
|
||||
|
||||
lptar = readl(data->ioaddr + SNVS_LPTAR);
|
||||
regmap_read(data->regmap, data->offset + SNVS_LPTAR, &lptar);
|
||||
rtc_time_to_tm(lptar, &alrm->time);
|
||||
|
||||
lpsr = readl(data->ioaddr + SNVS_LPSR);
|
||||
regmap_read(data->regmap, data->offset + SNVS_LPSR, &lpsr);
|
||||
alrm->pending = (lpsr & SNVS_LPSR_LPTA) ? 1 : 0;
|
||||
|
||||
return 0;
|
||||
|
@ -165,21 +165,12 @@ static int snvs_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|||
static int snvs_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
|
||||
{
|
||||
struct snvs_rtc_data *data = dev_get_drvdata(dev);
|
||||
u32 lpcr;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
regmap_update_bits(data->regmap, data->offset + SNVS_LPCR,
|
||||
(SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN),
|
||||
enable ? (SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN) : 0);
|
||||
|
||||
lpcr = readl(data->ioaddr + SNVS_LPCR);
|
||||
if (enable)
|
||||
lpcr |= (SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN);
|
||||
else
|
||||
lpcr &= ~(SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN);
|
||||
writel(lpcr, data->ioaddr + SNVS_LPCR);
|
||||
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
|
||||
rtc_write_sync_lp(data->ioaddr);
|
||||
rtc_write_sync_lp(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -189,24 +180,14 @@ static int snvs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|||
struct snvs_rtc_data *data = dev_get_drvdata(dev);
|
||||
struct rtc_time *alrm_tm = &alrm->time;
|
||||
unsigned long time;
|
||||
unsigned long flags;
|
||||
u32 lpcr;
|
||||
|
||||
rtc_tm_to_time(alrm_tm, &time);
|
||||
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
|
||||
/* Have to clear LPTA_EN before programming new alarm time in LPTAR */
|
||||
lpcr = readl(data->ioaddr + SNVS_LPCR);
|
||||
lpcr &= ~SNVS_LPCR_LPTA_EN;
|
||||
writel(lpcr, data->ioaddr + SNVS_LPCR);
|
||||
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
|
||||
writel(time, data->ioaddr + SNVS_LPTAR);
|
||||
regmap_update_bits(data->regmap, data->offset + SNVS_LPCR, SNVS_LPCR_LPTA_EN, 0);
|
||||
regmap_write(data->regmap, data->offset + SNVS_LPTAR, time);
|
||||
|
||||
/* Clear alarm interrupt status bit */
|
||||
writel(SNVS_LPSR_LPTA, data->ioaddr + SNVS_LPSR);
|
||||
regmap_write(data->regmap, data->offset + SNVS_LPSR, SNVS_LPSR_LPTA);
|
||||
|
||||
return snvs_rtc_alarm_irq_enable(dev, alrm->enabled);
|
||||
}
|
||||
|
@ -226,7 +207,7 @@ static irqreturn_t snvs_rtc_irq_handler(int irq, void *dev_id)
|
|||
u32 lpsr;
|
||||
u32 events = 0;
|
||||
|
||||
lpsr = readl(data->ioaddr + SNVS_LPSR);
|
||||
regmap_read(data->regmap, data->offset + SNVS_LPSR, &lpsr);
|
||||
|
||||
if (lpsr & SNVS_LPSR_LPTA) {
|
||||
events |= (RTC_AF | RTC_IRQF);
|
||||
|
@ -238,25 +219,48 @@ static irqreturn_t snvs_rtc_irq_handler(int irq, void *dev_id)
|
|||
}
|
||||
|
||||
/* clear interrupt status */
|
||||
writel(lpsr, data->ioaddr + SNVS_LPSR);
|
||||
regmap_write(data->regmap, data->offset + SNVS_LPSR, lpsr);
|
||||
|
||||
return events ? IRQ_HANDLED : IRQ_NONE;
|
||||
}
|
||||
|
||||
static const struct regmap_config snvs_rtc_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
};
|
||||
|
||||
static int snvs_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snvs_rtc_data *data;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
void __iomem *mmio;
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
data->ioaddr = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(data->ioaddr))
|
||||
return PTR_ERR(data->ioaddr);
|
||||
data->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "regmap");
|
||||
|
||||
if (IS_ERR(data->regmap)) {
|
||||
dev_warn(&pdev->dev, "snvs rtc: you use old dts file, please update it\n");
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
mmio = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(mmio))
|
||||
return PTR_ERR(mmio);
|
||||
|
||||
data->regmap = devm_regmap_init_mmio(&pdev->dev, mmio, &snvs_rtc_config);
|
||||
} else {
|
||||
data->offset = SNVS_LPREGISTER_OFFSET;
|
||||
of_property_read_u32(pdev->dev.of_node, "offset", &data->offset);
|
||||
}
|
||||
|
||||
if (!data->regmap) {
|
||||
dev_err(&pdev->dev, "Can't find snvs syscon\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
data->irq = platform_get_irq(pdev, 0);
|
||||
if (data->irq < 0)
|
||||
|
@ -276,13 +280,11 @@ static int snvs_rtc_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
spin_lock_init(&data->lock);
|
||||
|
||||
/* Initialize glitch detect */
|
||||
writel(SNVS_LPPGDR_INIT, data->ioaddr + SNVS_LPPGDR);
|
||||
regmap_write(data->regmap, data->offset + SNVS_LPPGDR, SNVS_LPPGDR_INIT);
|
||||
|
||||
/* Clear interrupt status */
|
||||
writel(0xffffffff, data->ioaddr + SNVS_LPSR);
|
||||
regmap_write(data->regmap, data->offset + SNVS_LPSR, 0xffffffff);
|
||||
|
||||
/* Enable RTC */
|
||||
snvs_rtc_enable(data, true);
|
||||
|
|
|
@ -435,4 +435,12 @@
|
|||
#define IMX6SX_GPR5_DISP_MUX_DCIC1_LVDS (0x1 << 1)
|
||||
#define IMX6SX_GPR5_DISP_MUX_DCIC1_MASK (0x1 << 1)
|
||||
|
||||
/* For imx6ul iomux gpr register field define */
|
||||
#define IMX6UL_GPR1_ENET1_CLK_DIR (0x1 << 17)
|
||||
#define IMX6UL_GPR1_ENET2_CLK_DIR (0x1 << 18)
|
||||
#define IMX6UL_GPR1_ENET1_CLK_OUTPUT (0x1 << 17)
|
||||
#define IMX6UL_GPR1_ENET2_CLK_OUTPUT (0x1 << 18)
|
||||
#define IMX6UL_GPR1_ENET_CLK_DIR (0x3 << 17)
|
||||
#define IMX6UL_GPR1_ENET_CLK_OUTPUT (0x3 << 17)
|
||||
|
||||
#endif /* __LINUX_IMX6Q_IOMUXC_GPR_H */
|
||||
|
|
Loading…
Reference in New Issue