|
@@ -0,0 +1,332 @@
|
|
|
+--- a/arch/arm/boot/dts/tps65217.dtsi 2014-10-09 15:46:37.000000000 +0200
|
|
|
++++ b/arch/arm/boot/dts/tps65217.dtsi 2017-01-30 15:56:21.108021669 +0100
|
|
|
+@@ -13,6 +13,10 @@
|
|
|
+
|
|
|
+ &tps {
|
|
|
+ compatible = "ti,tps65217";
|
|
|
++ ti,pmic-shutdown-controller;
|
|
|
++
|
|
|
++ interrupt-parent = <&intc>;
|
|
|
++ interrupts = <7>; /*NNMI */
|
|
|
+
|
|
|
+ regulators {
|
|
|
+ #address-cells = <1>;
|
|
|
+--- a/drivers/mfd/tps65217.c 2014-10-09 15:46:37.000000000 +0200
|
|
|
++++ b/drivers/mfd/tps65217.c 2017-01-30 21:44:53.397796575 +0100
|
|
|
+@@ -24,8 +24,12 @@
|
|
|
+ #include <linux/slab.h>
|
|
|
+ #include <linux/regmap.h>
|
|
|
+ #include <linux/err.h>
|
|
|
++#include <linux/input.h>
|
|
|
+ #include <linux/of.h>
|
|
|
+ #include <linux/of_device.h>
|
|
|
++#include <linux/of_irq.h>
|
|
|
++#include <linux/of_gpio.h>
|
|
|
++#include <linux/interrupt.h>
|
|
|
+
|
|
|
+ #include <linux/mfd/core.h>
|
|
|
+ #include <linux/mfd/tps65217.h>
|
|
|
+@@ -153,6 +157,87 @@
|
|
|
+ { /* sentinel */ },
|
|
|
+ };
|
|
|
+
|
|
|
++static irqreturn_t tps65217_irq(int irq, void *irq_data)
|
|
|
++{
|
|
|
++ struct tps65217 *tps = irq_data;
|
|
|
++ unsigned int int_reg = 0, status_reg = 0;
|
|
|
++
|
|
|
++ tps65217_reg_read(tps, TPS65217_REG_INT, &int_reg);
|
|
|
++ tps65217_reg_read(tps, TPS65217_REG_STATUS, &status_reg);
|
|
|
++ if (status_reg)
|
|
|
++ dev_dbg(tps->dev, "status now: 0x%X\n", status_reg);
|
|
|
++
|
|
|
++ if (!int_reg)
|
|
|
++ return IRQ_NONE;
|
|
|
++
|
|
|
++ if (int_reg & TPS65217_INT_PBI) {
|
|
|
++ /* Handle push button */
|
|
|
++ dev_dbg(tps->dev, "power button status change\n");
|
|
|
++ input_report_key(tps->pwr_but, KEY_POWER,
|
|
|
++ status_reg & TPS65217_STATUS_PB);
|
|
|
++ input_sync(tps->pwr_but);
|
|
|
++ }
|
|
|
++ if (int_reg & TPS65217_INT_ACI) {
|
|
|
++ /* Handle AC power status change */
|
|
|
++ dev_dbg(tps->dev, "AC power status change\n");
|
|
|
++ /* Press KEY_POWER when AC not present */
|
|
|
++ input_report_key(tps->pwr_but, KEY_POWER,
|
|
|
++ ~status_reg & TPS65217_STATUS_ACPWR);
|
|
|
++ input_sync(tps->pwr_but);
|
|
|
++ }
|
|
|
++ if (int_reg & TPS65217_INT_USBI) {
|
|
|
++ /* Handle USB power status change */
|
|
|
++ dev_dbg(tps->dev, "USB power status change\n");
|
|
|
++ /* Press KEY_POWER2 when USB not present */
|
|
|
++ input_report_key(tps->pwr_but, KEY_POWER2,
|
|
|
++ ~status_reg & TPS65217_STATUS_USBPWR);
|
|
|
++ input_sync(tps->pwr_but);
|
|
|
++ }
|
|
|
++
|
|
|
++ return IRQ_HANDLED;
|
|
|
++}
|
|
|
++
|
|
|
++static int tps65217_probe_pwr_but(struct tps65217 *tps)
|
|
|
++{
|
|
|
++ int ret;
|
|
|
++ unsigned int int_reg;
|
|
|
++
|
|
|
++ tps->pwr_but = devm_input_allocate_device(tps->dev);
|
|
|
++ if (!tps->pwr_but) {
|
|
|
++ dev_err(tps->dev,
|
|
|
++ "Failed to allocated pwr_but input device\n");
|
|
|
++ return -ENOMEM;
|
|
|
++ }
|
|
|
++
|
|
|
++ tps->pwr_but->evbit[0] = BIT_MASK(EV_KEY);
|
|
|
++ tps->pwr_but->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
|
|
|
++ tps->pwr_but->keybit[BIT_WORD(KEY_POWER2)] = BIT_MASK(KEY_POWER2);
|
|
|
++ tps->pwr_but->name = "tps65217_pwr_but";
|
|
|
++ ret = input_register_device(tps->pwr_but);
|
|
|
++ if (ret) {
|
|
|
++ /* NOTE: devm managed device */
|
|
|
++ dev_err(tps->dev, "Failed to register button device\n");
|
|
|
++ return ret;
|
|
|
++ }
|
|
|
++ ret = devm_request_threaded_irq(tps->dev,
|
|
|
++ tps->irq, NULL, tps65217_irq, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
|
|
++ "tps65217", tps);
|
|
|
++ if (ret != 0) {
|
|
|
++ dev_err(tps->dev, "Failed to request IRQ %d\n", tps->irq);
|
|
|
++ return ret;
|
|
|
++ }
|
|
|
++
|
|
|
++ /* enable the power button interrupt */
|
|
|
++ ret = tps65217_reg_read(tps, TPS65217_REG_INT, &int_reg);
|
|
|
++ if (ret < 0) {
|
|
|
++ dev_err(tps->dev, "Failed to read INT reg\n");
|
|
|
++ return ret;
|
|
|
++ }
|
|
|
++ int_reg &= ~TPS65217_INT_PBM;
|
|
|
++ tps65217_reg_write(tps, TPS65217_REG_INT, int_reg, TPS65217_PROTECT_NONE);
|
|
|
++ return 0;
|
|
|
++}
|
|
|
++
|
|
|
+ static int tps65217_probe(struct i2c_client *client,
|
|
|
+ const struct i2c_device_id *ids)
|
|
|
+ {
|
|
|
+@@ -160,10 +245,13 @@
|
|
|
+ unsigned int version;
|
|
|
+ unsigned int chip_id = ids->driver_data;
|
|
|
+ const struct of_device_id *match;
|
|
|
++ struct device_node *node;
|
|
|
+ bool status_off = false;
|
|
|
++ int irq = -1, irq_gpio = -1;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+- if (client->dev.of_node) {
|
|
|
++ node = client->dev.of_node;
|
|
|
++ if (node) {
|
|
|
+ match = of_match_device(tps65217_of_match, &client->dev);
|
|
|
+ if (!match) {
|
|
|
+ dev_err(&client->dev,
|
|
|
+@@ -173,6 +261,29 @@
|
|
|
+ chip_id = (unsigned int)match->data;
|
|
|
+ status_off = of_property_read_bool(client->dev.of_node,
|
|
|
+ "ti,pmic-shutdown-controller");
|
|
|
++
|
|
|
++ /* at first try to get irq via OF method */
|
|
|
++ irq = irq_of_parse_and_map(node, 0);
|
|
|
++ if (irq <= 0) {
|
|
|
++ irq = -1;
|
|
|
++ irq_gpio = of_get_named_gpio(node, "irq-gpio", 0);
|
|
|
++ if (irq_gpio >= 0) {
|
|
|
++ /* valid gpio; convert to irq */
|
|
|
++ ret = devm_gpio_request_one(&client->dev,
|
|
|
++ irq_gpio, GPIOF_DIR_IN,
|
|
|
++ "tps65217-gpio-irq");
|
|
|
++ if (ret != 0)
|
|
|
++ dev_warn(&client->dev, "Failed to "
|
|
|
++ "request gpio #%d\n", irq_gpio);
|
|
|
++ irq = gpio_to_irq(irq_gpio);
|
|
|
++ if (irq <= 0) {
|
|
|
++ dev_warn(&client->dev, "Failed to "
|
|
|
++ "convert gpio #%d to irq\n",
|
|
|
++ irq_gpio);
|
|
|
++ irq = -1;
|
|
|
++ }
|
|
|
++ }
|
|
|
++ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!chip_id) {
|
|
|
+@@ -196,6 +307,18 @@
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
++ tps->irq = irq;
|
|
|
++ tps->irq_gpio = irq_gpio;
|
|
|
++
|
|
|
++ /* we got an irq, request it */
|
|
|
++ if (tps->irq >= 0) {
|
|
|
++ ret = tps65217_probe_pwr_but(tps);
|
|
|
++ if (ret < 0) {
|
|
|
++ dev_err(tps->dev, "Failed to probe pwr_but\n");
|
|
|
++ return ret;
|
|
|
++ }
|
|
|
++ }
|
|
|
++
|
|
|
+ ret = mfd_add_devices(tps->dev, -1, tps65217s,
|
|
|
+ ARRAY_SIZE(tps65217s), NULL, 0, NULL);
|
|
|
+ if (ret < 0) {
|
|
|
+--- a/include/linux/mfd/tps65217.h 2014-10-09 15:46:37.000000000 +0200
|
|
|
++++ b/include/linux/mfd/tps65217.h 2017-01-30 15:56:21.108021669 +0100
|
|
|
+@@ -256,6 +256,11 @@
|
|
|
+ struct regulator_desc desc[TPS65217_NUM_REGULATOR];
|
|
|
+ struct regulator_dev *rdev[TPS65217_NUM_REGULATOR];
|
|
|
+ struct regmap *regmap;
|
|
|
++
|
|
|
++ /* Power button and IRQ handling */
|
|
|
++ int irq_gpio; /* might not be set */
|
|
|
++ int irq;
|
|
|
++ struct input_dev *pwr_but;
|
|
|
+ };
|
|
|
+
|
|
|
+ static inline struct tps65217 *dev_to_tps65217(struct device *dev)
|
|
|
+--- a/drivers/rtc/rtc-omap.c 2014-10-09 15:46:37.000000000 +0200
|
|
|
++++ b/drivers/rtc/rtc-omap.c 2017-01-30 23:19:10.548463160 +0100
|
|
|
+@@ -70,6 +70,14 @@
|
|
|
+ #define OMAP_RTC_KICK0_REG 0x6c
|
|
|
+ #define OMAP_RTC_KICK1_REG 0x70
|
|
|
+
|
|
|
++#define OMAP_RTC_ALARM2_SECONDS_REG 0x80
|
|
|
++#define OMAP_RTC_ALARM2_MINUTES_REG 0x84
|
|
|
++#define OMAP_RTC_ALARM2_HOURS_REG 0x88
|
|
|
++#define OMAP_RTC_ALARM2_DAYS_REG 0x8c
|
|
|
++#define OMAP_RTC_ALARM2_MONTHS_REG 0x90
|
|
|
++#define OMAP_RTC_ALARM2_YEARS_REG 0x94
|
|
|
++#define OMAP_RTC_PMIC_REG 0x98
|
|
|
++
|
|
|
+ #define OMAP_RTC_IRQWAKEEN 0x7c
|
|
|
+
|
|
|
+ /* OMAP_RTC_CTRL_REG bit fields: */
|
|
|
+@@ -93,18 +101,24 @@
|
|
|
+ #define OMAP_RTC_STATUS_BUSY (1<<0)
|
|
|
+
|
|
|
+ /* OMAP_RTC_INTERRUPTS_REG bit fields: */
|
|
|
++#define OMAP_RTC_INTERRUPTS_IT_ALARM2 (1<<4)
|
|
|
+ #define OMAP_RTC_INTERRUPTS_IT_ALARM (1<<3)
|
|
|
+ #define OMAP_RTC_INTERRUPTS_IT_TIMER (1<<2)
|
|
|
+
|
|
|
+ /* OMAP_RTC_IRQWAKEEN bit fields: */
|
|
|
+ #define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN (1<<1)
|
|
|
+
|
|
|
++/* OMAP_RTC_PMIC_REG bit fields: */
|
|
|
++#define OMAP_RTC_PMIC_POWER_EN_EN (1<<16)
|
|
|
++
|
|
|
+ /* OMAP_RTC_KICKER values */
|
|
|
+ #define KICK0_VALUE 0x83e70b13
|
|
|
+ #define KICK1_VALUE 0x95a4f1e0
|
|
|
+
|
|
|
+ #define OMAP_RTC_HAS_KICKER 0x1
|
|
|
+
|
|
|
++#define SHUTDOWN_TIME_SEC 2
|
|
|
++
|
|
|
+ /*
|
|
|
+ * Few RTC IP revisions has special WAKE-EN Register to enable Wakeup
|
|
|
+ * generation for event Alarm.
|
|
|
+@@ -299,6 +313,54 @@
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
++/*
|
|
|
++ * rtc_power_off: Set the pmic power off sequence. The RTC generates
|
|
|
++ * pmic_pwr_enable control, which can be used to control an external
|
|
|
++ * PMIC.
|
|
|
++ */
|
|
|
++static void rtc_power_off(void)
|
|
|
++{
|
|
|
++ u32 val;
|
|
|
++ struct rtc_time tm;
|
|
|
++ spinlock_t lock;
|
|
|
++ unsigned long flags, time;
|
|
|
++
|
|
|
++ spin_lock_init(&lock);
|
|
|
++
|
|
|
++ /* Set PMIC power enable */
|
|
|
++ val = readl(rtc_base + OMAP_RTC_PMIC_REG);
|
|
|
++ writel(val | OMAP_RTC_PMIC_POWER_EN_EN, rtc_base + OMAP_RTC_PMIC_REG);
|
|
|
++ /* Read rtc time */
|
|
|
++ omap_rtc_read_time(NULL, &tm);
|
|
|
++ /* Convert Gregorian date to seconds since 01-01-1970 00:00:00 */
|
|
|
++ rtc_tm_to_time(&tm, &time);
|
|
|
++ /* Add shutdown time to the current value */
|
|
|
++ time += SHUTDOWN_TIME_SEC;
|
|
|
++ /* Convert seconds since 01-01-1970 00:00:00 to Gregorian date */
|
|
|
++ rtc_time_to_tm(time, &tm);
|
|
|
++ if (tm2bcd(&tm) < 0)
|
|
|
++ return;
|
|
|
++ pr_info("System will go to power_off state in approx. %d secs\n",
|
|
|
++ SHUTDOWN_TIME_SEC);
|
|
|
++ /*
|
|
|
++ * pmic_pwr_enable is controlled by means of ALARM2 event. So here
|
|
|
++ * programming alarm2 expiry time and enabling alarm2 interrupt
|
|
|
++ */
|
|
|
++ rtc_write(tm.tm_sec, OMAP_RTC_ALARM2_SECONDS_REG);
|
|
|
++ rtc_write(tm.tm_min, OMAP_RTC_ALARM2_MINUTES_REG);
|
|
|
++ rtc_write(tm.tm_hour, OMAP_RTC_ALARM2_HOURS_REG);
|
|
|
++ rtc_write(tm.tm_mday, OMAP_RTC_ALARM2_DAYS_REG);
|
|
|
++ rtc_write(tm.tm_mon, OMAP_RTC_ALARM2_MONTHS_REG);
|
|
|
++ rtc_write(tm.tm_year, OMAP_RTC_ALARM2_YEARS_REG);
|
|
|
++ /* Enable alarm2 interrupt */
|
|
|
++ val = readl(rtc_base + OMAP_RTC_INTERRUPTS_REG);
|
|
|
++ writel(val | OMAP_RTC_INTERRUPTS_IT_ALARM2,
|
|
|
++ rtc_base + OMAP_RTC_INTERRUPTS_REG);
|
|
|
++ /* Do not allow to execute any other task */
|
|
|
++ spin_lock_irqsave(&lock, flags);
|
|
|
++ while (1);
|
|
|
++}
|
|
|
++
|
|
|
+ static struct rtc_class_ops omap_rtc_ops = {
|
|
|
+ .read_time = omap_rtc_read_time,
|
|
|
+ .set_time = omap_rtc_set_time,
|
|
|
+@@ -345,12 +407,16 @@
|
|
|
+ struct resource *res;
|
|
|
+ struct rtc_device *rtc;
|
|
|
+ u8 reg, new_ctrl;
|
|
|
++ bool pm_off=false;
|
|
|
+ const struct platform_device_id *id_entry;
|
|
|
+ const struct of_device_id *of_id;
|
|
|
+
|
|
|
+ of_id = of_match_device(omap_rtc_of_match, &pdev->dev);
|
|
|
+- if (of_id)
|
|
|
++ if (of_id){
|
|
|
+ pdev->id_entry = of_id->data;
|
|
|
++ pm_off = of_property_read_bool(pdev->dev.of_node,
|
|
|
++ "ti,system-power-controller");
|
|
|
++ }
|
|
|
+
|
|
|
+ omap_rtc_timer = platform_get_irq(pdev, 0);
|
|
|
+ if (omap_rtc_timer <= 0) {
|
|
|
+@@ -387,6 +453,9 @@
|
|
|
+ goto fail0;
|
|
|
+ }
|
|
|
+ platform_set_drvdata(pdev, rtc);
|
|
|
++ /* RTC power off */
|
|
|
++ if(pm_off && !pm_power_off)
|
|
|
++ pm_power_off = rtc_power_off;
|
|
|
+
|
|
|
+ /* clear pending irqs, and set 1/second periodic,
|
|
|
+ * which we'll use instead of update irqs
|
|
|
+--- a/arch/arm/boot/dts/am335x-bone-common.dtsi 2014-10-09 15:46:37.000000000 +0200
|
|
|
++++ b/arch/arm/boot/dts/am335x-bone-common.dtsi 2017-01-30 23:29:58.070292994 +0100
|
|
|
+@@ -231,6 +231,10 @@
|
|
|
+ };
|
|
|
+
|
|
|
+ };
|
|
|
++
|
|
|
++ rtc@44e3e000 {
|
|
|
++ ti,system-power-controller;
|
|
|
++ };
|
|
|
+ };
|
|
|
+
|
|
|
+ leds {
|