From 5b11e5d784c2dab41cd3171f4d297bdcac1b85ed Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 20 Feb 2020 21:58:12 -0300 Subject: [PATCH 01/26] power/supply: ingenic-battery: Don't print error on -EPROBE_DEFER Don't print an error message if devm_power_supply_register() returns -EPROBE_DEFER, since the driver will simply re-probe later. Signed-off-by: Paul Cercueil Signed-off-by: Sebastian Reichel --- drivers/power/supply/ingenic-battery.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/ingenic-battery.c b/drivers/power/supply/ingenic-battery.c index 2748715c4c75..dd3d93dfe3eb 100644 --- a/drivers/power/supply/ingenic-battery.c +++ b/drivers/power/supply/ingenic-battery.c @@ -148,7 +148,8 @@ static int ingenic_battery_probe(struct platform_device *pdev) bat->battery = devm_power_supply_register(dev, desc, &psy_cfg); if (IS_ERR(bat->battery)) { - dev_err(dev, "Unable to register battery\n"); + if (PTR_ERR(bat->battery) != -EPROBE_DEFER) + dev_err(dev, "Unable to register battery\n"); return PTR_ERR(bat->battery); } From 1c5dfc5e3f2df5892a849621d729daa87cfef436 Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Fri, 14 Feb 2020 13:38:58 +0800 Subject: [PATCH 02/26] power: supply: sc27xx: Add POWER_SUPPLY_PROP_CHARGE_NOW attribute Add the POWER_SUPPLY_PROP_CHARGE_NOW attribute to allow user to get current battery capacity (uAh) to do measurement. Signed-off-by: Baolin Wang Signed-off-by: Sebastian Reichel --- drivers/power/supply/sc27xx_fuel_gauge.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/power/supply/sc27xx_fuel_gauge.c b/drivers/power/supply/sc27xx_fuel_gauge.c index 469c83fdaa8e..a7c8a8453db1 100644 --- a/drivers/power/supply/sc27xx_fuel_gauge.c +++ b/drivers/power/supply/sc27xx_fuel_gauge.c @@ -614,6 +614,17 @@ static int sc27xx_fgu_get_property(struct power_supply *psy, val->intval = data->total_cap * 1000; break; + case POWER_SUPPLY_PROP_CHARGE_NOW: + ret = sc27xx_fgu_get_clbcnt(data, &value); + if (ret) + goto error; + + value = DIV_ROUND_CLOSEST(value * 10, + 36 * SC27XX_FGU_SAMPLE_HZ); + val->intval = sc27xx_fgu_adc_to_current(data, value); + + break; + default: ret = -EINVAL; break; @@ -682,6 +693,7 @@ static enum power_supply_property sc27xx_fgu_props[] = { POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, POWER_SUPPLY_PROP_CALIBRATE, + POWER_SUPPLY_PROP_CHARGE_NOW }; static const struct power_supply_desc sc27xx_fgu_desc = { From 241eaabc3c315cdfea505725a43de848f498527f Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Fri, 6 Mar 2020 10:34:10 +0800 Subject: [PATCH 03/26] power: supply: Allow charger manager can be built as a module Allow charger manager can be built as a module like other charger drivers. Signed-off-by: Baolin Wang Signed-off-by: Sebastian Reichel --- drivers/power/supply/Kconfig | 2 +- include/linux/power/charger-manager.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 9a5591ab90d0..195bc0462d3e 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -480,7 +480,7 @@ config CHARGER_GPIO called gpio-charger. config CHARGER_MANAGER - bool "Battery charger manager for multiple chargers" + tristate "Battery charger manager for multiple chargers" depends on REGULATOR select EXTCON help diff --git a/include/linux/power/charger-manager.h b/include/linux/power/charger-manager.h index ad19e68e1fc3..ae94dcebd936 100644 --- a/include/linux/power/charger-manager.h +++ b/include/linux/power/charger-manager.h @@ -248,7 +248,7 @@ struct charger_manager { u64 charging_end_time; }; -#ifdef CONFIG_CHARGER_MANAGER +#if IS_ENABLED(CONFIG_CHARGER_MANAGER) extern void cm_notify_event(struct power_supply *psy, enum cm_event_types type, char *msg); #else From ddb74e985f2d3db1ef5688121c8b1961f0c9d80d Mon Sep 17 00:00:00 2001 From: Ashish Chavan Date: Wed, 26 Feb 2020 23:22:23 +0530 Subject: [PATCH 04/26] power: supply: ab8500_charger: Fix typos in commit messages Trivial fix to spelling mistake in commit messages. Signed-off-by: Ashish Chavan Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500_charger.c | 35 +++++++++++++++------------ 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c index f69550d64f09..9469fe182d02 100644 --- a/drivers/power/supply/ab8500_charger.c +++ b/drivers/power/supply/ab8500_charger.c @@ -404,7 +404,7 @@ disable_otp: } /** - * ab8500_power_supply_changed - a wrapper with local extentions for + * ab8500_power_supply_changed - a wrapper with local extensions for * power_supply_changed * @di: pointer to the ab8500_charger structure * @psy: pointer to power_supply_that have changed. @@ -683,7 +683,7 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di, /* * Platform only supports USB 2.0. * This means that charging current from USB source - * is maximum 500 mA. Every occurence of USB_STAT_*_HOST_* + * is maximum 500 mA. Every occurrence of USB_STAT_*_HOST_* * should set USB_CH_IP_CUR_LVL_0P5. */ @@ -1379,13 +1379,13 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, /* * Due to a bug in AB8500, BTEMP_HIGH/LOW interrupts - * will be triggered everytime we enable the VDD ADC supply. + * will be triggered every time we enable the VDD ADC supply. * This will turn off charging for a short while. * It can be avoided by having the supply on when * there is a charger enabled. Normally the VDD ADC supply - * is enabled everytime a GPADC conversion is triggered. We will - * force it to be enabled from this driver to have - * the GPADC module independant of the AB8500 chargers + * is enabled every time a GPADC conversion is triggered. + * We will force it to be enabled from this driver to have + * the GPADC module independent of the AB8500 chargers */ if (!di->vddadc_en_ac) { ret = regulator_enable(di->regu); @@ -1455,7 +1455,7 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger, if (is_ab8500_1p1_or_earlier(di->parent)) { /* * For ABB revision 1.0 and 1.1 there is a bug in the - * watchdog logic. That means we have to continously + * watchdog logic. That means we have to continuously * kick the charger watchdog even when no charger is * connected. This is only valid once the AC charger * has been enabled. This is a bug that is not handled @@ -1552,13 +1552,13 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger, /* * Due to a bug in AB8500, BTEMP_HIGH/LOW interrupts - * will be triggered everytime we enable the VDD ADC supply. + * will be triggered every time we enable the VDD ADC supply. * This will turn off charging for a short while. * It can be avoided by having the supply on when * there is a charger enabled. Normally the VDD ADC supply - * is enabled everytime a GPADC conversion is triggered. We will - * force it to be enabled from this driver to have - * the GPADC module independant of the AB8500 chargers + * is enabled every time a GPADC conversion is triggered. + * We will force it to be enabled from this driver to have + * the GPADC module independent of the AB8500 chargers */ if (!di->vddadc_en_usb) { ret = regulator_enable(di->regu); @@ -1582,7 +1582,10 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger, return -ENXIO; } - /* ChVoltLevel: max voltage upto which battery can be charged */ + /* + * ChVoltLevel: max voltage up to which battery can be + * charged + */ ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER, AB8500_CH_VOLT_LVL_REG, (u8) volt_index); if (ret) { @@ -2014,7 +2017,7 @@ static void ab8500_charger_check_hw_failure_work(struct work_struct *work) * Work queue function for kicking the charger watchdog. * * For ABB revision 1.0 and 1.1 there is a bug in the watchdog - * logic. That means we have to continously kick the charger + * logic. That means we have to continuously kick the charger * watchdog even when no charger is connected. This is only * valid once the AC charger has been enabled. This is * a bug that is not handled by the algorithm and the @@ -2262,7 +2265,7 @@ static void ab8500_charger_usb_link_status_work(struct work_struct *work) * Some chargers that breaks the USB spec is * identified as invalid by AB8500 and it refuse * to start the charging process. but by jumping - * thru a few hoops it can be forced to start. + * through a few hoops it can be forced to start. */ if (is_ab8500(di->parent)) ret = abx500_get_register_interruptible(di->dev, AB8500_USB, @@ -3214,7 +3217,7 @@ static int ab8500_charger_resume(struct platform_device *pdev) /* * For ABB revision 1.0 and 1.1 there is a bug in the watchdog - * logic. That means we have to continously kick the charger + * logic. That means we have to continuously kick the charger * watchdog even when no charger is connected. This is only * valid once the AC charger has been enabled. This is * a bug that is not handled by the algorithm and the @@ -3483,7 +3486,7 @@ static int ab8500_charger_probe(struct platform_device *pdev) /* * For ABB revision 1.0 and 1.1 there is a bug in the watchdog - * logic. That means we have to continously kick the charger + * logic. That means we have to continuously kick the charger * watchdog even when no charger is connected. This is only * valid once the AC charger has been enabled. This is * a bug that is not handled by the algorithm and the From e42fe5b29ac07210297e75f36deefe54edbdbf80 Mon Sep 17 00:00:00 2001 From: Jeffery Miller Date: Tue, 25 Feb 2020 16:59:41 -0600 Subject: [PATCH 05/26] power: supply: axp288_fuel_gauge: Broaden vendor check for Intel Compute Sticks. The Intel Compute Stick `STK1A32SC` can have a system vendor of "Intel(R) Client Systems". Broaden the Intel Compute Stick DMI checks so that they match "Intel Corporation" as well as "Intel(R) Client Systems". This fixes an issue where the STK1A32SC compute sticks were still exposing a battery with the existing blacklist entry. Signed-off-by: Jeffery Miller Reviewed-by: Hans de Goede Signed-off-by: Sebastian Reichel --- drivers/power/supply/axp288_fuel_gauge.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/axp288_fuel_gauge.c b/drivers/power/supply/axp288_fuel_gauge.c index e1bc4e6e6f30..f40fa0e63b6e 100644 --- a/drivers/power/supply/axp288_fuel_gauge.c +++ b/drivers/power/supply/axp288_fuel_gauge.c @@ -706,14 +706,14 @@ static const struct dmi_system_id axp288_fuel_gauge_blacklist[] = { { /* Intel Cherry Trail Compute Stick, Windows version */ .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_SYS_VENDOR, "Intel"), DMI_MATCH(DMI_PRODUCT_NAME, "STK1AW32SC"), }, }, { /* Intel Cherry Trail Compute Stick, version without an OS */ .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_SYS_VENDOR, "Intel"), DMI_MATCH(DMI_PRODUCT_NAME, "STK1A32SC"), }, }, From 9c80662a74cd2a5d1113f5c69d027face963a556 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 23 Feb 2020 16:32:08 +0100 Subject: [PATCH 06/26] power: supply: axp288_charger: Add special handling for HP Pavilion x2 10 Some HP Pavilion x2 10 models use an AXP288 for charging and fuel-gauge. We use a native power_supply / PMIC driver in this case, because on most models with an AXP288 the ACPI AC / Battery code is either completely missing or relies on custom / proprietary ACPI OpRegions which Linux does not implement. The native drivers mostly work fine, but there are 2 problems: 1. These model uses a Type-C connector for charging which the AXP288 does not support. As long as a Type-A charger (which uses the USB data pins for charger type detection) is used everything is fine. But if a Type-C charger is used (such as the charger shipped with the device) then the charger is not recognized. So we end up slowly discharging the device even though a charger is connected, because we are limiting the current from the charger to 500mA. To make things worse this happens with the device's official charger. Looking at the ACPI tables HP has "solved" the problem of the AXP288 not being able to recognize Type-C chargers by simply always programming the input-current-limit at 3000mA and relying on a Vhold setting of 4.7V (normally 4.4V) to limit the current intake if the charger cannot handle this. 2. If no charger is connected when the machine boots then it boots with the vbus-path disabled. On other devices this is done when a 5V boost converter is active to avoid the PMIC trying to charge from the 5V boost output. This is done when an OTG host cable is inserted and the ID pin on the micro-B receptacle is pulled low, the ID pin has an ACPI event handler associated with it which re-enables the vbus-path when the ID pin is pulled high when the OTG cable is removed. The Type-C connector has no ID pin, there is no ID pin handler and there appears to be no 5V boost converter, so we end up not charging because the vbus-path is disabled, until we unplug the charger which automatically clears the vbus-path disable bit and then on the second plug-in of the adapter we start charging. The HP Pavilion x2 10 models with an AXP288 do have mostly working ACPI AC / Battery code which does not rely on custom / proprietary ACPI OpRegions. So one possible solution would be to blacklist the AXP288 native power_supply drivers and add the HP Pavilion x2 10 with AXP288 DMI ids to the list of devices which should use the ACPI AC / Battery code even though they have an AXP288 PMIC. This would require changes to 4 files: drivers/acpi/ac.c, drivers/power/supply/axp288_charger.c, drivers/acpi/battery.c and drivers/power/supply/axp288_fuel_gauge.c. Beside needing adding the same DMI matches to 4 different files, this approach also triggers problem 2. from above, but then when suspended, during suspend the machine will not wakeup because the vbus path is disabled by the AML code when not charging, so the Vbus low-to-high IRQ is not triggered, the CPU never wakes up and the device does not charge even though the user likely things it is charging, esp. since the charge status LED is directly coupled to an adapter being plugged in and does not reflect actual charging. This could be worked by enabling vbus-path explicitly from say the axp288_charger driver's suspend handler. So neither situation is ideal, in both cased we need to explicitly enable the vbus-path to work around different variants of problem 2 above, this requires a quirk in the axp288_charger code. If we go the route of using the ACPI AC / Battery drivers then we need modifications to 3 other drivers; and we need to partially disable the axp288_charger code, while at the same time keeping it around to enable vbus-path on suspend. OTOH we can copy the hardcoding of 3A input-current-limit (we never touch Vhold, so that would stay at 4.7V) to the axp288_charger code, which needs changes regardless, then we concentrate all special handling of this interesting device model in the axp288_charger code. That is what this commit does. Cc: stable@vger.kernel.org BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1791098 Signed-off-by: Hans de Goede Signed-off-by: Sebastian Reichel --- drivers/power/supply/axp288_charger.c | 57 ++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/axp288_charger.c b/drivers/power/supply/axp288_charger.c index 1bbba6bba673..cf4c67b2d235 100644 --- a/drivers/power/supply/axp288_charger.c +++ b/drivers/power/supply/axp288_charger.c @@ -21,6 +21,7 @@ #include #include #include +#include #define PS_STAT_VBUS_TRIGGER BIT(0) #define PS_STAT_BAT_CHRG_DIR BIT(2) @@ -545,6 +546,49 @@ out: return IRQ_HANDLED; } +/* + * The HP Pavilion x2 10 series comes in a number of variants: + * Bay Trail SoC + AXP288 PMIC, DMI_BOARD_NAME: "815D" + * Cherry Trail SoC + AXP288 PMIC, DMI_BOARD_NAME: "813E" + * Cherry Trail SoC + TI PMIC, DMI_BOARD_NAME: "827C" or "82F4" + * + * The variants with the AXP288 PMIC are all kinds of special: + * + * 1. All variants use a Type-C connector which the AXP288 does not support, so + * when using a Type-C charger it is not recognized. Unlike most AXP288 devices, + * this model actually has mostly working ACPI AC / Battery code, the ACPI code + * "solves" this by simply setting the input_current_limit to 3A. + * There are still some issues with the ACPI code, so we use this native driver, + * and to solve the charging not working (500mA is not enough) issue we hardcode + * the 3A input_current_limit like the ACPI code does. + * + * 2. If no charger is connected the machine boots with the vbus-path disabled. + * Normally this is done when a 5V boost converter is active to avoid the PMIC + * trying to charge from the 5V boost converter's output. This is done when + * an OTG host cable is inserted and the ID pin on the micro-B receptacle is + * pulled low and the ID pin has an ACPI event handler associated with it + * which re-enables the vbus-path when the ID pin is pulled high when the + * OTG host cable is removed. The Type-C connector has no ID pin, there is + * no ID pin handler and there appears to be no 5V boost converter, so we + * end up not charging because the vbus-path is disabled, until we unplug + * the charger which automatically clears the vbus-path disable bit and then + * on the second plug-in of the adapter we start charging. To solve the not + * charging on first charger plugin we unconditionally enable the vbus-path at + * probe on this model, which is safe since there is no 5V boost converter. + */ +static const struct dmi_system_id axp288_hp_x2_dmi_ids[] = { + { + /* + * Bay Trail model has "Hewlett-Packard" as sys_vendor, Cherry + * Trail model has "HP", so we only match on product_name. + */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"), + }, + }, + {} /* Terminating entry */ +}; + static void axp288_charger_extcon_evt_worker(struct work_struct *work) { struct axp288_chrg_info *info = @@ -568,7 +612,11 @@ static void axp288_charger_extcon_evt_worker(struct work_struct *work) } /* Determine cable/charger type */ - if (extcon_get_state(edev, EXTCON_CHG_USB_SDP) > 0) { + if (dmi_check_system(axp288_hp_x2_dmi_ids)) { + /* See comment above axp288_hp_x2_dmi_ids declaration */ + dev_dbg(&info->pdev->dev, "HP X2 with Type-C, setting inlmt to 3A\n"); + current_limit = 3000000; + } else if (extcon_get_state(edev, EXTCON_CHG_USB_SDP) > 0) { dev_dbg(&info->pdev->dev, "USB SDP charger is connected\n"); current_limit = 500000; } else if (extcon_get_state(edev, EXTCON_CHG_USB_CDP) > 0) { @@ -685,6 +733,13 @@ static int charger_init_hw_regs(struct axp288_chrg_info *info) return ret; } + if (dmi_check_system(axp288_hp_x2_dmi_ids)) { + /* See comment above axp288_hp_x2_dmi_ids declaration */ + ret = axp288_charger_vbus_path_select(info, true); + if (ret < 0) + return ret; + } + /* Read current charge voltage and current limit */ ret = regmap_read(info->regmap, AXP20X_CHRG_CTRL1, &val); if (ret < 0) { From b2a16610f2ba72468b4a7ac1e462af1e9c70bae8 Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:29 +0000 Subject: [PATCH 07/26] power: reset: at91-reset: introduce struct at91_reset Introduce struct at91_reset intended to keep all the at91 reset controller data. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index d94e3267c3b6..2df0610e5527 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -49,7 +49,13 @@ enum reset_type { RESET_TYPE_ULP2 = 8, }; -static void __iomem *at91_ramc_base[2], *at91_rstc_base; +struct at91_reset { + void __iomem *rstc_base; +}; + +static struct at91_reset reset; + +static void __iomem *at91_ramc_base[2]; static struct clk *sclk; /* @@ -76,7 +82,7 @@ static int at91sam9260_restart(struct notifier_block *this, unsigned long mode, "b .\n\t" : : "r" (at91_ramc_base[0]), - "r" (at91_rstc_base), + "r" (reset.rstc_base), "r" (1), "r" cpu_to_le32(AT91_SDRAMC_LPCB_POWER_DOWN), "r" cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST)); @@ -119,7 +125,7 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, : : "r" (at91_ramc_base[0]), "r" (at91_ramc_base[1]), - "r" (at91_rstc_base), + "r" (reset.rstc_base), "r" (1), "r" cpu_to_le32(AT91_DDRSDRC_LPCB_POWER_DOWN), "r" cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST) @@ -131,8 +137,8 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, static int sama5d3_restart(struct notifier_block *this, unsigned long mode, void *cmd) { - writel(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST, - at91_rstc_base); + writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST), + reset.rstc_base); return NOTIFY_DONE; } @@ -140,14 +146,16 @@ static int sama5d3_restart(struct notifier_block *this, unsigned long mode, static int samx7_restart(struct notifier_block *this, unsigned long mode, void *cmd) { - writel(AT91_RSTC_KEY | AT91_RSTC_PROCRST, at91_rstc_base); + writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PROCRST), + reset.rstc_base); + return NOTIFY_DONE; } static void __init at91_reset_status(struct platform_device *pdev) { const char *reason; - u32 reg = readl(at91_rstc_base + AT91_RSTC_SR); + u32 reg = readl(reset.rstc_base + AT91_RSTC_SR); switch ((reg & AT91_RSTC_RSTTYP) >> 8) { case RESET_TYPE_GENERAL: @@ -208,8 +216,8 @@ static int __init at91_reset_probe(struct platform_device *pdev) struct device_node *np; int ret, idx = 0; - at91_rstc_base = of_iomap(pdev->dev.of_node, 0); - if (!at91_rstc_base) { + reset.rstc_base = of_iomap(pdev->dev.of_node, 0); + if (!reset.rstc_base) { dev_err(&pdev->dev, "Could not map reset controller address\n"); return -ENODEV; } From 4d9ce0f56aeeb46c8be0e8974646f163d3f6b72d Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:30 +0000 Subject: [PATCH 08/26] power: reset: at91-reset: add ramc_base[] to struct at91_reset Add ramc_base[] to struct at91_reset. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 2df0610e5527..999d3a1653d2 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -51,11 +51,11 @@ enum reset_type { struct at91_reset { void __iomem *rstc_base; + void __iomem *ramc_base[2]; }; static struct at91_reset reset; -static void __iomem *at91_ramc_base[2]; static struct clk *sclk; /* @@ -81,7 +81,7 @@ static int at91sam9260_restart(struct notifier_block *this, unsigned long mode, "b .\n\t" : - : "r" (at91_ramc_base[0]), + : "r" (reset.ramc_base[0]), "r" (reset.rstc_base), "r" (1), "r" cpu_to_le32(AT91_SDRAMC_LPCB_POWER_DOWN), @@ -123,8 +123,8 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, " b .\n\t" : - : "r" (at91_ramc_base[0]), - "r" (at91_ramc_base[1]), + : "r" (reset.ramc_base[0]), + "r" (reset.ramc_base[1]), "r" (reset.rstc_base), "r" (1), "r" cpu_to_le32(AT91_DDRSDRC_LPCB_POWER_DOWN), @@ -225,8 +225,8 @@ static int __init at91_reset_probe(struct platform_device *pdev) if (!of_device_is_compatible(pdev->dev.of_node, "atmel,sama5d3-rstc")) { /* we need to shutdown the ddr controller, so get ramc base */ for_each_matching_node(np, at91_ramc_of_match) { - at91_ramc_base[idx] = of_iomap(np, 0); - if (!at91_ramc_base[idx]) { + reset.ramc_base[idx] = of_iomap(np, 0); + if (!reset.ramc_base[idx]) { dev_err(&pdev->dev, "Could not map ram controller address\n"); of_node_put(np); return -ENODEV; From f9e6ce74cbf2a34f4d37bccbbfc7865e5b3e01dd Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:30 +0000 Subject: [PATCH 09/26] power: reset: at91-reset: add sclk to struct at91_reset Add sclk to struct at91_reset. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 999d3a1653d2..1bc39bfda0aa 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -52,12 +52,11 @@ enum reset_type { struct at91_reset { void __iomem *rstc_base; void __iomem *ramc_base[2]; + struct clk *sclk; }; static struct at91_reset reset; -static struct clk *sclk; - /* * unless the SDRAM is cleanly shutdown before we hit the * reset register it can be left driving the data bus and @@ -238,11 +237,11 @@ static int __init at91_reset_probe(struct platform_device *pdev) match = of_match_node(at91_reset_of_match, pdev->dev.of_node); at91_restart_nb.notifier_call = match->data; - sclk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(sclk)) - return PTR_ERR(sclk); + reset.sclk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(reset.sclk)) + return PTR_ERR(reset.sclk); - ret = clk_prepare_enable(sclk); + ret = clk_prepare_enable(reset.sclk); if (ret) { dev_err(&pdev->dev, "Could not enable slow clock\n"); return ret; @@ -250,7 +249,7 @@ static int __init at91_reset_probe(struct platform_device *pdev) ret = register_restart_handler(&at91_restart_nb); if (ret) { - clk_disable_unprepare(sclk); + clk_disable_unprepare(reset.sclk); return ret; } @@ -262,7 +261,7 @@ static int __init at91_reset_probe(struct platform_device *pdev) static int __exit at91_reset_remove(struct platform_device *pdev) { unregister_restart_handler(&at91_restart_nb); - clk_disable_unprepare(sclk); + clk_disable_unprepare(reset.sclk); return 0; } From 1e3c4af9de26a0246cf00aba207c49846e80c37b Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:31 +0000 Subject: [PATCH 10/26] power: reset: at91-reset: add notifier block to struct at91_reset Add struct notifier_block to struct at91_reset. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 1bc39bfda0aa..e8840193620d 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -53,6 +53,7 @@ struct at91_reset { void __iomem *rstc_base; void __iomem *ramc_base[2]; struct clk *sclk; + struct notifier_block nb; }; static struct at91_reset reset; @@ -205,10 +206,6 @@ static const struct of_device_id at91_reset_of_match[] = { }; MODULE_DEVICE_TABLE(of, at91_reset_of_match); -static struct notifier_block at91_restart_nb = { - .priority = 192, -}; - static int __init at91_reset_probe(struct platform_device *pdev) { const struct of_device_id *match; @@ -235,7 +232,8 @@ static int __init at91_reset_probe(struct platform_device *pdev) } match = of_match_node(at91_reset_of_match, pdev->dev.of_node); - at91_restart_nb.notifier_call = match->data; + reset.nb.notifier_call = match->data; + reset.nb.priority = 192; reset.sclk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(reset.sclk)) @@ -247,7 +245,7 @@ static int __init at91_reset_probe(struct platform_device *pdev) return ret; } - ret = register_restart_handler(&at91_restart_nb); + ret = register_restart_handler(&reset.nb); if (ret) { clk_disable_unprepare(reset.sclk); return ret; @@ -260,7 +258,7 @@ static int __init at91_reset_probe(struct platform_device *pdev) static int __exit at91_reset_remove(struct platform_device *pdev) { - unregister_restart_handler(&at91_restart_nb); + unregister_restart_handler(&reset.nb); clk_disable_unprepare(reset.sclk); return 0; From b7967b7919f0e3787d6e23424b5ad367fbb937e2 Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:31 +0000 Subject: [PATCH 11/26] power: reset: at91-reset: convert reset in pointer to struct at91_reset Convert reset in pointer to struct at91_reset. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 50 +++++++++++++++++--------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index e8840193620d..4bb5eef4b258 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -56,7 +56,7 @@ struct at91_reset { struct notifier_block nb; }; -static struct at91_reset reset; +static struct at91_reset *reset; /* * unless the SDRAM is cleanly shutdown before we hit the @@ -81,8 +81,8 @@ static int at91sam9260_restart(struct notifier_block *this, unsigned long mode, "b .\n\t" : - : "r" (reset.ramc_base[0]), - "r" (reset.rstc_base), + : "r" (reset->ramc_base[0]), + "r" (reset->rstc_base), "r" (1), "r" cpu_to_le32(AT91_SDRAMC_LPCB_POWER_DOWN), "r" cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST)); @@ -123,9 +123,9 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, " b .\n\t" : - : "r" (reset.ramc_base[0]), - "r" (reset.ramc_base[1]), - "r" (reset.rstc_base), + : "r" (reset->ramc_base[0]), + "r" (reset->ramc_base[1]), + "r" (reset->rstc_base), "r" (1), "r" cpu_to_le32(AT91_DDRSDRC_LPCB_POWER_DOWN), "r" cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST) @@ -138,7 +138,7 @@ static int sama5d3_restart(struct notifier_block *this, unsigned long mode, void *cmd) { writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST), - reset.rstc_base); + reset->rstc_base); return NOTIFY_DONE; } @@ -147,7 +147,7 @@ static int samx7_restart(struct notifier_block *this, unsigned long mode, void *cmd) { writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PROCRST), - reset.rstc_base); + reset->rstc_base); return NOTIFY_DONE; } @@ -155,7 +155,7 @@ static int samx7_restart(struct notifier_block *this, unsigned long mode, static void __init at91_reset_status(struct platform_device *pdev) { const char *reason; - u32 reg = readl(reset.rstc_base + AT91_RSTC_SR); + u32 reg = readl(reset->rstc_base + AT91_RSTC_SR); switch ((reg & AT91_RSTC_RSTTYP) >> 8) { case RESET_TYPE_GENERAL: @@ -212,8 +212,12 @@ static int __init at91_reset_probe(struct platform_device *pdev) struct device_node *np; int ret, idx = 0; - reset.rstc_base = of_iomap(pdev->dev.of_node, 0); - if (!reset.rstc_base) { + reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL); + if (!reset) + return -ENOMEM; + + reset->rstc_base = of_iomap(pdev->dev.of_node, 0); + if (!reset->rstc_base) { dev_err(&pdev->dev, "Could not map reset controller address\n"); return -ENODEV; } @@ -221,8 +225,8 @@ static int __init at91_reset_probe(struct platform_device *pdev) if (!of_device_is_compatible(pdev->dev.of_node, "atmel,sama5d3-rstc")) { /* we need to shutdown the ddr controller, so get ramc base */ for_each_matching_node(np, at91_ramc_of_match) { - reset.ramc_base[idx] = of_iomap(np, 0); - if (!reset.ramc_base[idx]) { + reset->ramc_base[idx] = of_iomap(np, 0); + if (!reset->ramc_base[idx]) { dev_err(&pdev->dev, "Could not map ram controller address\n"); of_node_put(np); return -ENODEV; @@ -232,22 +236,22 @@ static int __init at91_reset_probe(struct platform_device *pdev) } match = of_match_node(at91_reset_of_match, pdev->dev.of_node); - reset.nb.notifier_call = match->data; - reset.nb.priority = 192; + reset->nb.notifier_call = match->data; + reset->nb.priority = 192; - reset.sclk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(reset.sclk)) - return PTR_ERR(reset.sclk); + reset->sclk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(reset->sclk)) + return PTR_ERR(reset->sclk); - ret = clk_prepare_enable(reset.sclk); + ret = clk_prepare_enable(reset->sclk); if (ret) { dev_err(&pdev->dev, "Could not enable slow clock\n"); return ret; } - ret = register_restart_handler(&reset.nb); + ret = register_restart_handler(&reset->nb); if (ret) { - clk_disable_unprepare(reset.sclk); + clk_disable_unprepare(reset->sclk); return ret; } @@ -258,8 +262,8 @@ static int __init at91_reset_probe(struct platform_device *pdev) static int __exit at91_reset_remove(struct platform_device *pdev) { - unregister_restart_handler(&reset.nb); - clk_disable_unprepare(reset.sclk); + unregister_restart_handler(&reset->nb); + clk_disable_unprepare(reset->sclk); return 0; } From 55f8e6fdefbe926e1729bba3a7608eed7d7f24f5 Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:32 +0000 Subject: [PATCH 12/26] power: reset: at91-reset: pass rstc base address to at91_reset_status() Add new argument to at91_reset_status() that is the pointer to reset controller base address. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 4bb5eef4b258..bd05496c5ac7 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -152,10 +152,11 @@ static int samx7_restart(struct notifier_block *this, unsigned long mode, return NOTIFY_DONE; } -static void __init at91_reset_status(struct platform_device *pdev) +static void __init at91_reset_status(struct platform_device *pdev, + void __iomem *base) { const char *reason; - u32 reg = readl(reset->rstc_base + AT91_RSTC_SR); + u32 reg = readl(base + AT91_RSTC_SR); switch ((reg & AT91_RSTC_RSTTYP) >> 8) { case RESET_TYPE_GENERAL: @@ -255,7 +256,7 @@ static int __init at91_reset_probe(struct platform_device *pdev) return ret; } - at91_reset_status(pdev); + at91_reset_status(pdev, reset->rstc_base); return 0; } From 583ef884c8dc8e5ec9a7fde12d40ef7fdf18f5fb Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:32 +0000 Subject: [PATCH 13/26] power: reset: at91-reset: devm_kzalloc() for at91_reset data structure Allocate at91_reset data on probe and set it as platform data. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index bd05496c5ac7..7ba77555e9e1 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -56,8 +56,6 @@ struct at91_reset { struct notifier_block nb; }; -static struct at91_reset *reset; - /* * unless the SDRAM is cleanly shutdown before we hit the * reset register it can be left driving the data bus and @@ -66,6 +64,8 @@ static struct at91_reset *reset; static int at91sam9260_restart(struct notifier_block *this, unsigned long mode, void *cmd) { + struct at91_reset *reset = container_of(this, struct at91_reset, nb); + asm volatile( /* Align to cache lines */ ".balign 32\n\t" @@ -93,6 +93,8 @@ static int at91sam9260_restart(struct notifier_block *this, unsigned long mode, static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, void *cmd) { + struct at91_reset *reset = container_of(this, struct at91_reset, nb); + asm volatile( /* * Test wether we have a second RAM controller to care @@ -137,6 +139,8 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, static int sama5d3_restart(struct notifier_block *this, unsigned long mode, void *cmd) { + struct at91_reset *reset = container_of(this, struct at91_reset, nb); + writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST), reset->rstc_base); @@ -146,6 +150,8 @@ static int sama5d3_restart(struct notifier_block *this, unsigned long mode, static int samx7_restart(struct notifier_block *this, unsigned long mode, void *cmd) { + struct at91_reset *reset = container_of(this, struct at91_reset, nb); + writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PROCRST), reset->rstc_base); @@ -210,6 +216,7 @@ MODULE_DEVICE_TABLE(of, at91_reset_of_match); static int __init at91_reset_probe(struct platform_device *pdev) { const struct of_device_id *match; + struct at91_reset *reset; struct device_node *np; int ret, idx = 0; @@ -250,6 +257,8 @@ static int __init at91_reset_probe(struct platform_device *pdev) return ret; } + platform_set_drvdata(pdev, reset); + ret = register_restart_handler(&reset->nb); if (ret) { clk_disable_unprepare(reset->sclk); @@ -263,6 +272,8 @@ static int __init at91_reset_probe(struct platform_device *pdev) static int __exit at91_reset_remove(struct platform_device *pdev) { + struct at91_reset *reset = platform_get_drvdata(pdev); + unregister_restart_handler(&reset->nb); clk_disable_unprepare(reset->sclk); From a5bbad258a9ec41df4a158c828b9ef0af7955854 Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:32 +0000 Subject: [PATCH 14/26] power: reset: at91-reset: introduce struct at91_reset_data Introduce struct at91_reset_data to be able to provide per SoC data. At the moment this being only notifier callback. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 50 ++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 7ba77555e9e1..c653bd7ac29a 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -49,6 +49,11 @@ enum reset_type { RESET_TYPE_ULP2 = 8, }; +struct at91_reset_data { + int (*notifier_call)(struct notifier_block *this, unsigned long mode, + void *cmd); +}; + struct at91_reset { void __iomem *rstc_base; void __iomem *ramc_base[2]; @@ -203,18 +208,50 @@ static const struct of_device_id at91_ramc_of_match[] = { { /* sentinel */ } }; +static const struct at91_reset_data at91sam9260_reset_data = { + .notifier_call = at91sam9260_restart, +}; + +static const struct at91_reset_data at91sam9g45_reset_data = { + .notifier_call = at91sam9g45_restart, +}; + +static const struct at91_reset_data sama5d3_reset_data = { + .notifier_call = sama5d3_restart, +}; + +static const struct at91_reset_data samx7_reset_data = { + .notifier_call = samx7_restart, +}; + static const struct of_device_id at91_reset_of_match[] = { - { .compatible = "atmel,at91sam9260-rstc", .data = at91sam9260_restart }, - { .compatible = "atmel,at91sam9g45-rstc", .data = at91sam9g45_restart }, - { .compatible = "atmel,sama5d3-rstc", .data = sama5d3_restart }, - { .compatible = "atmel,samx7-rstc", .data = samx7_restart }, - { .compatible = "microchip,sam9x60-rstc", .data = samx7_restart }, + { + .compatible = "atmel,at91sam9260-rstc", + .data = &at91sam9260_reset_data + }, + { + .compatible = "atmel,at91sam9g45-rstc", + .data = &at91sam9g45_reset_data + }, + { + .compatible = "atmel,sama5d3-rstc", + .data = &sama5d3_reset_data + }, + { + .compatible = "atmel,samx7-rstc", + .data = &samx7_reset_data + }, + { + .compatible = "microchip,sam9x60-rstc", + .data = &samx7_reset_data + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, at91_reset_of_match); static int __init at91_reset_probe(struct platform_device *pdev) { + const struct at91_reset_data *reset_data; const struct of_device_id *match; struct at91_reset *reset; struct device_node *np; @@ -244,7 +281,8 @@ static int __init at91_reset_probe(struct platform_device *pdev) } match = of_match_node(at91_reset_of_match, pdev->dev.of_node); - reset->nb.notifier_call = match->data; + reset_data = match->data; + reset->nb.notifier_call = reset_data->notifier_call; reset->nb.priority = 192; reset->sclk = devm_clk_get(&pdev->dev, NULL); From 25b80b7d5a5b41cb52db441e37a04d71e7196f60 Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:33 +0000 Subject: [PATCH 15/26] power: reset: at91-reset: introduce args member in at91_reset_data Introduce args member in struct at91_reset_data. It stores the value that needs to be written in mode register so that the reboot actions to happen. With these changes samx7_restart() could be removed. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index c653bd7ac29a..dc48f6850796 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -52,6 +52,7 @@ enum reset_type { struct at91_reset_data { int (*notifier_call)(struct notifier_block *this, unsigned long mode, void *cmd); + u32 args; }; struct at91_reset { @@ -59,6 +60,7 @@ struct at91_reset { void __iomem *ramc_base[2]; struct clk *sclk; struct notifier_block nb; + u32 args; }; /* @@ -90,7 +92,7 @@ static int at91sam9260_restart(struct notifier_block *this, unsigned long mode, "r" (reset->rstc_base), "r" (1), "r" cpu_to_le32(AT91_SDRAMC_LPCB_POWER_DOWN), - "r" cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST)); + "r" (reset->args)); return NOTIFY_DONE; } @@ -135,7 +137,7 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, "r" (reset->rstc_base), "r" (1), "r" cpu_to_le32(AT91_DDRSDRC_LPCB_POWER_DOWN), - "r" cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST) + "r" (reset->args) : "r0"); return NOTIFY_DONE; @@ -146,19 +148,7 @@ static int sama5d3_restart(struct notifier_block *this, unsigned long mode, { struct at91_reset *reset = container_of(this, struct at91_reset, nb); - writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST), - reset->rstc_base); - - return NOTIFY_DONE; -} - -static int samx7_restart(struct notifier_block *this, unsigned long mode, - void *cmd) -{ - struct at91_reset *reset = container_of(this, struct at91_reset, nb); - - writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PROCRST), - reset->rstc_base); + writel(reset->args, reset->rstc_base); return NOTIFY_DONE; } @@ -210,18 +200,22 @@ static const struct of_device_id at91_ramc_of_match[] = { static const struct at91_reset_data at91sam9260_reset_data = { .notifier_call = at91sam9260_restart, + .args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST, }; static const struct at91_reset_data at91sam9g45_reset_data = { .notifier_call = at91sam9g45_restart, + .args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST, }; static const struct at91_reset_data sama5d3_reset_data = { .notifier_call = sama5d3_restart, + .args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST, }; static const struct at91_reset_data samx7_reset_data = { - .notifier_call = samx7_restart, + .notifier_call = sama5d3_restart, + .args = AT91_RSTC_KEY | AT91_RSTC_PROCRST, }; static const struct of_device_id at91_reset_of_match[] = { @@ -284,6 +278,7 @@ static int __init at91_reset_probe(struct platform_device *pdev) reset_data = match->data; reset->nb.notifier_call = reset_data->notifier_call; reset->nb.priority = 192; + reset->args = reset_data->args; reset->sclk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(reset->sclk)) From 7cb290d3dd559dff5028b9418a31ecb99988f640 Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:33 +0000 Subject: [PATCH 16/26] power: reset: at91-reset: use r4 as tmp argument Use r4 as temporary register. On ARM r0-r3 should be used to hold function arguments. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index dc48f6850796..3b1d566350f4 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -113,8 +113,8 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, "beq 1f\n\t" /* Then, test that the RAM controller is enabled */ - "ldr r0, [%1]\n\t" - "cmp r0, #0\n\t" + "ldr r4, [%1]\n\t" + "cmp r4, #0\n\t" /* Align to cache lines */ ".balign 32\n\t" @@ -138,7 +138,7 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, "r" (1), "r" cpu_to_le32(AT91_DDRSDRC_LPCB_POWER_DOWN), "r" (reset->args) - : "r0"); + : "r4"); return NOTIFY_DONE; } From 68a84a3e68a2238036dd6c7dbb677fe62a92d70a Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:34 +0000 Subject: [PATCH 17/26] power: reset: at91-reset: introduce ramc_lpr to struct at91_reset Introduce ramc_lpr to struct at91_reset. This will lead to the unification of at91sam9260_restart() and at91sam9g45_restart(). Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 3b1d566350f4..4e1961334e4d 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -61,6 +61,7 @@ struct at91_reset { struct clk *sclk; struct notifier_block nb; u32 args; + u32 ramc_lpr; }; /* @@ -81,7 +82,7 @@ static int at91sam9260_restart(struct notifier_block *this, unsigned long mode, "str %2, [%0, #" __stringify(AT91_SDRAMC_TR) "]\n\t" /* Power down SDRAM */ - "str %3, [%0, #" __stringify(AT91_SDRAMC_LPR) "]\n\t" + "str %3, [%0, %5]\n\t" /* Reset CPU */ "str %4, [%1, #" __stringify(AT91_RSTC_CR) "]\n\t" @@ -92,7 +93,8 @@ static int at91sam9260_restart(struct notifier_block *this, unsigned long mode, "r" (reset->rstc_base), "r" (1), "r" cpu_to_le32(AT91_SDRAMC_LPCB_POWER_DOWN), - "r" (reset->args)); + "r" (reset->args), + "r" (reset->ramc_lpr)); return NOTIFY_DONE; } @@ -122,11 +124,11 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, /* Disable SDRAM0 accesses */ "1: str %3, [%0, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t" /* Power down SDRAM0 */ - " str %4, [%0, #" __stringify(AT91_DDRSDRC_LPR) "]\n\t" + " str %4, [%0, %6]\n\t" /* Disable SDRAM1 accesses */ " strne %3, [%1, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t" /* Power down SDRAM1 */ - " strne %4, [%1, #" __stringify(AT91_DDRSDRC_LPR) "]\n\t" + " strne %4, [%1, %6]\n\t" /* Reset CPU */ " str %5, [%2, #" __stringify(AT91_RSTC_CR) "]\n\t" @@ -137,7 +139,8 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, "r" (reset->rstc_base), "r" (1), "r" cpu_to_le32(AT91_DDRSDRC_LPCB_POWER_DOWN), - "r" (reset->args) + "r" (reset->args), + "r" (reset->ramc_lpr) : "r4"); return NOTIFY_DONE; @@ -193,8 +196,14 @@ static void __init at91_reset_status(struct platform_device *pdev, } static const struct of_device_id at91_ramc_of_match[] = { - { .compatible = "atmel,at91sam9260-sdramc", }, - { .compatible = "atmel,at91sam9g45-ddramc", }, + { + .compatible = "atmel,at91sam9260-sdramc", + .data = (void *)AT91_SDRAMC_LPR, + }, + { + .compatible = "atmel,at91sam9g45-ddramc", + .data = (void *)AT91_DDRSDRC_LPR, + }, { /* sentinel */ } }; @@ -263,7 +272,8 @@ static int __init at91_reset_probe(struct platform_device *pdev) if (!of_device_is_compatible(pdev->dev.of_node, "atmel,sama5d3-rstc")) { /* we need to shutdown the ddr controller, so get ramc base */ - for_each_matching_node(np, at91_ramc_of_match) { + for_each_matching_node_and_match(np, at91_ramc_of_match, &match) { + reset->ramc_lpr = (u32)match->data; reset->ramc_base[idx] = of_iomap(np, 0); if (!reset->ramc_base[idx]) { dev_err(&pdev->dev, "Could not map ram controller address\n"); From fcd0532fac2ac82cec6d7b43298c8ecfc93e1049 Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:37 +0000 Subject: [PATCH 18/26] power: reset: at91-reset: make at91sam9g45_restart() generic Make at91sam9g45_restart() generic. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 4e1961334e4d..61433060d784 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -105,32 +105,23 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, struct at91_reset *reset = container_of(this, struct at91_reset, nb); asm volatile( - /* - * Test wether we have a second RAM controller to care - * about. - * - * First, test that we can dereference the virtual address. - */ - "cmp %1, #0\n\t" - "beq 1f\n\t" - - /* Then, test that the RAM controller is enabled */ - "ldr r4, [%1]\n\t" - "cmp r4, #0\n\t" - /* Align to cache lines */ ".balign 32\n\t" /* Disable SDRAM0 accesses */ - "1: str %3, [%0, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t" + " tst %0, #0\n\t" + " beq 1f\n\t" + " str %3, [%0, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t" /* Power down SDRAM0 */ " str %4, [%0, %6]\n\t" /* Disable SDRAM1 accesses */ + "1: tst %1, #0\n\t" + " beq 2f\n\t" " strne %3, [%1, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t" /* Power down SDRAM1 */ " strne %4, [%1, %6]\n\t" /* Reset CPU */ - " str %5, [%2, #" __stringify(AT91_RSTC_CR) "]\n\t" + "2: str %5, [%2, #" __stringify(AT91_RSTC_CR) "]\n\t" " b .\n\t" : From 51aa7d45f905ca03d3c61d32a09537903a7ea707 Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:38 +0000 Subject: [PATCH 19/26] power: reset: at91-reset: keep only one reset function Keep only one reset function. With this, notifier_call member of struct at91_reset_data could be removed. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 52 ++------------------------------ 1 file changed, 3 insertions(+), 49 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 61433060d784..9c1b69f76a01 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -50,8 +50,6 @@ enum reset_type { }; struct at91_reset_data { - int (*notifier_call)(struct notifier_block *this, unsigned long mode, - void *cmd); u32 args; }; @@ -69,38 +67,8 @@ struct at91_reset { * reset register it can be left driving the data bus and * killing the chance of a subsequent boot from NAND */ -static int at91sam9260_restart(struct notifier_block *this, unsigned long mode, - void *cmd) -{ - struct at91_reset *reset = container_of(this, struct at91_reset, nb); - - asm volatile( - /* Align to cache lines */ - ".balign 32\n\t" - - /* Disable SDRAM accesses */ - "str %2, [%0, #" __stringify(AT91_SDRAMC_TR) "]\n\t" - - /* Power down SDRAM */ - "str %3, [%0, %5]\n\t" - - /* Reset CPU */ - "str %4, [%1, #" __stringify(AT91_RSTC_CR) "]\n\t" - - "b .\n\t" - : - : "r" (reset->ramc_base[0]), - "r" (reset->rstc_base), - "r" (1), - "r" cpu_to_le32(AT91_SDRAMC_LPCB_POWER_DOWN), - "r" (reset->args), - "r" (reset->ramc_lpr)); - - return NOTIFY_DONE; -} - -static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, - void *cmd) +static int at91_reset(struct notifier_block *this, unsigned long mode, + void *cmd) { struct at91_reset *reset = container_of(this, struct at91_reset, nb); @@ -137,16 +105,6 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, return NOTIFY_DONE; } -static int sama5d3_restart(struct notifier_block *this, unsigned long mode, - void *cmd) -{ - struct at91_reset *reset = container_of(this, struct at91_reset, nb); - - writel(reset->args, reset->rstc_base); - - return NOTIFY_DONE; -} - static void __init at91_reset_status(struct platform_device *pdev, void __iomem *base) { @@ -199,22 +157,18 @@ static const struct of_device_id at91_ramc_of_match[] = { }; static const struct at91_reset_data at91sam9260_reset_data = { - .notifier_call = at91sam9260_restart, .args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST, }; static const struct at91_reset_data at91sam9g45_reset_data = { - .notifier_call = at91sam9g45_restart, .args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST, }; static const struct at91_reset_data sama5d3_reset_data = { - .notifier_call = sama5d3_restart, .args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST, }; static const struct at91_reset_data samx7_reset_data = { - .notifier_call = sama5d3_restart, .args = AT91_RSTC_KEY | AT91_RSTC_PROCRST, }; @@ -277,7 +231,7 @@ static int __init at91_reset_probe(struct platform_device *pdev) match = of_match_node(at91_reset_of_match, pdev->dev.of_node); reset_data = match->data; - reset->nb.notifier_call = reset_data->notifier_call; + reset->nb.notifier_call = at91_reset; reset->nb.priority = 192; reset->args = reset_data->args; From 766b0162e613a89a330382e566e29da57f5f0de5 Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:39 +0000 Subject: [PATCH 20/26] power: reset: at91-reset: get rid of at91_reset_data After refactoring struct at91_reset_data and struct at91_reset_data at91sam9260_reset_data are not needed anymore. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 37 ++++++++------------------------ 1 file changed, 9 insertions(+), 28 deletions(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 9c1b69f76a01..537ccb180568 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -49,10 +49,6 @@ enum reset_type { RESET_TYPE_ULP2 = 8, }; -struct at91_reset_data { - u32 args; -}; - struct at91_reset { void __iomem *rstc_base; void __iomem *ramc_base[2]; @@ -156,42 +152,29 @@ static const struct of_device_id at91_ramc_of_match[] = { { /* sentinel */ } }; -static const struct at91_reset_data at91sam9260_reset_data = { - .args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST, -}; - -static const struct at91_reset_data at91sam9g45_reset_data = { - .args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST, -}; - -static const struct at91_reset_data sama5d3_reset_data = { - .args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST, -}; - -static const struct at91_reset_data samx7_reset_data = { - .args = AT91_RSTC_KEY | AT91_RSTC_PROCRST, -}; - static const struct of_device_id at91_reset_of_match[] = { { .compatible = "atmel,at91sam9260-rstc", - .data = &at91sam9260_reset_data + .data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PERRST | + AT91_RSTC_PROCRST), }, { .compatible = "atmel,at91sam9g45-rstc", - .data = &at91sam9g45_reset_data + .data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PERRST | + AT91_RSTC_PROCRST) }, { .compatible = "atmel,sama5d3-rstc", - .data = &sama5d3_reset_data + .data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PERRST | + AT91_RSTC_PROCRST) }, { .compatible = "atmel,samx7-rstc", - .data = &samx7_reset_data + .data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PROCRST) }, { .compatible = "microchip,sam9x60-rstc", - .data = &samx7_reset_data + .data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PROCRST) }, { /* sentinel */ } }; @@ -199,7 +182,6 @@ MODULE_DEVICE_TABLE(of, at91_reset_of_match); static int __init at91_reset_probe(struct platform_device *pdev) { - const struct at91_reset_data *reset_data; const struct of_device_id *match; struct at91_reset *reset; struct device_node *np; @@ -230,10 +212,9 @@ static int __init at91_reset_probe(struct platform_device *pdev) } match = of_match_node(at91_reset_of_match, pdev->dev.of_node); - reset_data = match->data; reset->nb.notifier_call = at91_reset; reset->nb.priority = 192; - reset->args = reset_data->args; + reset->args = (u32)match->data; reset->sclk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(reset->sclk)) From e48bbb52a2aad8613291a9e4e757bbf995769015 Mon Sep 17 00:00:00 2001 From: "Claudiu.Beznea@microchip.com" Date: Tue, 21 Jan 2020 10:03:39 +0000 Subject: [PATCH 21/26] power: reset: at91-reset: handle nrst async for sam9x60 Handle NRST asynchronously for SAM9X60 to avoid problem with fast drop of VDDCORE on shutdown operations in the first 100 us after CPU is shutdown. Signed-off-by: Claudiu Beznea Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 537ccb180568..3ff9d93a5226 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -35,6 +35,7 @@ #define AT91_RSTC_MR 0x08 /* Reset Controller Mode Register */ #define AT91_RSTC_URSTEN BIT(0) /* User Reset Enable */ +#define AT91_RSTC_URSTASYNC BIT(2) /* User Reset Asynchronous Control */ #define AT91_RSTC_URSTIEN BIT(4) /* User Reset Interrupt Enable */ #define AT91_RSTC_ERSTL GENMASK(11, 8) /* External Reset Length */ @@ -228,6 +229,13 @@ static int __init at91_reset_probe(struct platform_device *pdev) platform_set_drvdata(pdev, reset); + if (of_device_is_compatible(pdev->dev.of_node, "microchip,sam9x60-rstc")) { + u32 val = readl(reset->rstc_base + AT91_RSTC_MR); + + writel(AT91_RSTC_KEY | AT91_RSTC_URSTASYNC | val, + reset->rstc_base + AT91_RSTC_MR); + } + ret = register_restart_handler(&reset->nb); if (ret) { clk_disable_unprepare(reset->sclk); From 583b53ece0b0268c542a1eafadb62e3d4b0aab8c Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 9 Mar 2020 00:51:43 +0300 Subject: [PATCH 22/26] power: supply: bq27xxx_battery: Silence deferred-probe error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver fails to probe with -EPROBE_DEFER if battery's power supply (charger driver) isn't ready yet and this results in a bit noisy error message in KMSG during kernel's boot up. Let's silence the harmless error message. Signed-off-by: Dmitry Osipenko Reviewed-by: Andrew F. Davis Reviewed-by: Pali Rohár Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq27xxx_battery.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 195c18c2f426..664e50103eaa 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -1885,7 +1885,10 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di) di->bat = power_supply_register_no_ws(di->dev, psy_desc, &psy_cfg); if (IS_ERR(di->bat)) { - dev_err(di->dev, "failed to register battery\n"); + if (PTR_ERR(di->bat) == -EPROBE_DEFER) + dev_dbg(di->dev, "failed to register battery, deferring probe\n"); + else + dev_err(di->dev, "failed to register battery\n"); return PTR_ERR(di->bat); } From 9027f6111ca40dcc703e1cf6129a73703ae299b7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 11 Mar 2020 10:08:18 +0100 Subject: [PATCH 23/26] power: twl4030: Use scnprintf() for avoiding potential buffer overflow Since snprintf() returns the would-be-output size instead of the actual output size, the succeeding calls may go beyond the given buffer limit. Fix it by replacing with scnprintf(). Signed-off-by: Takashi Iwai Signed-off-by: Sebastian Reichel --- drivers/power/supply/twl4030_charger.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/twl4030_charger.c b/drivers/power/supply/twl4030_charger.c index 648ab80288c9..1bc49b2e12e8 100644 --- a/drivers/power/supply/twl4030_charger.c +++ b/drivers/power/supply/twl4030_charger.c @@ -726,10 +726,10 @@ twl4030_bci_mode_show(struct device *dev, for (i = 0; i < ARRAY_SIZE(modes); i++) if (mode == i) - len += snprintf(buf+len, PAGE_SIZE-len, + len += scnprintf(buf+len, PAGE_SIZE-len, "[%s] ", modes[i]); else - len += snprintf(buf+len, PAGE_SIZE-len, + len += scnprintf(buf+len, PAGE_SIZE-len, "%s ", modes[i]); buf[len-1] = '\n'; return len; From 6cdd5b09cbe67365c42aee539f6fd00f2ecfdaab Mon Sep 17 00:00:00 2001 From: Sherry Zong Date: Mon, 9 Mar 2020 16:18:44 +0800 Subject: [PATCH 24/26] power: reset: sc27xx: Power off the external subsystems' connection When powering off the whole system, we should power off some external subsystems' connection firstly, otherwise some external subsystems will hold some power and result in powering down abnormally. Signed-off-by: Sherry Zong Signed-off-by: Baolin Wang Signed-off-by: Sebastian Reichel --- drivers/power/reset/sc27xx-poweroff.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/power/reset/sc27xx-poweroff.c b/drivers/power/reset/sc27xx-poweroff.c index 29fb08b8faa0..2bedd4c58ddc 100644 --- a/drivers/power/reset/sc27xx-poweroff.c +++ b/drivers/power/reset/sc27xx-poweroff.c @@ -13,6 +13,8 @@ #define SC27XX_PWR_PD_HW 0xc2c #define SC27XX_PWR_OFF_EN BIT(0) +#define SC27XX_SLP_CTRL 0xdf0 +#define SC27XX_LDO_XTL_EN BIT(3) static struct regmap *regmap; @@ -40,6 +42,9 @@ static struct syscore_ops poweroff_syscore_ops = { static void sc27xx_poweroff_do_poweroff(void) { + /* Disable the external subsys connection's power firstly */ + regmap_write(regmap, SC27XX_SLP_CTRL, SC27XX_LDO_XTL_EN); + regmap_write(regmap, SC27XX_PWR_PD_HW, SC27XX_PWR_OFF_EN); } From 274afbc3ad33136962d66447e89d02e3c142a30a Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Mon, 9 Mar 2020 16:18:45 +0800 Subject: [PATCH 25/26] power: reset: sc27xx: Change to use cpu_down() To allow the SC27XX driver can be built as a module, and the freeze_secondary_cpus() symbol is not exported, thus we can change to use the exported cpu_down() API to shut down other cpus to avoid racing, which is same as the freeze_secondary_cpus(). Signed-off-by: Baolin Wang Signed-off-by: Sebastian Reichel --- drivers/power/reset/sc27xx-poweroff.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/power/reset/sc27xx-poweroff.c b/drivers/power/reset/sc27xx-poweroff.c index 2bedd4c58ddc..91b5eceeb810 100644 --- a/drivers/power/reset/sc27xx-poweroff.c +++ b/drivers/power/reset/sc27xx-poweroff.c @@ -29,10 +29,13 @@ static struct regmap *regmap; */ static void sc27xx_poweroff_shutdown(void) { -#ifdef CONFIG_PM_SLEEP_SMP - int cpu = smp_processor_id(); +#ifdef CONFIG_HOTPLUG_CPU + int cpu; - freeze_secondary_cpus(cpu); + for_each_online_cpu(cpu) { + if (cpu != smp_processor_id()) + cpu_down(cpu); + } #endif } From f78c55e3b4806974f7d590b2aab8683232b7bd25 Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Mon, 9 Mar 2020 16:18:46 +0800 Subject: [PATCH 26/26] power: reset: sc27xx: Allow the SC27XX poweroff driver building into a module Change the config to 'tristate' and use module_platform_driver() to allow the SC27XX poweroff driver building into a module, as well as adding some mudule information. Signed-off-by: Baolin Wang Signed-off-by: Sebastian Reichel --- drivers/power/reset/Kconfig | 2 +- drivers/power/reset/sc27xx-poweroff.c | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 513efe8e7628..890380302080 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -248,7 +248,7 @@ config SYSCON_REBOOT_MODE action according to the mode. config POWER_RESET_SC27XX - bool "Spreadtrum SC27xx PMIC power-off driver" + tristate "Spreadtrum SC27xx PMIC power-off driver" depends on MFD_SC27XX_PMIC || COMPILE_TEST help This driver supports powering off a system through diff --git a/drivers/power/reset/sc27xx-poweroff.c b/drivers/power/reset/sc27xx-poweroff.c index 91b5eceeb810..69863074daf6 100644 --- a/drivers/power/reset/sc27xx-poweroff.c +++ b/drivers/power/reset/sc27xx-poweroff.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -71,4 +72,8 @@ static struct platform_driver sc27xx_poweroff_driver = { .name = "sc27xx-poweroff", }, }; -builtin_platform_driver(sc27xx_poweroff_driver); +module_platform_driver(sc27xx_poweroff_driver); + +MODULE_DESCRIPTION("Power off driver for SC27XX PMIC Device"); +MODULE_AUTHOR("Baolin Wang "); +MODULE_LICENSE("GPL v2");