浏览代码

powerbutton activatet, input device,
powerdown is working now (built in rtc-omap.c)

Reinhard Russinger 8 年之前
父节点
当前提交
692618bfa6
共有 2 个文件被更改,包括 333 次插入1 次删除
  1. 1 1
      board/GfA/Display001/BUILD
  2. 332 0
      board/GfA/Display001/linux_3.12.30/linux-016-tps65217-pwr-button.patch

+ 1 - 1
board/GfA/Display001/BUILD

@@ -1 +1 @@
-333
+335

+ 332 - 0
board/GfA/Display001/linux_3.12.30/linux-016-tps65217-pwr-button.patch

@@ -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 {