Commit a10c9c71 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull power supply and reset changes from Sebastian Reichel:
 "Core:
   - Nothing

  Drivers:
   - at91-reset: cleanups, proper handling for sam9x60
   - sc27xx, charger-manager: allow building as module
   - sc27xx: add support to read current charge capacity
   - axp288: more quirks for weird hardware
   - misc fixes"

* tag 'for-v5.7' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (26 commits)
  power: reset: sc27xx: Allow the SC27XX poweroff driver building into a module
  power: reset: sc27xx: Change to use cpu_down()
  power: reset: sc27xx: Power off the external subsystems' connection
  power: twl4030: Use scnprintf() for avoiding potential buffer overflow
  power: supply: bq27xxx_battery: Silence deferred-probe error
  power: reset: at91-reset: handle nrst async for sam9x60
  power: reset: at91-reset: get rid of at91_reset_data
  power: reset: at91-reset: keep only one reset function
  power: reset: at91-reset: make at91sam9g45_restart() generic
  power: reset: at91-reset: introduce ramc_lpr to struct at91_reset
  power: reset: at91-reset: use r4 as tmp argument
  power: reset: at91-reset: introduce args member in at91_reset_data
  power: reset: at91-reset: introduce struct at91_reset_data
  power: reset: at91-reset: devm_kzalloc() for at91_reset data structure
  power: reset: at91-reset: pass rstc base address to at91_reset_status()
  power: reset: at91-reset: convert reset in pointer to struct at91_reset
  power: reset: at91-reset: add notifier block to struct at91_reset
  power: reset: at91-reset: add sclk to struct at91_reset
  power: reset: at91-reset: add ramc_base[] to struct at91_reset
  power: reset: at91-reset: introduce struct at91_reset
  ...
parents c48b0722 f78c55e3
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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
+94 −96
Original line number Diff line number Diff line
@@ -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 */

@@ -49,105 +50,63 @@ enum reset_type {
	RESET_TYPE_ULP2		= 8,
};

static void __iomem *at91_ramc_base[2], *at91_rstc_base;
static struct clk *sclk;
struct at91_reset {
	void __iomem *rstc_base;
	void __iomem *ramc_base[2];
	struct clk *sclk;
	struct notifier_block nb;
	u32 args;
	u32 ramc_lpr;
};

/*
* unless the SDRAM is cleanly shutdown before we hit the
* 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,
static int at91_reset(struct notifier_block *this, unsigned long mode,
		      void *cmd)
{
	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, #" __stringify(AT91_SDRAMC_LPR) "]\n\t"

		/* Reset CPU */
		"str	%4, [%1, #" __stringify(AT91_RSTC_CR) "]\n\t"

		"b	.\n\t"
		:
		: "r" (at91_ramc_base[0]),
		  "r" (at91_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));

	return NOTIFY_DONE;
}
	struct at91_reset *reset = container_of(this, struct at91_reset, nb);

static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode,
			       void *cmd)
{
	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	r0, [%1]\n\t"
		"cmp	r0, #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, #" __stringify(AT91_DDRSDRC_LPR) "]\n\t"
		"	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, #" __stringify(AT91_DDRSDRC_LPR) "]\n\t"
		"	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"
		:
		: "r" (at91_ramc_base[0]),
		  "r" (at91_ramc_base[1]),
		  "r" (at91_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)
		: "r0");
		  "r" (reset->args),
		  "r" (reset->ramc_lpr)
		: "r4");

	return NOTIFY_DONE;
}

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);

	return NOTIFY_DONE;
}

static int samx7_restart(struct notifier_block *this, unsigned long mode,
			 void *cmd)
{
	writel(AT91_RSTC_KEY | AT91_RSTC_PROCRST, at91_rstc_base);
	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(at91_rstc_base + AT91_RSTC_SR);
	u32 reg = readl(base + AT91_RSTC_SR);

	switch ((reg & AT91_RSTC_RSTTYP) >> 8) {
	case RESET_TYPE_GENERAL:
@@ -183,42 +142,68 @@ 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 */ }
};

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 = (void *)(AT91_RSTC_KEY | AT91_RSTC_PERRST |
				 AT91_RSTC_PROCRST),
	},
	{
		.compatible = "atmel,at91sam9g45-rstc",
		.data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PERRST |
				 AT91_RSTC_PROCRST)
	},
	{
		.compatible = "atmel,sama5d3-rstc",
		.data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PERRST |
				 AT91_RSTC_PROCRST)
	},
	{
		.compatible = "atmel,samx7-rstc",
		.data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PROCRST)
	},
	{
		.compatible = "microchip,sam9x60-rstc",
		.data = (void *)(AT91_RSTC_KEY | AT91_RSTC_PROCRST)
	},
	{ /* sentinel */ }
};
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;
	struct at91_reset *reset;
	struct device_node *np;
	int ret, idx = 0;

	at91_rstc_base = of_iomap(pdev->dev.of_node, 0);
	if (!at91_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;
	}

	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]) {
		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");
				of_node_put(np);
				return -ENODEV;
@@ -228,33 +213,46 @@ 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 = at91_reset;
	reset->nb.priority = 192;
	reset->args = (u32)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;
	}

	ret = register_restart_handler(&at91_restart_nb);
	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(sclk);
		clk_disable_unprepare(reset->sclk);
		return ret;
	}

	at91_reset_status(pdev);
	at91_reset_status(pdev, reset->rstc_base);

	return 0;
}

static int __exit at91_reset_remove(struct platform_device *pdev)
{
	unregister_restart_handler(&at91_restart_nb);
	clk_disable_unprepare(sclk);
	struct at91_reset *reset = platform_get_drvdata(pdev);

	unregister_restart_handler(&reset->nb);
	clk_disable_unprepare(reset->sclk);

	return 0;
}
+17 −4
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@

#include <linux/cpu.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/regmap.h>
@@ -13,6 +14,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;

@@ -27,10 +30,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())
			remove_cpu(cpu);
	}
#endif
}

@@ -40,6 +46,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);
}

@@ -63,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 <baolin.wang@unisoc.com>");
MODULE_LICENSE("GPL v2");
+1 −1
Original line number Diff line number Diff line
@@ -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
+19 −16
Original line number Diff line number Diff line
@@ -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.
	 */

@@ -1383,9 +1383,9 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger,
		 * 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
@@ -1556,9 +1556,9 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger,
		 * 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
Loading