diff options
Diffstat (limited to 'target/linux/layerscape/patches-4.14/806-rtc-support-layerscape.patch')
-rw-r--r-- | target/linux/layerscape/patches-4.14/806-rtc-support-layerscape.patch | 776 |
1 files changed, 0 insertions, 776 deletions
diff --git a/target/linux/layerscape/patches-4.14/806-rtc-support-layerscape.patch b/target/linux/layerscape/patches-4.14/806-rtc-support-layerscape.patch deleted file mode 100644 index 5e4aac047a..0000000000 --- a/target/linux/layerscape/patches-4.14/806-rtc-support-layerscape.patch +++ /dev/null @@ -1,776 +0,0 @@ -From f8d89482075e2a4a62fc5cbacf6bea6baf4dc65f Mon Sep 17 00:00:00 2001 -From: Biwen Li <biwen.li@nxp.com> -Date: Tue, 30 Oct 2018 18:27:31 +0800 -Subject: [PATCH 23/40] rtc: support layerscape -This is an integrated patch of rtc for layerscape - -Signed-off-by: Martin Fuzzey <mfuzzey@parkeon.com> -Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com> -Signed-off-by: Biwen Li <biwen.li@nxp.com> ---- - .../devicetree/bindings/rtc/nxp,pcf85263.txt | 42 ++ - drivers/rtc/Kconfig | 8 + - drivers/rtc/Makefile | 1 + - drivers/rtc/rtc-pcf85263.c | 664 ++++++++++++++++++ - include/dt-bindings/rtc/nxp,pcf85263.h | 14 + - 5 files changed, 729 insertions(+) - create mode 100644 Documentation/devicetree/bindings/rtc/nxp,pcf85263.txt - create mode 100644 drivers/rtc/rtc-pcf85263.c - create mode 100644 include/dt-bindings/rtc/nxp,pcf85263.h - ---- /dev/null -+++ b/Documentation/devicetree/bindings/rtc/nxp,pcf85263.txt -@@ -0,0 +1,42 @@ -+NXP PCF85263 I2C Real Time Clock -+ -+Required properties: -+- compatible: must be: "nxp,rtc-pcf85263" -+- reg: must be the I2C address -+ -+Optional properties: -+- interrupt-names: Which interrupt signal is used must be "INTA" or "INTB" -+ Defaults to "INTA" -+ -+- quartz-load-capacitance: The internal capacitor to select for the quartz: -+ PCF85263_QUARTZCAP_7pF [0] -+ PCF85263_QUARTZCAP_6pF [1] -+ PCF85263_QUARTZCAP_12p5pF [2] DEFAULT -+ -+- quartz-drive-strength: Drive strength for the quartz: -+ PCF85263_QUARTZDRIVE_NORMAL [0] DEFAULT -+ PCF85263_QUARTZDRIVE_LOW [1] -+ PCF85263_QUARTZDRIVE_HIGH [2] -+ -+- quartz-low-jitter: Boolean property, if present enables low jitter mode -+which -+ reduces jitter at the cost of increased power consumption. -+ -+- wakeup-source: mark the chip as a wakeup source, independently of -+ the availability of an IRQ line connected to the SoC. -+ This is useful if the IRQ line is connected to a PMIC or other circuit -+ that can power up the device rather than to a normal SOC interrupt. -+ -+Example: -+ -+rtc@51 { -+ compatible = "nxp,pcf85263"; -+ reg = <0x51>; -+ -+ interrupt-parent = <&gpio4>; -+ interrupts = <5 IRQ_TYPE_LEVEL_LOW>; -+ interrupt-names = "INTB"; -+ -+ quartz-load-capacitance = <PCF85263_QUARTZCAP_12p5pF>; -+ quartz-drive-strength = <PCF85263_QUARTZDRIVE_LOW>; -+}; ---- a/drivers/rtc/Kconfig -+++ b/drivers/rtc/Kconfig -@@ -434,6 +434,14 @@ config RTC_DRV_PCF85063 - This driver can also be built as a module. If so, the module - will be called rtc-pcf85063. - -+config RTC_DRV_PCF85263 -+ tristate "NXP PCF85263" -+ help -+ If you say yes here you get support for the PCF85263 RTC chip -+ -+ This driver can also be built as a module. If so, the module -+ will be called rtc-pcf85263. -+ - config RTC_DRV_PCF8563 - tristate "Philips PCF8563/Epson RTC8564" - help ---- a/drivers/rtc/Makefile -+++ b/drivers/rtc/Makefile -@@ -115,6 +115,7 @@ obj-$(CONFIG_RTC_DRV_PCF2127) += rtc-pcf - obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o - obj-$(CONFIG_RTC_DRV_PCF85063) += rtc-pcf85063.o - obj-$(CONFIG_RTC_DRV_PCF8523) += rtc-pcf8523.o -+obj-$(CONFIG_RTC_DRV_PCF85263) += rtc-pcf85263.o - obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o - obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o - obj-$(CONFIG_RTC_DRV_PIC32) += rtc-pic32.o ---- /dev/null -+++ b/drivers/rtc/rtc-pcf85263.c -@@ -0,0 +1,664 @@ -+/* -+ * rtc-pcf85263 Driver for the NXP PCF85263 RTC -+ * Copyright 2016 Parkeon -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include <linux/module.h> -+#include <linux/mutex.h> -+#include <linux/rtc.h> -+#include <linux/i2c.h> -+#include <linux/bcd.h> -+#include <linux/of.h> -+#include <linux/of_device.h> -+#include <linux/regmap.h> -+ -+ -+#define DRV_NAME "rtc-pcf85263" -+ -+/* Quartz capacitance */ -+#define PCF85263_QUARTZCAP_7pF 0 -+#define PCF85263_QUARTZCAP_6pF 1 -+#define PCF85263_QUARTZCAP_12p5pF 2 -+ -+/* Quartz drive strength */ -+#define PCF85263_QUARTZDRIVE_NORMAL 0 -+#define PCF85263_QUARTZDRIVE_LOW 1 -+#define PCF85263_QUARTZDRIVE_HIGH 2 -+ -+ -+#define PCF85263_REG_RTC_SC 0x01 /* Seconds */ -+#define PCF85263_REG_RTC_SC_OS BIT(7) /* Oscilator stopped flag */ -+ -+#define PCF85263_REG_RTC_MN 0x02 /* Minutes */ -+#define PCF85263_REG_RTC_HR 0x03 /* Hours */ -+#define PCF85263_REG_RTC_DT 0x04 /* Day of month 1-31 */ -+#define PCF85263_REG_RTC_DW 0x05 /* Day of week 0-6 */ -+#define PCF85263_REG_RTC_MO 0x06 /* Month 1-12 */ -+#define PCF85263_REG_RTC_YR 0x07 /* Year 0-99 */ -+ -+#define PCF85263_REG_ALM1_SC 0x08 /* Seconds */ -+#define PCF85263_REG_ALM1_MN 0x09 /* Minutes */ -+#define PCF85263_REG_ALM1_HR 0x0a /* Hours */ -+#define PCF85263_REG_ALM1_DT 0x0b /* Day of month 1-31 */ -+#define PCF85263_REG_ALM1_MO 0x0c /* Month 1-12 */ -+ -+#define PCF85263_REG_ALM_CTL 0x10 -+#define PCF85263_REG_ALM_CTL_ALL_A1E 0x1f /* sec,min,hr,day,mon alarm 1 */ -+ -+#define PCF85263_REG_OSC 0x25 -+#define PCF85263_REG_OSC_CL_MASK (BIT(0) | BIT(1)) -+#define PCF85263_REG_OSC_CL_SHIFT 0 -+#define PCF85263_REG_OSC_OSCD_MASK (BIT(2) | BIT(3)) -+#define PCF85263_REG_OSC_OSCD_SHIFT 2 -+#define PCF85263_REG_OSC_LOWJ BIT(4) -+#define PCF85263_REG_OSC_12H BIT(5) -+ -+#define PCF85263_REG_PINIO 0x27 -+#define PCF85263_REG_PINIO_INTAPM_MASK (BIT(0) | BIT(1)) -+#define PCF85263_REG_PINIO_INTAPM_SHIFT 0 -+#define PCF85263_INTAPM_INTA (0x2 << PCF85263_REG_PINIO_INTAPM_SHIFT) -+#define PCF85263_INTAPM_HIGHZ (0x3 << PCF85263_REG_PINIO_INTAPM_SHIFT) -+#define PCF85263_REG_PINIO_TSPM_MASK (BIT(2) | BIT(3)) -+#define PCF85263_REG_PINIO_TSPM_SHIFT 2 -+#define PCF85263_TSPM_DISABLED (0x0 << PCF85263_REG_PINIO_TSPM_SHIFT) -+#define PCF85263_TSPM_INTB (0x1 << PCF85263_REG_PINIO_TSPM_SHIFT) -+#define PCF85263_REG_PINIO_CLKDISABLE BIT(7) -+ -+#define PCF85263_REG_FUNCTION 0x28 -+#define PCF85263_REG_FUNCTION_COF_MASK 0x7 -+#define PCF85263_REG_FUNCTION_COF_OFF 0x7 /* No clock output */ -+ -+#define PCF85263_REG_INTA_CTL 0x29 -+#define PCF85263_REG_INTB_CTL 0x2A -+#define PCF85263_REG_INTx_CTL_A1E BIT(4) /* Alarm 1 */ -+#define PCF85263_REG_INTx_CTL_ILP BIT(7) /* 0=pulse, 1=level */ -+ -+#define PCF85263_REG_FLAGS 0x2B -+#define PCF85263_REG_FLAGS_A1F BIT(5) -+ -+#define PCF85263_REG_RAM_BYTE 0x2c -+ -+#define PCF85263_REG_STOPENABLE 0x2e -+#define PCF85263_REG_STOPENABLE_STOP BIT(0) -+ -+#define PCF85263_REG_RESET 0x2f /* Reset command */ -+#define PCF85263_REG_RESET_CMD_CPR 0xa4 /* Clear prescaler */ -+ -+#define PCF85263_MAX_REG 0x2f -+ -+#define PCF85263_HR_PM BIT(5) -+ -+enum pcf85263_irqpin { -+ PCF85263_IRQPIN_NONE, -+ PCF85263_IRQPIN_INTA, -+ PCF85263_IRQPIN_INTB -+}; -+ -+static const char *const pcf85263_irqpin_names[] = { -+ [PCF85263_IRQPIN_NONE] = "None", -+ [PCF85263_IRQPIN_INTA] = "INTA", -+ [PCF85263_IRQPIN_INTB] = "INTB" -+}; -+ -+struct pcf85263 { -+ struct device *dev; -+ struct rtc_device *rtc; -+ struct regmap *regmap; -+ enum pcf85263_irqpin irq_pin; -+ int irq; -+ bool mode_12h; -+}; -+ -+/* -+ * Helpers to convert 12h to 24h and vice versa. -+ * Values in register are stored in BCD with a PM flag in bit 5 -+ * -+ * 23:00 <=> 11PM <=> 0x31 -+ * 00:00 <=> 12AM <=> 0x12 -+ * 01:00 <=> 1AM <=> 0x01 -+ * 12:00 <=> 12PM <=> 0x32 -+ * 13:00 <=> 1PM <=> 0x21 -+ */ -+static int pcf85263_bcd12h_to_bin24h(int regval) -+{ -+ int hr = bcd2bin(regval & 0x1f); -+ bool pm = regval & PCF85263_HR_PM; -+ -+ if (hr == 12) -+ return pm ? 12 : 0; -+ -+ return pm ? hr + 12 : hr; -+} -+ -+static int pcf85263_bin24h_to_bcd12h(int hr24) -+{ -+ bool pm = hr24 >= 12; -+ int hr12 = hr24 % 12; -+ -+ if (!hr12) -+ hr12++; -+ -+ return bin2bcd(hr12) | pm ? 0 : PCF85263_HR_PM; -+} -+ -+static int pcf85263_read_time(struct device *dev, struct rtc_time *tm) -+{ -+ struct pcf85263 *pcf85263 = dev_get_drvdata(dev); -+ const int first = PCF85263_REG_RTC_SC; -+ const int last = PCF85263_REG_RTC_YR; -+ const int len = last - first + 1; -+ u8 regs[len]; -+ u8 hr_reg; -+ int ret; -+ -+ ret = regmap_bulk_read(pcf85263->regmap, first, regs, len); -+ if (ret) -+ return ret; -+ -+ if (regs[PCF85263_REG_RTC_SC - first] & PCF85263_REG_RTC_SC_OS) { -+ dev_warn(dev, "Oscillator stop detected, date/time is not reliable.\n"); -+ return -EINVAL; -+ } -+ -+ tm->tm_sec = bcd2bin(regs[PCF85263_REG_RTC_SC - first] & 0x7f); -+ tm->tm_min = bcd2bin(regs[PCF85263_REG_RTC_MN - first] & 0x7f); -+ -+ hr_reg = regs[PCF85263_REG_RTC_HR - first]; -+ if (pcf85263->mode_12h) -+ tm->tm_hour = pcf85263_bcd12h_to_bin24h(hr_reg); -+ else -+ tm->tm_hour = bcd2bin(hr_reg & 0x3f); -+ -+ tm->tm_mday = bcd2bin(regs[PCF85263_REG_RTC_DT - first]); -+ tm->tm_wday = bcd2bin(regs[PCF85263_REG_RTC_DW - first]); -+ tm->tm_mon = bcd2bin(regs[PCF85263_REG_RTC_MO - first]) - 1; -+ tm->tm_year = bcd2bin(regs[PCF85263_REG_RTC_YR - first]); -+ -+ tm->tm_year += 100; /* Assume 21st century */ -+ -+ return 0; -+} -+ -+static int pcf85263_set_time(struct device *dev, struct rtc_time *tm) -+{ -+ struct pcf85263 *pcf85263 = dev_get_drvdata(dev); -+ -+ /* -+ * Before setting time need to stop RTC and disable prescaler -+ * Do this all in a single I2C transaction exploiting wraparound -+ * as described in data sheet. -+ * This means that the array below must be in register order -+ */ -+ u8 regs[] = { -+ PCF85263_REG_STOPENABLE_STOP, /* STOP */ -+ PCF85263_REG_RESET_CMD_CPR, /* Disable prescaler */ -+ /* Wrap around to register 0 (1/100s) */ -+ 0, /* 1/100s always zero. */ -+ bin2bcd(tm->tm_sec), -+ bin2bcd(tm->tm_min), -+ bin2bcd(tm->tm_hour), /* 24-hour */ -+ bin2bcd(tm->tm_mday), -+ bin2bcd(tm->tm_wday + 1), -+ bin2bcd(tm->tm_mon + 1), -+ bin2bcd(tm->tm_year % 100) -+ }; -+ int ret; -+ -+ ret = regmap_bulk_write(pcf85263->regmap, PCF85263_REG_STOPENABLE, -+ regs, sizeof(regs)); -+ if (ret) -+ return ret; -+ -+ /* As we have set the time in 24H update the hardware for that */ -+ if (pcf85263->mode_12h) { -+ pcf85263->mode_12h = false; -+ ret = regmap_update_bits(pcf85263->regmap, PCF85263_REG_OSC, -+ PCF85263_REG_OSC_12H, 0); -+ if (ret) -+ return ret; -+ } -+ -+ /* Start it again */ -+ return regmap_write(pcf85263->regmap, PCF85263_REG_STOPENABLE, 0); -+} -+ -+static int pcf85263_enable_alarm(struct pcf85263 *pcf85263, bool enable) -+{ -+ int reg; -+ int ret; -+ -+ ret = regmap_update_bits(pcf85263->regmap, PCF85263_REG_ALM_CTL, -+ PCF85263_REG_ALM_CTL_ALL_A1E, -+ enable ? PCF85263_REG_ALM_CTL_ALL_A1E : 0); -+ if (ret) -+ return ret; -+ -+ switch (pcf85263->irq_pin) { -+ case PCF85263_IRQPIN_NONE: -+ return 0; -+ -+ case PCF85263_IRQPIN_INTA: -+ reg = PCF85263_REG_INTA_CTL; -+ break; -+ -+ case PCF85263_IRQPIN_INTB: -+ reg = PCF85263_REG_INTB_CTL; -+ break; -+ -+ default: -+ return -EINVAL; -+ } -+ -+ return regmap_update_bits(pcf85263->regmap, reg, -+ PCF85263_REG_INTx_CTL_A1E, -+ enable ? PCF85263_REG_INTx_CTL_A1E : 0); -+} -+ -+static int pcf85263_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) -+{ -+ struct pcf85263 *pcf85263 = dev_get_drvdata(dev); -+ struct rtc_time *tm = &alarm->time; -+ const int first = PCF85263_REG_ALM1_SC; -+ const int last = PCF85263_REG_ALM1_MO; -+ const int len = last - first + 1; -+ u8 regs[len]; -+ u8 hr_reg; -+ unsigned int regval; -+ int ret; -+ -+ ret = regmap_bulk_read(pcf85263->regmap, first, regs, len); -+ if (ret) -+ return ret; -+ -+ tm->tm_sec = bcd2bin(regs[PCF85263_REG_ALM1_SC - first] & 0x7f); -+ tm->tm_min = bcd2bin(regs[PCF85263_REG_ALM1_MN - first] & 0x7f); -+ -+ hr_reg = regs[PCF85263_REG_ALM1_HR - first]; -+ if (pcf85263->mode_12h) -+ tm->tm_hour = pcf85263_bcd12h_to_bin24h(hr_reg); -+ else -+ tm->tm_hour = bcd2bin(hr_reg & 0x3f); -+ -+ tm->tm_mday = bcd2bin(regs[PCF85263_REG_ALM1_DT - first]); -+ tm->tm_mon = bcd2bin(regs[PCF85263_REG_ALM1_MO - first]) - 1; -+ tm->tm_year = -1; -+ tm->tm_wday = -1; -+ -+ ret = regmap_read(pcf85263->regmap, PCF85263_REG_ALM_CTL, ®val); -+ if (ret) -+ return ret; -+ alarm->enabled = !!(regval & PCF85263_REG_ALM_CTL_ALL_A1E); -+ -+ ret = regmap_read(pcf85263->regmap, PCF85263_REG_FLAGS, ®val); -+ if (ret) -+ return ret; -+ alarm->pending = !!(regval & PCF85263_REG_FLAGS_A1F); -+ -+ return 0; -+} -+ -+static int pcf85263_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) -+{ -+ struct pcf85263 *pcf85263 = dev_get_drvdata(dev); -+ struct rtc_time *tm = &alarm->time; -+ const int first = PCF85263_REG_ALM1_SC; -+ const int last = PCF85263_REG_ALM1_MO; -+ const int len = last - first + 1; -+ u8 regs[len]; -+ int ret; -+ -+ /* Disable alarm comparison during update */ -+ ret = pcf85263_enable_alarm(pcf85263, false); -+ if (ret) -+ return ret; -+ -+ /* Clear any pending alarm (write 0=>clr, 1=>no change) */ -+ ret = regmap_write(pcf85263->regmap, PCF85263_REG_FLAGS, -+ (unsigned int)(~PCF85263_REG_FLAGS_A1F)); -+ if (ret) -+ return ret; -+ -+ /* Set the alarm time registers */ -+ regs[PCF85263_REG_ALM1_SC - first] = bin2bcd(tm->tm_sec); -+ regs[PCF85263_REG_ALM1_MN - first] = bin2bcd(tm->tm_min); -+ regs[PCF85263_REG_ALM1_HR - first] = pcf85263->mode_12h ? -+ pcf85263_bin24h_to_bcd12h(tm->tm_hour) : -+ bin2bcd(tm->tm_hour); -+ regs[PCF85263_REG_ALM1_DT - first] = bin2bcd(tm->tm_mday); -+ regs[PCF85263_REG_ALM1_MO - first] = bin2bcd(tm->tm_mon + 1); -+ -+ ret = regmap_bulk_write(pcf85263->regmap, first, regs, sizeof(regs)); -+ if (ret) -+ return ret; -+ -+ if (alarm->enabled) -+ ret = pcf85263_enable_alarm(pcf85263, true); -+ -+ return ret; -+} -+ -+static int pcf85263_alarm_irq_enable(struct device *dev, unsigned int enable) -+{ -+ struct pcf85263 *pcf85263 = dev_get_drvdata(dev); -+ -+ return pcf85263_enable_alarm(pcf85263, !!enable); -+} -+ -+static irqreturn_t pcf85263_irq(int irq, void *data) -+{ -+ struct pcf85263 *pcf85263 = data; -+ unsigned int regval; -+ int ret; -+ -+ ret = regmap_read(pcf85263->regmap, PCF85263_REG_FLAGS, ®val); -+ if (ret) -+ return IRQ_NONE; -+ -+ if (regval & PCF85263_REG_FLAGS_A1F) { -+ regmap_write(pcf85263->regmap, PCF85263_REG_FLAGS, -+ (unsigned int)(~PCF85263_REG_FLAGS_A1F)); -+ -+ rtc_update_irq(pcf85263->rtc, 1, RTC_IRQF | RTC_AF); -+ -+ return IRQ_HANDLED; -+ } -+ -+ return IRQ_NONE; -+} -+ -+static int pcf85263_check_osc_stopped(struct pcf85263 *pcf85263) -+{ -+ unsigned int regval; -+ int ret; -+ -+ ret = regmap_read(pcf85263->regmap, PCF85263_REG_RTC_SC, ®val); -+ if (ret) -+ return ret; -+ -+ ret = regval & PCF85263_REG_RTC_SC_OS ? 1 : 0; -+ if (ret) -+ dev_warn(pcf85263->dev, "Oscillator stop detected, date/time is not reliable.\n"); -+ -+ return ret; -+} -+ -+#ifdef CONFIG_RTC_INTF_DEV -+static int pcf85263_ioctl(struct device *dev, -+ unsigned int cmd, unsigned long arg) -+{ -+ struct pcf85263 *pcf85263 = dev_get_drvdata(dev); -+ int ret; -+ -+ switch (cmd) { -+ case RTC_VL_READ: -+ ret = pcf85263_check_osc_stopped(pcf85263); -+ if (ret < 0) -+ return ret; -+ -+ if (copy_to_user((void __user *)arg, &ret, sizeof(int))) -+ return -EFAULT; -+ return 0; -+ -+ case RTC_VL_CLR: -+ return regmap_update_bits(pcf85263->regmap, -+ PCF85263_REG_RTC_SC, -+ PCF85263_REG_RTC_SC_OS, 0); -+ default: -+ return -ENOIOCTLCMD; -+ } -+} -+#else -+#define pcf85263_ioctl NULL -+#endif -+ -+static int pcf85263_init_hw(struct pcf85263 *pcf85263) -+{ -+ struct device_node *np = pcf85263->dev->of_node; -+ unsigned int regval; -+ u32 propval; -+ int ret; -+ -+ /* Determine if oscilator has been stopped (probably low power) */ -+ ret = pcf85263_check_osc_stopped(pcf85263); -+ if (ret < 0) { -+ /* Log here since this is the first hw access on probe */ -+ dev_err(pcf85263->dev, "Unable to read register\n"); -+ -+ return ret; -+ } -+ -+ /* Determine 12/24H mode */ -+ ret = regmap_read(pcf85263->regmap, PCF85263_REG_OSC, ®val); -+ if (ret) -+ return ret; -+ pcf85263->mode_12h = !!(regval & PCF85263_REG_OSC_12H); -+ -+ /* Set oscilator register */ -+ regval &= ~PCF85263_REG_OSC_12H; /* keep current 12/24 h setting */ -+ -+ propval = PCF85263_QUARTZCAP_12p5pF; -+ of_property_read_u32(np, "quartz-load-capacitance", &propval); -+ regval |= ((propval << PCF85263_REG_OSC_CL_SHIFT) -+ & PCF85263_REG_OSC_CL_MASK); -+ -+ propval = PCF85263_QUARTZDRIVE_NORMAL; -+ of_property_read_u32(np, "quartz-drive-strength", &propval); -+ regval |= ((propval << PCF85263_REG_OSC_OSCD_SHIFT) -+ & PCF85263_REG_OSC_OSCD_MASK); -+ -+ if (of_property_read_bool(np, "quartz-low-jitter")) -+ regval |= PCF85263_REG_OSC_LOWJ; -+ -+ ret = regmap_write(pcf85263->regmap, PCF85263_REG_OSC, regval); -+ if (ret) -+ return ret; -+ -+ /* Set function register (RTC mode, 1s tick, clock output static) */ -+ ret = regmap_write(pcf85263->regmap, PCF85263_REG_FUNCTION, -+ PCF85263_REG_FUNCTION_COF_OFF); -+ if (ret) -+ return ret; -+ -+ /* Set all interrupts to disabled, level mode */ -+ ret = regmap_write(pcf85263->regmap, PCF85263_REG_INTA_CTL, -+ PCF85263_REG_INTx_CTL_ILP); -+ if (ret) -+ return ret; -+ ret = regmap_write(pcf85263->regmap, PCF85263_REG_INTB_CTL, -+ PCF85263_REG_INTx_CTL_ILP); -+ if (ret) -+ return ret; -+ -+ /* Setup IO pin config register */ -+ regval = PCF85263_REG_PINIO_CLKDISABLE; -+ switch (pcf85263->irq_pin) { -+ case PCF85263_IRQPIN_INTA: -+ regval |= (PCF85263_INTAPM_INTA | PCF85263_TSPM_DISABLED); -+ break; -+ case PCF85263_IRQPIN_INTB: -+ regval |= (PCF85263_INTAPM_HIGHZ | PCF85263_TSPM_INTB); -+ break; -+ case PCF85263_IRQPIN_NONE: -+ regval |= (PCF85263_INTAPM_HIGHZ | PCF85263_TSPM_DISABLED); -+ break; -+ } -+ ret = regmap_write(pcf85263->regmap, PCF85263_REG_PINIO, regval); -+ -+ return ret; -+} -+ -+static const struct rtc_class_ops rtc_ops = { -+ .ioctl = pcf85263_ioctl, -+ .read_time = pcf85263_read_time, -+ .set_time = pcf85263_set_time, -+ .read_alarm = pcf85263_read_alarm, -+ .set_alarm = pcf85263_set_alarm, -+ .alarm_irq_enable = pcf85263_alarm_irq_enable, -+}; -+ -+static const struct regmap_config pcf85263_regmap_cfg = { -+ .reg_bits = 8, -+ .val_bits = 8, -+ .max_register = PCF85263_MAX_REG, -+}; -+ -+/* -+ * On some boards the interrupt line may not be wired to the CPU but only to -+ * a power supply circuit. -+ * In that case no interrupt will be specified in the device tree but the -+ * wakeup-source DT property may be used to enable wakeup programming in -+ * sysfs -+ */ -+static bool pcf85263_can_wakeup_machine(struct pcf85263 *pcf85263) -+{ -+ return pcf85263->irq || -+ of_property_read_bool(pcf85263->dev->of_node, "wakeup-source"); -+} -+ -+static int pcf85263_probe(struct i2c_client *client, -+ const struct i2c_device_id *id) -+{ -+ struct device *dev = &client->dev; -+ struct pcf85263 *pcf85263; -+ int ret; -+ -+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C | -+ I2C_FUNC_SMBUS_BYTE_DATA | -+ I2C_FUNC_SMBUS_I2C_BLOCK)) -+ return -ENODEV; -+ -+ pcf85263 = devm_kzalloc(dev, sizeof(*pcf85263), GFP_KERNEL); -+ if (!pcf85263) -+ return -ENOMEM; -+ -+ pcf85263->dev = dev; -+ pcf85263->irq = client->irq; -+ dev_set_drvdata(dev, pcf85263); -+ -+ pcf85263->regmap = devm_regmap_init_i2c(client, &pcf85263_regmap_cfg); -+ if (IS_ERR(pcf85263->regmap)) { -+ ret = PTR_ERR(pcf85263->regmap); -+ dev_err(dev, "regmap allocation failed (%d)\n", ret); -+ -+ return ret; -+ } -+ -+ /* Determine which interrupt pin the board uses */ -+ if (pcf85263_can_wakeup_machine(pcf85263)) { -+ if (of_property_match_string(dev->of_node, -+ "interrupt-names", "INTB") >= 0) -+ pcf85263->irq_pin = PCF85263_IRQPIN_INTB; -+ else -+ pcf85263->irq_pin = PCF85263_IRQPIN_INTA; -+ } else { -+ pcf85263->irq_pin = PCF85263_IRQPIN_NONE; -+ } -+ -+ ret = pcf85263_init_hw(pcf85263); -+ if (ret) -+ return ret; -+ -+ if (pcf85263->irq) { -+ ret = devm_request_threaded_irq(dev, pcf85263->irq, NULL, -+ pcf85263_irq, -+ IRQF_ONESHOT, -+ dev->driver->name, pcf85263); -+ if (ret) { -+ dev_err(dev, "irq %d unavailable (%d)\n", -+ pcf85263->irq, ret); -+ pcf85263->irq = 0; -+ } -+ } -+ -+ if (pcf85263_can_wakeup_machine(pcf85263)) -+ device_init_wakeup(dev, true); -+ -+ pcf85263->rtc = devm_rtc_device_register(dev, dev->driver->name, -+ &rtc_ops, THIS_MODULE); -+ ret = PTR_ERR_OR_ZERO(pcf85263->rtc); -+ if (ret) -+ return ret; -+ -+ /* We cannot support UIE mode if we do not have an IRQ line */ -+ if (!pcf85263->irq) -+ pcf85263->rtc->uie_unsupported = 1; -+ -+ dev_info(pcf85263->dev, -+ "PCF85263 RTC (irqpin=%s irq=%d)\n", -+ pcf85263_irqpin_names[pcf85263->irq_pin], -+ pcf85263->irq); -+ -+ return 0; -+} -+ -+static int pcf85263_remove(struct i2c_client *client) -+{ -+ struct pcf85263 *pcf85263 = i2c_get_clientdata(client); -+ -+ if (pcf85263_can_wakeup_machine(pcf85263)) -+ device_init_wakeup(pcf85263->dev, false); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int pcf85263_suspend(struct device *dev) -+{ -+ struct pcf85263 *pcf85263 = dev_get_drvdata(dev); -+ int ret = 0; -+ -+ if (device_may_wakeup(dev)) -+ ret = enable_irq_wake(pcf85263->irq); -+ -+ return ret; -+} -+ -+static int pcf85263_resume(struct device *dev) -+{ -+ struct pcf85263 *pcf85263 = dev_get_drvdata(dev); -+ int ret = 0; -+ -+ if (device_may_wakeup(dev)) -+ ret = disable_irq_wake(pcf85263->irq); -+ -+ return ret; -+} -+ -+#endif -+ -+static const struct i2c_device_id pcf85263_id[] = { -+ { "pcf85263", 0 }, -+ { } -+}; -+MODULE_DEVICE_TABLE(i2c, pcf85263_id); -+ -+#ifdef CONFIG_OF -+static const struct of_device_id pcf85263_of_match[] = { -+ { .compatible = "nxp,pcf85263" }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, pcf85263_of_match); -+#endif -+ -+static SIMPLE_DEV_PM_OPS(pcf85263_pm_ops, pcf85263_suspend, pcf85263_resume); -+ -+static struct i2c_driver pcf85263_driver = { -+ .driver = { -+ .name = "rtc-pcf85263", -+ .of_match_table = of_match_ptr(pcf85263_of_match), -+ .pm = &pcf85263_pm_ops, -+ }, -+ .probe = pcf85263_probe, -+ .remove = pcf85263_remove, -+ .id_table = pcf85263_id, -+}; -+ -+module_i2c_driver(pcf85263_driver); -+ -+MODULE_AUTHOR("Martin Fuzzey <mfuzzey@parkeon.com>"); -+MODULE_DESCRIPTION("PCF85263 RTC Driver"); -+MODULE_LICENSE("GPL"); ---- /dev/null -+++ b/include/dt-bindings/rtc/nxp,pcf85263.h -@@ -0,0 +1,14 @@ -+#ifndef _DT_BINDINGS_RTC_NXP_PCF85263_H -+#define _DT_BINDINGS_RTC_NXP_PCF85263_H -+ -+/* Quartz capacitance */ -+#define PCF85263_QUARTZCAP_7pF 0 -+#define PCF85263_QUARTZCAP_6pF 1 -+#define PCF85263_QUARTZCAP_12p5pF 2 -+ -+/* Quartz drive strength */ -+#define PCF85263_QUARTZDRIVE_NORMAL 0 -+#define PCF85263_QUARTZDRIVE_LOW 1 -+#define PCF85263_QUARTZDRIVE_HIGH 2 -+ -+#endif /* _DT_BINDINGS_RTC_NXP_PCF85263_H */ |