forked from mirrors/linux
		
	rtc: omap: Support ext_wakeup configuration
Support configuration of ext_wakeup sources. This patch makes it possible to enable ext_wakeup and set it's polarity, depending on board configuration. AM335x's dedicated PMIC (tps65217) uses ext_wakeup to notify about power-button presses. Handling power-button presses enables to recover from RTC-only power states correctly. Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com> Acked-by: Tony Lindgren <tony@atomide.com> Acked-by: Rob Herring <robh@kernel.org> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
This commit is contained in:
		
							parent
							
								
									970fc7f4af
								
							
						
					
					
						commit
						97ea1906b3
					
				
					 3 changed files with 185 additions and 9 deletions
				
			
		|  | @ -18,6 +18,18 @@ Optional properties: | |||
|   through pmic_power_en | ||||
| - clocks: Any internal or external clocks feeding in to rtc | ||||
| - clock-names: Corresponding names of the clocks | ||||
| - pinctrl-0: a phandle pointing to the pin settings for the device | ||||
| - pinctrl-names: should be "default" | ||||
| 
 | ||||
| Optional subnodes: | ||||
| - generic pinctrl node | ||||
| 
 | ||||
| Required pinctrl subnodes properties: | ||||
| - pins - Names of ext_wakeup pins to configure | ||||
| 
 | ||||
| Optional pinctrl subnodes properties: | ||||
| - input-enable - Enables ext_wakeup | ||||
| - ti,active-high - Set input active high (by default active low) | ||||
| 
 | ||||
| Example: | ||||
| 
 | ||||
|  | @ -30,4 +42,13 @@ rtc@1c23000 { | |||
| 	system-power-controller; | ||||
| 	clocks = <&clk_32k_rtc>, <&clk_32768_ck>; | ||||
| 	clock-names = "ext-clk", "int-clk"; | ||||
| 
 | ||||
| 	pinctrl-0 = <&ext_wakeup>; | ||||
| 	pinctrl-names = "default"; | ||||
| 
 | ||||
| 	ext_wakeup: ext-wakeup { | ||||
| 		pins = "ext_wakeup0"; | ||||
| 		input-enable; | ||||
| 		ti,active-high; | ||||
| 	}; | ||||
| }; | ||||
|  |  | |||
|  | @ -1245,6 +1245,9 @@ config RTC_DRV_IMXDI | |||
| config RTC_DRV_OMAP | ||||
| 	tristate "TI OMAP Real Time Clock" | ||||
| 	depends on ARCH_OMAP || ARCH_DAVINCI || COMPILE_TEST | ||||
| 	depends on OF | ||||
| 	depends on PINCTRL | ||||
| 	select GENERIC_PINCONF | ||||
| 	help | ||||
| 	  Say "yes" here to support the on chip real time clock | ||||
| 	  present on TI OMAP1, AM33xx, DA8xx/OMAP-L13x, AM43xx and DRA7xx. | ||||
|  |  | |||
|  | @ -13,19 +13,23 @@ | |||
|  * 2 of the License, or (at your option) any later version. | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/kernel.h> | ||||
| #include <linux/init.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/ioport.h> | ||||
| #include <linux/delay.h> | ||||
| #include <linux/rtc.h> | ||||
| #include <dt-bindings/gpio/gpio.h> | ||||
| #include <linux/bcd.h> | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/clk.h> | ||||
| #include <linux/delay.h> | ||||
| #include <linux/init.h> | ||||
| #include <linux/io.h> | ||||
| #include <linux/ioport.h> | ||||
| #include <linux/kernel.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/of.h> | ||||
| #include <linux/of_device.h> | ||||
| #include <linux/pinctrl/pinctrl.h> | ||||
| #include <linux/pinctrl/pinconf.h> | ||||
| #include <linux/pinctrl/pinconf-generic.h> | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/pm_runtime.h> | ||||
| #include <linux/io.h> | ||||
| #include <linux/clk.h> | ||||
| #include <linux/rtc.h> | ||||
| 
 | ||||
| /*
 | ||||
|  * The OMAP RTC is a year/month/day/hours/minutes/seconds BCD clock | ||||
|  | @ -115,6 +119,8 @@ | |||
| 
 | ||||
| /* OMAP_RTC_PMIC bit fields: */ | ||||
| #define OMAP_RTC_PMIC_POWER_EN_EN	BIT(16) | ||||
| #define OMAP_RTC_PMIC_EXT_WKUP_EN(x)	BIT(x) | ||||
| #define OMAP_RTC_PMIC_EXT_WKUP_POL(x)	BIT(4 + x) | ||||
| 
 | ||||
| /* OMAP_RTC_KICKER values */ | ||||
| #define	KICK0_VALUE			0x83e70b13 | ||||
|  | @ -141,6 +147,7 @@ struct omap_rtc { | |||
| 	bool is_pmic_controller; | ||||
| 	bool has_ext_clk; | ||||
| 	const struct omap_rtc_device_type *type; | ||||
| 	struct pinctrl_dev *pctldev; | ||||
| }; | ||||
| 
 | ||||
| static inline u8 rtc_read(struct omap_rtc *rtc, unsigned int reg) | ||||
|  | @ -525,6 +532,139 @@ static const struct of_device_id omap_rtc_of_match[] = { | |||
| }; | ||||
| MODULE_DEVICE_TABLE(of, omap_rtc_of_match); | ||||
| 
 | ||||
| static const struct pinctrl_pin_desc rtc_pins_desc[] = { | ||||
| 	PINCTRL_PIN(0, "ext_wakeup0"), | ||||
| 	PINCTRL_PIN(1, "ext_wakeup1"), | ||||
| 	PINCTRL_PIN(2, "ext_wakeup2"), | ||||
| 	PINCTRL_PIN(3, "ext_wakeup3"), | ||||
| }; | ||||
| 
 | ||||
| static int rtc_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static const char *rtc_pinctrl_get_group_name(struct pinctrl_dev *pctldev, | ||||
| 					unsigned int group) | ||||
| { | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| static const struct pinctrl_ops rtc_pinctrl_ops = { | ||||
| 	.get_groups_count = rtc_pinctrl_get_groups_count, | ||||
| 	.get_group_name = rtc_pinctrl_get_group_name, | ||||
| 	.dt_node_to_map = pinconf_generic_dt_node_to_map_pin, | ||||
| 	.dt_free_map = pinconf_generic_dt_free_map, | ||||
| }; | ||||
| 
 | ||||
| enum rtc_pin_config_param { | ||||
| 	PIN_CONFIG_ACTIVE_HIGH = PIN_CONFIG_END + 1, | ||||
| }; | ||||
| 
 | ||||
| static const struct pinconf_generic_params rtc_params[] = { | ||||
| 	{"ti,active-high", PIN_CONFIG_ACTIVE_HIGH, 0}, | ||||
| }; | ||||
| 
 | ||||
| #ifdef CONFIG_DEBUG_FS | ||||
| static const struct pin_config_item rtc_conf_items[ARRAY_SIZE(rtc_params)] = { | ||||
| 	PCONFDUMP(PIN_CONFIG_ACTIVE_HIGH, "input active high", NULL, false), | ||||
| }; | ||||
| #endif | ||||
| 
 | ||||
| static int rtc_pinconf_get(struct pinctrl_dev *pctldev, | ||||
| 			unsigned int pin, unsigned long *config) | ||||
| { | ||||
| 	struct omap_rtc *rtc = pinctrl_dev_get_drvdata(pctldev); | ||||
| 	unsigned int param = pinconf_to_config_param(*config); | ||||
| 	u32 val; | ||||
| 	u16 arg = 0; | ||||
| 
 | ||||
| 	rtc->type->unlock(rtc); | ||||
| 	val = rtc_readl(rtc, OMAP_RTC_PMIC_REG); | ||||
| 	rtc->type->lock(rtc); | ||||
| 
 | ||||
| 	switch (param) { | ||||
| 	case PIN_CONFIG_INPUT_ENABLE: | ||||
| 		if (!(val & OMAP_RTC_PMIC_EXT_WKUP_EN(pin))) | ||||
| 			return -EINVAL; | ||||
| 		break; | ||||
| 	case PIN_CONFIG_ACTIVE_HIGH: | ||||
| 		if (val & OMAP_RTC_PMIC_EXT_WKUP_POL(pin)) | ||||
| 			return -EINVAL; | ||||
| 		break; | ||||
| 	default: | ||||
| 		return -ENOTSUPP; | ||||
| 	}; | ||||
| 
 | ||||
| 	*config = pinconf_to_config_packed(param, arg); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int rtc_pinconf_set(struct pinctrl_dev *pctldev, | ||||
| 			unsigned int pin, unsigned long *configs, | ||||
| 			unsigned int num_configs) | ||||
| { | ||||
| 	struct omap_rtc *rtc = pinctrl_dev_get_drvdata(pctldev); | ||||
| 	u32 val; | ||||
| 	unsigned int param; | ||||
| 	u16 param_val; | ||||
| 	int i; | ||||
| 
 | ||||
| 	rtc->type->unlock(rtc); | ||||
| 	val = rtc_readl(rtc, OMAP_RTC_PMIC_REG); | ||||
| 	rtc->type->lock(rtc); | ||||
| 
 | ||||
| 	/* active low by default */ | ||||
| 	val |= OMAP_RTC_PMIC_EXT_WKUP_POL(pin); | ||||
| 
 | ||||
| 	for (i = 0; i < num_configs; i++) { | ||||
| 		param = pinconf_to_config_param(configs[i]); | ||||
| 		param_val = pinconf_to_config_argument(configs[i]); | ||||
| 
 | ||||
| 		switch (param) { | ||||
| 		case PIN_CONFIG_INPUT_ENABLE: | ||||
| 			if (param_val) | ||||
| 				val |= OMAP_RTC_PMIC_EXT_WKUP_EN(pin); | ||||
| 			else | ||||
| 				val &= ~OMAP_RTC_PMIC_EXT_WKUP_EN(pin); | ||||
| 			break; | ||||
| 		case PIN_CONFIG_ACTIVE_HIGH: | ||||
| 			val &= ~OMAP_RTC_PMIC_EXT_WKUP_POL(pin); | ||||
| 			break; | ||||
| 		default: | ||||
| 			dev_err(&rtc->rtc->dev, "Property %u not supported\n", | ||||
| 				param); | ||||
| 			return -ENOTSUPP; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	rtc->type->unlock(rtc); | ||||
| 	rtc_writel(rtc, OMAP_RTC_PMIC_REG, val); | ||||
| 	rtc->type->lock(rtc); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static const struct pinconf_ops rtc_pinconf_ops = { | ||||
| 	.is_generic = true, | ||||
| 	.pin_config_get = rtc_pinconf_get, | ||||
| 	.pin_config_set = rtc_pinconf_set, | ||||
| }; | ||||
| 
 | ||||
| static struct pinctrl_desc rtc_pinctrl_desc = { | ||||
| 	.pins = rtc_pins_desc, | ||||
| 	.npins = ARRAY_SIZE(rtc_pins_desc), | ||||
| 	.pctlops = &rtc_pinctrl_ops, | ||||
| 	.confops = &rtc_pinconf_ops, | ||||
| 	.custom_params = rtc_params, | ||||
| 	.num_custom_params = ARRAY_SIZE(rtc_params), | ||||
| #ifdef CONFIG_DEBUG_FS | ||||
| 	.custom_conf_items = rtc_conf_items, | ||||
| #endif | ||||
| 	.owner = THIS_MODULE, | ||||
| }; | ||||
| 
 | ||||
| static int omap_rtc_probe(struct platform_device *pdev) | ||||
| { | ||||
| 	struct omap_rtc	*rtc; | ||||
|  | @ -681,6 +821,15 @@ static int omap_rtc_probe(struct platform_device *pdev) | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* Support ext_wakeup pinconf */ | ||||
| 	rtc_pinctrl_desc.name = dev_name(&pdev->dev); | ||||
| 
 | ||||
| 	rtc->pctldev = pinctrl_register(&rtc_pinctrl_desc, &pdev->dev, rtc); | ||||
| 	if (IS_ERR(rtc->pctldev)) { | ||||
| 		dev_err(&pdev->dev, "Couldn't register pinctrl driver\n"); | ||||
| 		return PTR_ERR(rtc->pctldev); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| err: | ||||
|  | @ -724,6 +873,9 @@ static int __exit omap_rtc_remove(struct platform_device *pdev) | |||
| 	pm_runtime_put_sync(&pdev->dev); | ||||
| 	pm_runtime_disable(&pdev->dev); | ||||
| 
 | ||||
| 	/* Remove ext_wakeup pinconf */ | ||||
| 	pinctrl_unregister(rtc->pctldev); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Marcin Niestroj
						Marcin Niestroj