mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-21 06:33:41 +00:00
generic: 6.1: backport AXP PMIC support
Backport AXP15060, AXP313a and AXP192 support. The AXP15060 PMIC is used for starfive boards, and the AXP313a PMIC is used for sunxi boards. Remove conflicting patches from starfive target. Signed-off-by: Chukun Pan <amadeus@jmu.edu.cn>
This commit is contained in:
parent
9a19ec79f9
commit
85b156c113
@ -0,0 +1,80 @@
|
||||
From 8781ba7f45695af3ab8e8d1b55a31f527c9201a3 Mon Sep 17 00:00:00 2001
|
||||
From: Aren Moynihan <aren@peacevolution.org>
|
||||
Date: Thu, 8 Dec 2022 17:02:26 -0500
|
||||
Subject: [PATCH] mfd: axp20x: Fix order of pek rise and fall events
|
||||
|
||||
The power button can get "stuck" if the rising edge and falling edge irq
|
||||
are read in the same pass. This can often be triggered when resuming
|
||||
from suspend if the power button is released before the kernel handles
|
||||
the interrupt.
|
||||
|
||||
Swapping the order of the rise and fall events makes sure that the press
|
||||
event is handled first, which prevents this situation.
|
||||
|
||||
Signed-off-by: Aren Moynihan <aren@peacevolution.org>
|
||||
Reviewed-by: Samuel Holland <samuel@sholland.org>
|
||||
Tested-by: Samuel Holland <samuel@sholland.org>
|
||||
Acked-by: Chen-Yu Tsai <wens@csie.org>
|
||||
Signed-off-by: Lee Jones <lee@kernel.org>
|
||||
Link: https://lore.kernel.org/r/20221208220225.635414-1-aren@peacevolution.org
|
||||
---
|
||||
include/linux/mfd/axp20x.h | 15 ++++++++++-----
|
||||
1 file changed, 10 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/include/linux/mfd/axp20x.h
|
||||
+++ b/include/linux/mfd/axp20x.h
|
||||
@@ -432,8 +432,9 @@ enum {
|
||||
AXP152_IRQ_PEK_SHORT,
|
||||
AXP152_IRQ_PEK_LONG,
|
||||
AXP152_IRQ_TIMER,
|
||||
- AXP152_IRQ_PEK_RIS_EDGE,
|
||||
+ /* out of bit order to make sure the press event is handled first */
|
||||
AXP152_IRQ_PEK_FAL_EDGE,
|
||||
+ AXP152_IRQ_PEK_RIS_EDGE,
|
||||
AXP152_IRQ_GPIO3_INPUT,
|
||||
AXP152_IRQ_GPIO2_INPUT,
|
||||
AXP152_IRQ_GPIO1_INPUT,
|
||||
@@ -472,8 +473,9 @@ enum {
|
||||
AXP20X_IRQ_LOW_PWR_LVL1,
|
||||
AXP20X_IRQ_LOW_PWR_LVL2,
|
||||
AXP20X_IRQ_TIMER,
|
||||
- AXP20X_IRQ_PEK_RIS_EDGE,
|
||||
+ /* out of bit order to make sure the press event is handled first */
|
||||
AXP20X_IRQ_PEK_FAL_EDGE,
|
||||
+ AXP20X_IRQ_PEK_RIS_EDGE,
|
||||
AXP20X_IRQ_GPIO3_INPUT,
|
||||
AXP20X_IRQ_GPIO2_INPUT,
|
||||
AXP20X_IRQ_GPIO1_INPUT,
|
||||
@@ -502,8 +504,9 @@ enum axp22x_irqs {
|
||||
AXP22X_IRQ_LOW_PWR_LVL1,
|
||||
AXP22X_IRQ_LOW_PWR_LVL2,
|
||||
AXP22X_IRQ_TIMER,
|
||||
- AXP22X_IRQ_PEK_RIS_EDGE,
|
||||
+ /* out of bit order to make sure the press event is handled first */
|
||||
AXP22X_IRQ_PEK_FAL_EDGE,
|
||||
+ AXP22X_IRQ_PEK_RIS_EDGE,
|
||||
AXP22X_IRQ_GPIO1_INPUT,
|
||||
AXP22X_IRQ_GPIO0_INPUT,
|
||||
};
|
||||
@@ -571,8 +574,9 @@ enum axp803_irqs {
|
||||
AXP803_IRQ_LOW_PWR_LVL1,
|
||||
AXP803_IRQ_LOW_PWR_LVL2,
|
||||
AXP803_IRQ_TIMER,
|
||||
- AXP803_IRQ_PEK_RIS_EDGE,
|
||||
+ /* out of bit order to make sure the press event is handled first */
|
||||
AXP803_IRQ_PEK_FAL_EDGE,
|
||||
+ AXP803_IRQ_PEK_RIS_EDGE,
|
||||
AXP803_IRQ_PEK_SHORT,
|
||||
AXP803_IRQ_PEK_LONG,
|
||||
AXP803_IRQ_PEK_OVER_OFF,
|
||||
@@ -623,8 +627,9 @@ enum axp809_irqs {
|
||||
AXP809_IRQ_LOW_PWR_LVL1,
|
||||
AXP809_IRQ_LOW_PWR_LVL2,
|
||||
AXP809_IRQ_TIMER,
|
||||
- AXP809_IRQ_PEK_RIS_EDGE,
|
||||
+ /* out of bit order to make sure the press event is handled first */
|
||||
AXP809_IRQ_PEK_FAL_EDGE,
|
||||
+ AXP809_IRQ_PEK_RIS_EDGE,
|
||||
AXP809_IRQ_PEK_SHORT,
|
||||
AXP809_IRQ_PEK_LONG,
|
||||
AXP809_IRQ_PEK_OVER_OFF,
|
@ -0,0 +1,82 @@
|
||||
From 1b1305e95e85624f538ec56db9acf88e2d3d7397 Mon Sep 17 00:00:00 2001
|
||||
From: Samuel Holland <samuel@sholland.org>
|
||||
Date: Wed, 28 Dec 2022 10:27:52 -0600
|
||||
Subject: [PATCH] mfd: axp20x: Switch to the sys-off handler API
|
||||
|
||||
This removes a layer of indirection through pm_power_off() and allows
|
||||
the PMIC handler to be used as a fallback when firmware power off fails.
|
||||
This happens on boards like the Clockwork DevTerm R-01 where OpenSBI
|
||||
does not know how to use the PMIC to power off the board.
|
||||
|
||||
Move the check for AXP288 to avoid registering a dummy handler.
|
||||
|
||||
Signed-off-by: Samuel Holland <samuel@sholland.org>
|
||||
[Lee: Removed superfluous new line]
|
||||
Signed-off-by: Lee Jones <lee@kernel.org>
|
||||
Link: https://lore.kernel.org/r/20221228162752.14204-1-samuel@sholland.org
|
||||
---
|
||||
drivers/mfd/axp20x.c | 27 +++++++++++----------------
|
||||
1 file changed, 11 insertions(+), 16 deletions(-)
|
||||
|
||||
--- a/drivers/mfd/axp20x.c
|
||||
+++ b/drivers/mfd/axp20x.c
|
||||
@@ -23,7 +23,7 @@
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
-#include <linux/pm_runtime.h>
|
||||
+#include <linux/reboot.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
@@ -832,17 +832,16 @@ static const struct mfd_cell axp813_cell
|
||||
},
|
||||
};
|
||||
|
||||
-static struct axp20x_dev *axp20x_pm_power_off;
|
||||
-static void axp20x_power_off(void)
|
||||
+static int axp20x_power_off(struct sys_off_data *data)
|
||||
{
|
||||
- if (axp20x_pm_power_off->variant == AXP288_ID)
|
||||
- return;
|
||||
+ struct axp20x_dev *axp20x = data->cb_data;
|
||||
|
||||
- regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL,
|
||||
- AXP20X_OFF);
|
||||
+ regmap_write(axp20x->regmap, AXP20X_OFF_CTRL, AXP20X_OFF);
|
||||
|
||||
/* Give capacitors etc. time to drain to avoid kernel panic msg. */
|
||||
mdelay(500);
|
||||
+
|
||||
+ return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
int axp20x_match_device(struct axp20x_dev *axp20x)
|
||||
@@ -1009,10 +1008,11 @@ int axp20x_device_probe(struct axp20x_de
|
||||
return ret;
|
||||
}
|
||||
|
||||
- if (!pm_power_off) {
|
||||
- axp20x_pm_power_off = axp20x;
|
||||
- pm_power_off = axp20x_power_off;
|
||||
- }
|
||||
+ if (axp20x->variant != AXP288_ID)
|
||||
+ devm_register_sys_off_handler(axp20x->dev,
|
||||
+ SYS_OFF_MODE_POWER_OFF,
|
||||
+ SYS_OFF_PRIO_DEFAULT,
|
||||
+ axp20x_power_off, axp20x);
|
||||
|
||||
dev_info(axp20x->dev, "AXP20X driver loaded\n");
|
||||
|
||||
@@ -1022,11 +1022,6 @@ EXPORT_SYMBOL(axp20x_device_probe);
|
||||
|
||||
void axp20x_device_remove(struct axp20x_dev *axp20x)
|
||||
{
|
||||
- if (axp20x == axp20x_pm_power_off) {
|
||||
- axp20x_pm_power_off = NULL;
|
||||
- pm_power_off = NULL;
|
||||
- }
|
||||
-
|
||||
mfd_remove_devices(axp20x->dev);
|
||||
regmap_del_irq_chip(axp20x->irq, axp20x->regmap_irqc);
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
From 2405fbfb384ef39e9560d76d3f6e4c90519f90aa Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Wed, 29 Mar 2023 22:55:44 +0200
|
||||
Subject: [PATCH] mfd: axp20x: Fix axp288 writable-ranges
|
||||
|
||||
Register AXP288_POWER_REASON is writable and needs to be written
|
||||
to reset the reset- / power-on-reason bits.
|
||||
|
||||
Add it to the axp288 writable-ranges so that the extcon-axp288
|
||||
driver can properly clear the reset- / power-on-reason bits.
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
Signed-off-by: Lee Jones <lee@kernel.org>
|
||||
Link: https://lore.kernel.org/r/20230329205544.1051393-1-hdegoede@redhat.com
|
||||
---
|
||||
drivers/mfd/axp20x.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/mfd/axp20x.c
|
||||
+++ b/drivers/mfd/axp20x.c
|
||||
@@ -119,6 +119,7 @@ static const struct regmap_access_table
|
||||
|
||||
/* AXP288 ranges are shared with the AXP803, as they cover the same range */
|
||||
static const struct regmap_range axp288_writeable_ranges[] = {
|
||||
+ regmap_reg_range(AXP288_POWER_REASON, AXP288_POWER_REASON),
|
||||
regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ6_STATE),
|
||||
regmap_reg_range(AXP20X_DCDC_MODE, AXP288_FG_TUNE5),
|
||||
};
|
@ -0,0 +1,343 @@
|
||||
From e0f8ad2a705367518b5c56bf9d6da89681467c02 Mon Sep 17 00:00:00 2001
|
||||
From: Shengyu Qu <wiagn233@outlook.com>
|
||||
Date: Fri, 21 Apr 2023 23:08:15 +0800
|
||||
Subject: [PATCH] mfd: axp20x: Add support for AXP15060 PMIC
|
||||
|
||||
The AXP15060 is a PMIC chip produced by X-Powers, and could be connected
|
||||
via an I2C bus.
|
||||
|
||||
Describe the regmap and the MFD bits, along with the registers exposed
|
||||
via I2C. Eventually advertise the device using a new compatible string
|
||||
and add support for power off the system.
|
||||
|
||||
The driver would disable PEK function if IRQ is not configured in device
|
||||
tree, since some boards (For example, Starfive Visionfive 2) didn't
|
||||
connect IRQ line of PMIC to SOC.
|
||||
|
||||
GPIO function isn't enabled in this commit, since its configuration
|
||||
operation is different from any existing AXP PMICs and needs
|
||||
logic modification on existing driver. GPIO support might come in later
|
||||
patches.
|
||||
|
||||
Signed-off-by: Shengyu Qu <wiagn233@outlook.com>
|
||||
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
|
||||
Signed-off-by: Lee Jones <lee@kernel.org>
|
||||
Link: https://lore.kernel.org/r/TY3P286MB261162D57695AC8164ED50E298609@TY3P286MB2611.JPNP286.PROD.OUTLOOK.COM
|
||||
---
|
||||
drivers/mfd/axp20x-i2c.c | 2 +
|
||||
drivers/mfd/axp20x.c | 107 +++++++++++++++++++++++++++++++++++++
|
||||
include/linux/mfd/axp20x.h | 85 +++++++++++++++++++++++++++++
|
||||
3 files changed, 194 insertions(+)
|
||||
|
||||
--- a/drivers/mfd/axp20x-i2c.c
|
||||
+++ b/drivers/mfd/axp20x-i2c.c
|
||||
@@ -66,6 +66,7 @@ static const struct of_device_id axp20x_
|
||||
{ .compatible = "x-powers,axp223", .data = (void *)AXP223_ID },
|
||||
{ .compatible = "x-powers,axp803", .data = (void *)AXP803_ID },
|
||||
{ .compatible = "x-powers,axp806", .data = (void *)AXP806_ID },
|
||||
+ { .compatible = "x-powers,axp15060", .data = (void *)AXP15060_ID },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, axp20x_i2c_of_match);
|
||||
@@ -79,6 +80,7 @@ static const struct i2c_device_id axp20x
|
||||
{ "axp223", 0 },
|
||||
{ "axp803", 0 },
|
||||
{ "axp806", 0 },
|
||||
+ { "axp15060", 0 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
|
||||
--- a/drivers/mfd/axp20x.c
|
||||
+++ b/drivers/mfd/axp20x.c
|
||||
@@ -43,6 +43,7 @@ static const char * const axp20x_model_n
|
||||
"AXP806",
|
||||
"AXP809",
|
||||
"AXP813",
|
||||
+ "AXP15060",
|
||||
};
|
||||
|
||||
static const struct regmap_range axp152_writeable_ranges[] = {
|
||||
@@ -169,6 +170,31 @@ static const struct regmap_access_table
|
||||
.n_yes_ranges = ARRAY_SIZE(axp806_volatile_ranges),
|
||||
};
|
||||
|
||||
+static const struct regmap_range axp15060_writeable_ranges[] = {
|
||||
+ regmap_reg_range(AXP15060_PWR_OUT_CTRL1, AXP15060_DCDC_MODE_CTRL2),
|
||||
+ regmap_reg_range(AXP15060_OUTPUT_MONITOR_DISCHARGE, AXP15060_CPUSLDO_V_CTRL),
|
||||
+ regmap_reg_range(AXP15060_PWR_WAKEUP_CTRL, AXP15060_PWR_DISABLE_DOWN_SEQ),
|
||||
+ regmap_reg_range(AXP15060_PEK_KEY, AXP15060_PEK_KEY),
|
||||
+ regmap_reg_range(AXP15060_IRQ1_EN, AXP15060_IRQ2_EN),
|
||||
+ regmap_reg_range(AXP15060_IRQ1_STATE, AXP15060_IRQ2_STATE),
|
||||
+};
|
||||
+
|
||||
+static const struct regmap_range axp15060_volatile_ranges[] = {
|
||||
+ regmap_reg_range(AXP15060_STARTUP_SRC, AXP15060_STARTUP_SRC),
|
||||
+ regmap_reg_range(AXP15060_PWR_WAKEUP_CTRL, AXP15060_PWR_DISABLE_DOWN_SEQ),
|
||||
+ regmap_reg_range(AXP15060_IRQ1_STATE, AXP15060_IRQ2_STATE),
|
||||
+};
|
||||
+
|
||||
+static const struct regmap_access_table axp15060_writeable_table = {
|
||||
+ .yes_ranges = axp15060_writeable_ranges,
|
||||
+ .n_yes_ranges = ARRAY_SIZE(axp15060_writeable_ranges),
|
||||
+};
|
||||
+
|
||||
+static const struct regmap_access_table axp15060_volatile_table = {
|
||||
+ .yes_ranges = axp15060_volatile_ranges,
|
||||
+ .n_yes_ranges = ARRAY_SIZE(axp15060_volatile_ranges),
|
||||
+};
|
||||
+
|
||||
static const struct resource axp152_pek_resources[] = {
|
||||
DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_RIS_EDGE, "PEK_DBR"),
|
||||
DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_FAL_EDGE, "PEK_DBF"),
|
||||
@@ -237,6 +263,11 @@ static const struct resource axp809_pek_
|
||||
DEFINE_RES_IRQ_NAMED(AXP809_IRQ_PEK_FAL_EDGE, "PEK_DBF"),
|
||||
};
|
||||
|
||||
+static const struct resource axp15060_pek_resources[] = {
|
||||
+ DEFINE_RES_IRQ_NAMED(AXP15060_IRQ_PEK_RIS_EDGE, "PEK_DBR"),
|
||||
+ DEFINE_RES_IRQ_NAMED(AXP15060_IRQ_PEK_FAL_EDGE, "PEK_DBF"),
|
||||
+};
|
||||
+
|
||||
static const struct regmap_config axp152_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
@@ -282,6 +313,15 @@ static const struct regmap_config axp806
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
+static const struct regmap_config axp15060_regmap_config = {
|
||||
+ .reg_bits = 8,
|
||||
+ .val_bits = 8,
|
||||
+ .wr_table = &axp15060_writeable_table,
|
||||
+ .volatile_table = &axp15060_volatile_table,
|
||||
+ .max_register = AXP15060_IRQ2_STATE,
|
||||
+ .cache_type = REGCACHE_RBTREE,
|
||||
+};
|
||||
+
|
||||
#define INIT_REGMAP_IRQ(_variant, _irq, _off, _mask) \
|
||||
[_variant##_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
|
||||
|
||||
@@ -503,6 +543,23 @@ static const struct regmap_irq axp809_re
|
||||
INIT_REGMAP_IRQ(AXP809, GPIO0_INPUT, 4, 0),
|
||||
};
|
||||
|
||||
+static const struct regmap_irq axp15060_regmap_irqs[] = {
|
||||
+ INIT_REGMAP_IRQ(AXP15060, DIE_TEMP_HIGH_LV1, 0, 0),
|
||||
+ INIT_REGMAP_IRQ(AXP15060, DIE_TEMP_HIGH_LV2, 0, 1),
|
||||
+ INIT_REGMAP_IRQ(AXP15060, DCDC1_V_LOW, 0, 2),
|
||||
+ INIT_REGMAP_IRQ(AXP15060, DCDC2_V_LOW, 0, 3),
|
||||
+ INIT_REGMAP_IRQ(AXP15060, DCDC3_V_LOW, 0, 4),
|
||||
+ INIT_REGMAP_IRQ(AXP15060, DCDC4_V_LOW, 0, 5),
|
||||
+ INIT_REGMAP_IRQ(AXP15060, DCDC5_V_LOW, 0, 6),
|
||||
+ INIT_REGMAP_IRQ(AXP15060, DCDC6_V_LOW, 0, 7),
|
||||
+ INIT_REGMAP_IRQ(AXP15060, PEK_LONG, 1, 0),
|
||||
+ INIT_REGMAP_IRQ(AXP15060, PEK_SHORT, 1, 1),
|
||||
+ INIT_REGMAP_IRQ(AXP15060, GPIO1_INPUT, 1, 2),
|
||||
+ INIT_REGMAP_IRQ(AXP15060, PEK_FAL_EDGE, 1, 3),
|
||||
+ INIT_REGMAP_IRQ(AXP15060, PEK_RIS_EDGE, 1, 4),
|
||||
+ INIT_REGMAP_IRQ(AXP15060, GPIO2_INPUT, 1, 5),
|
||||
+};
|
||||
+
|
||||
static const struct regmap_irq_chip axp152_regmap_irq_chip = {
|
||||
.name = "axp152_irq_chip",
|
||||
.status_base = AXP152_IRQ1_STATE,
|
||||
@@ -589,6 +646,17 @@ static const struct regmap_irq_chip axp8
|
||||
.num_regs = 5,
|
||||
};
|
||||
|
||||
+static const struct regmap_irq_chip axp15060_regmap_irq_chip = {
|
||||
+ .name = "axp15060",
|
||||
+ .status_base = AXP15060_IRQ1_STATE,
|
||||
+ .ack_base = AXP15060_IRQ1_STATE,
|
||||
+ .unmask_base = AXP15060_IRQ1_EN,
|
||||
+ .init_ack_masked = true,
|
||||
+ .irqs = axp15060_regmap_irqs,
|
||||
+ .num_irqs = ARRAY_SIZE(axp15060_regmap_irqs),
|
||||
+ .num_regs = 2,
|
||||
+};
|
||||
+
|
||||
static const struct mfd_cell axp20x_cells[] = {
|
||||
{
|
||||
.name = "axp20x-gpio",
|
||||
@@ -833,6 +901,23 @@ static const struct mfd_cell axp813_cell
|
||||
},
|
||||
};
|
||||
|
||||
+static const struct mfd_cell axp15060_cells[] = {
|
||||
+ {
|
||||
+ .name = "axp221-pek",
|
||||
+ .num_resources = ARRAY_SIZE(axp15060_pek_resources),
|
||||
+ .resources = axp15060_pek_resources,
|
||||
+ }, {
|
||||
+ .name = "axp20x-regulator",
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+/* For boards that don't have IRQ line connected to SOC. */
|
||||
+static const struct mfd_cell axp_regulator_only_cells[] = {
|
||||
+ {
|
||||
+ .name = "axp20x-regulator",
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
static int axp20x_power_off(struct sys_off_data *data)
|
||||
{
|
||||
struct axp20x_dev *axp20x = data->cb_data;
|
||||
@@ -942,6 +1027,28 @@ int axp20x_match_device(struct axp20x_de
|
||||
*/
|
||||
axp20x->regmap_irq_chip = &axp803_regmap_irq_chip;
|
||||
break;
|
||||
+ case AXP15060_ID:
|
||||
+ /*
|
||||
+ * Don't register the power key part if there is no interrupt
|
||||
+ * line.
|
||||
+ *
|
||||
+ * Since most use cases of AXP PMICs are Allwinner SOCs, board
|
||||
+ * designers follow Allwinner's reference design and connects
|
||||
+ * IRQ line to SOC, there's no need for those variants to deal
|
||||
+ * with cases that IRQ isn't connected. However, AXP15660 is
|
||||
+ * used by some other vendors' SOCs that didn't connect IRQ
|
||||
+ * line, we need to deal with this case.
|
||||
+ */
|
||||
+ if (axp20x->irq > 0) {
|
||||
+ axp20x->nr_cells = ARRAY_SIZE(axp15060_cells);
|
||||
+ axp20x->cells = axp15060_cells;
|
||||
+ } else {
|
||||
+ axp20x->nr_cells = ARRAY_SIZE(axp_regulator_only_cells);
|
||||
+ axp20x->cells = axp_regulator_only_cells;
|
||||
+ }
|
||||
+ axp20x->regmap_cfg = &axp15060_regmap_config;
|
||||
+ axp20x->regmap_irq_chip = &axp15060_regmap_irq_chip;
|
||||
+ break;
|
||||
default:
|
||||
dev_err(dev, "unsupported AXP20X ID %lu\n", axp20x->variant);
|
||||
return -EINVAL;
|
||||
--- a/include/linux/mfd/axp20x.h
|
||||
+++ b/include/linux/mfd/axp20x.h
|
||||
@@ -21,6 +21,7 @@ enum axp20x_variants {
|
||||
AXP806_ID,
|
||||
AXP809_ID,
|
||||
AXP813_ID,
|
||||
+ AXP15060_ID,
|
||||
NR_AXP20X_VARIANTS,
|
||||
};
|
||||
|
||||
@@ -131,6 +132,39 @@ enum axp20x_variants {
|
||||
/* Other DCDC regulator control registers are the same as AXP803 */
|
||||
#define AXP813_DCDC7_V_OUT 0x26
|
||||
|
||||
+#define AXP15060_STARTUP_SRC 0x00
|
||||
+#define AXP15060_PWR_OUT_CTRL1 0x10
|
||||
+#define AXP15060_PWR_OUT_CTRL2 0x11
|
||||
+#define AXP15060_PWR_OUT_CTRL3 0x12
|
||||
+#define AXP15060_DCDC1_V_CTRL 0x13
|
||||
+#define AXP15060_DCDC2_V_CTRL 0x14
|
||||
+#define AXP15060_DCDC3_V_CTRL 0x15
|
||||
+#define AXP15060_DCDC4_V_CTRL 0x16
|
||||
+#define AXP15060_DCDC5_V_CTRL 0x17
|
||||
+#define AXP15060_DCDC6_V_CTRL 0x18
|
||||
+#define AXP15060_ALDO1_V_CTRL 0x19
|
||||
+#define AXP15060_DCDC_MODE_CTRL1 0x1a
|
||||
+#define AXP15060_DCDC_MODE_CTRL2 0x1b
|
||||
+#define AXP15060_OUTPUT_MONITOR_DISCHARGE 0x1e
|
||||
+#define AXP15060_IRQ_PWROK_VOFF 0x1f
|
||||
+#define AXP15060_ALDO2_V_CTRL 0x20
|
||||
+#define AXP15060_ALDO3_V_CTRL 0x21
|
||||
+#define AXP15060_ALDO4_V_CTRL 0x22
|
||||
+#define AXP15060_ALDO5_V_CTRL 0x23
|
||||
+#define AXP15060_BLDO1_V_CTRL 0x24
|
||||
+#define AXP15060_BLDO2_V_CTRL 0x25
|
||||
+#define AXP15060_BLDO3_V_CTRL 0x26
|
||||
+#define AXP15060_BLDO4_V_CTRL 0x27
|
||||
+#define AXP15060_BLDO5_V_CTRL 0x28
|
||||
+#define AXP15060_CLDO1_V_CTRL 0x29
|
||||
+#define AXP15060_CLDO2_V_CTRL 0x2a
|
||||
+#define AXP15060_CLDO3_V_CTRL 0x2b
|
||||
+#define AXP15060_CLDO4_V_CTRL 0x2d
|
||||
+#define AXP15060_CPUSLDO_V_CTRL 0x2e
|
||||
+#define AXP15060_PWR_WAKEUP_CTRL 0x31
|
||||
+#define AXP15060_PWR_DISABLE_DOWN_SEQ 0x32
|
||||
+#define AXP15060_PEK_KEY 0x36
|
||||
+
|
||||
/* Interrupt */
|
||||
#define AXP152_IRQ1_EN 0x40
|
||||
#define AXP152_IRQ2_EN 0x41
|
||||
@@ -152,6 +186,11 @@ enum axp20x_variants {
|
||||
#define AXP20X_IRQ5_STATE 0x4c
|
||||
#define AXP20X_IRQ6_STATE 0x4d
|
||||
|
||||
+#define AXP15060_IRQ1_EN 0x40
|
||||
+#define AXP15060_IRQ2_EN 0x41
|
||||
+#define AXP15060_IRQ1_STATE 0x48
|
||||
+#define AXP15060_IRQ2_STATE 0x49
|
||||
+
|
||||
/* ADC */
|
||||
#define AXP20X_ACIN_V_ADC_H 0x56
|
||||
#define AXP20X_ACIN_V_ADC_L 0x57
|
||||
@@ -222,6 +261,8 @@ enum axp20x_variants {
|
||||
#define AXP22X_GPIO_STATE 0x94
|
||||
#define AXP22X_GPIO_PULL_DOWN 0x95
|
||||
|
||||
+#define AXP15060_CLDO4_GPIO2_MODESET 0x2c
|
||||
+
|
||||
/* Battery */
|
||||
#define AXP20X_CHRG_CC_31_24 0xb0
|
||||
#define AXP20X_CHRG_CC_23_16 0xb1
|
||||
@@ -419,6 +460,33 @@ enum {
|
||||
AXP813_REG_ID_MAX,
|
||||
};
|
||||
|
||||
+enum {
|
||||
+ AXP15060_DCDC1 = 0,
|
||||
+ AXP15060_DCDC2,
|
||||
+ AXP15060_DCDC3,
|
||||
+ AXP15060_DCDC4,
|
||||
+ AXP15060_DCDC5,
|
||||
+ AXP15060_DCDC6,
|
||||
+ AXP15060_ALDO1,
|
||||
+ AXP15060_ALDO2,
|
||||
+ AXP15060_ALDO3,
|
||||
+ AXP15060_ALDO4,
|
||||
+ AXP15060_ALDO5,
|
||||
+ AXP15060_BLDO1,
|
||||
+ AXP15060_BLDO2,
|
||||
+ AXP15060_BLDO3,
|
||||
+ AXP15060_BLDO4,
|
||||
+ AXP15060_BLDO5,
|
||||
+ AXP15060_CLDO1,
|
||||
+ AXP15060_CLDO2,
|
||||
+ AXP15060_CLDO3,
|
||||
+ AXP15060_CLDO4,
|
||||
+ AXP15060_CPUSLDO,
|
||||
+ AXP15060_SW,
|
||||
+ AXP15060_RTC_LDO,
|
||||
+ AXP15060_REG_ID_MAX,
|
||||
+};
|
||||
+
|
||||
/* IRQs */
|
||||
enum {
|
||||
AXP152_IRQ_LDO0IN_CONNECT = 1,
|
||||
@@ -637,6 +705,23 @@ enum axp809_irqs {
|
||||
AXP809_IRQ_GPIO0_INPUT,
|
||||
};
|
||||
|
||||
+enum axp15060_irqs {
|
||||
+ AXP15060_IRQ_DIE_TEMP_HIGH_LV1 = 1,
|
||||
+ AXP15060_IRQ_DIE_TEMP_HIGH_LV2,
|
||||
+ AXP15060_IRQ_DCDC1_V_LOW,
|
||||
+ AXP15060_IRQ_DCDC2_V_LOW,
|
||||
+ AXP15060_IRQ_DCDC3_V_LOW,
|
||||
+ AXP15060_IRQ_DCDC4_V_LOW,
|
||||
+ AXP15060_IRQ_DCDC5_V_LOW,
|
||||
+ AXP15060_IRQ_DCDC6_V_LOW,
|
||||
+ AXP15060_IRQ_PEK_LONG,
|
||||
+ AXP15060_IRQ_PEK_SHORT,
|
||||
+ AXP15060_IRQ_GPIO1_INPUT,
|
||||
+ AXP15060_IRQ_PEK_FAL_EDGE,
|
||||
+ AXP15060_IRQ_PEK_RIS_EDGE,
|
||||
+ AXP15060_IRQ_GPIO2_INPUT,
|
||||
+};
|
||||
+
|
||||
struct axp20x_dev {
|
||||
struct device *dev;
|
||||
int irq;
|
@ -0,0 +1,256 @@
|
||||
From 75c8cb2f4cb218aaf4ea68cab08d6dbc96eeae15 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Botka <martin.botka@somainline.org>
|
||||
Date: Wed, 24 May 2023 01:00:10 +0100
|
||||
Subject: [PATCH] mfd: axp20x: Add support for AXP313a PMIC
|
||||
|
||||
The AXP313a is a PMIC chip produced by X-Powers, it can be connected via
|
||||
an I2C bus.
|
||||
The name AXP1530 seems to appear as well, and this is what is used in
|
||||
the BSP driver. From all we know it's the same chip, just a different
|
||||
name. However we have only seen AXP313a chips in the wild, so go with
|
||||
this name.
|
||||
|
||||
Compared to the other AXP PMICs it's a rather simple affair: just three
|
||||
DCDC converters, three LDOs, and no battery charging support.
|
||||
|
||||
Describe the regmap and the MFD bits, along with the registers exposed
|
||||
via I2C. Aside from the various regulators, also describe the power key
|
||||
interrupts, and adjust the shutdown handler routine to use a different
|
||||
register than the other PMICs.
|
||||
Eventually advertise the device using the new compatible string.
|
||||
|
||||
Signed-off-by: Martin Botka <martin.botka@somainline.org>
|
||||
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
|
||||
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
|
||||
Link: https://lore.kernel.org/r/20230524000012.15028-2-andre.przywara@arm.com
|
||||
Signed-off-by: Lee Jones <lee@kernel.org>
|
||||
---
|
||||
drivers/mfd/axp20x-i2c.c | 2 +
|
||||
drivers/mfd/axp20x.c | 78 +++++++++++++++++++++++++++++++++++++-
|
||||
include/linux/mfd/axp20x.h | 32 ++++++++++++++++
|
||||
3 files changed, 111 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/mfd/axp20x-i2c.c
|
||||
+++ b/drivers/mfd/axp20x-i2c.c
|
||||
@@ -64,6 +64,7 @@ static const struct of_device_id axp20x_
|
||||
{ .compatible = "x-powers,axp209", .data = (void *)AXP209_ID },
|
||||
{ .compatible = "x-powers,axp221", .data = (void *)AXP221_ID },
|
||||
{ .compatible = "x-powers,axp223", .data = (void *)AXP223_ID },
|
||||
+ { .compatible = "x-powers,axp313a", .data = (void *)AXP313A_ID },
|
||||
{ .compatible = "x-powers,axp803", .data = (void *)AXP803_ID },
|
||||
{ .compatible = "x-powers,axp806", .data = (void *)AXP806_ID },
|
||||
{ .compatible = "x-powers,axp15060", .data = (void *)AXP15060_ID },
|
||||
@@ -78,6 +79,7 @@ static const struct i2c_device_id axp20x
|
||||
{ "axp209", 0 },
|
||||
{ "axp221", 0 },
|
||||
{ "axp223", 0 },
|
||||
+ { "axp313a", 0 },
|
||||
{ "axp803", 0 },
|
||||
{ "axp806", 0 },
|
||||
{ "axp15060", 0 },
|
||||
--- a/drivers/mfd/axp20x.c
|
||||
+++ b/drivers/mfd/axp20x.c
|
||||
@@ -39,6 +39,7 @@ static const char * const axp20x_model_n
|
||||
"AXP221",
|
||||
"AXP223",
|
||||
"AXP288",
|
||||
+ "AXP313a",
|
||||
"AXP803",
|
||||
"AXP806",
|
||||
"AXP809",
|
||||
@@ -156,6 +157,25 @@ static const struct regmap_range axp806_
|
||||
regmap_reg_range(AXP806_REG_ADDR_EXT, AXP806_REG_ADDR_EXT),
|
||||
};
|
||||
|
||||
+static const struct regmap_range axp313a_writeable_ranges[] = {
|
||||
+ regmap_reg_range(AXP313A_ON_INDICATE, AXP313A_IRQ_STATE),
|
||||
+};
|
||||
+
|
||||
+static const struct regmap_range axp313a_volatile_ranges[] = {
|
||||
+ regmap_reg_range(AXP313A_SHUTDOWN_CTRL, AXP313A_SHUTDOWN_CTRL),
|
||||
+ regmap_reg_range(AXP313A_IRQ_STATE, AXP313A_IRQ_STATE),
|
||||
+};
|
||||
+
|
||||
+static const struct regmap_access_table axp313a_writeable_table = {
|
||||
+ .yes_ranges = axp313a_writeable_ranges,
|
||||
+ .n_yes_ranges = ARRAY_SIZE(axp313a_writeable_ranges),
|
||||
+};
|
||||
+
|
||||
+static const struct regmap_access_table axp313a_volatile_table = {
|
||||
+ .yes_ranges = axp313a_volatile_ranges,
|
||||
+ .n_yes_ranges = ARRAY_SIZE(axp313a_volatile_ranges),
|
||||
+};
|
||||
+
|
||||
static const struct regmap_range axp806_volatile_ranges[] = {
|
||||
regmap_reg_range(AXP20X_IRQ1_STATE, AXP20X_IRQ2_STATE),
|
||||
};
|
||||
@@ -248,6 +268,11 @@ static const struct resource axp288_fuel
|
||||
DEFINE_RES_IRQ(AXP288_IRQ_WL1),
|
||||
};
|
||||
|
||||
+static const struct resource axp313a_pek_resources[] = {
|
||||
+ DEFINE_RES_IRQ_NAMED(AXP313A_IRQ_PEK_RIS_EDGE, "PEK_DBR"),
|
||||
+ DEFINE_RES_IRQ_NAMED(AXP313A_IRQ_PEK_FAL_EDGE, "PEK_DBF"),
|
||||
+};
|
||||
+
|
||||
static const struct resource axp803_pek_resources[] = {
|
||||
DEFINE_RES_IRQ_NAMED(AXP803_IRQ_PEK_RIS_EDGE, "PEK_DBR"),
|
||||
DEFINE_RES_IRQ_NAMED(AXP803_IRQ_PEK_FAL_EDGE, "PEK_DBF"),
|
||||
@@ -304,6 +329,15 @@ static const struct regmap_config axp288
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
+static const struct regmap_config axp313a_regmap_config = {
|
||||
+ .reg_bits = 8,
|
||||
+ .val_bits = 8,
|
||||
+ .wr_table = &axp313a_writeable_table,
|
||||
+ .volatile_table = &axp313a_volatile_table,
|
||||
+ .max_register = AXP313A_IRQ_STATE,
|
||||
+ .cache_type = REGCACHE_RBTREE,
|
||||
+};
|
||||
+
|
||||
static const struct regmap_config axp806_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
@@ -456,6 +490,16 @@ static const struct regmap_irq axp288_re
|
||||
INIT_REGMAP_IRQ(AXP288, BC_USB_CHNG, 5, 1),
|
||||
};
|
||||
|
||||
+static const struct regmap_irq axp313a_regmap_irqs[] = {
|
||||
+ INIT_REGMAP_IRQ(AXP313A, PEK_RIS_EDGE, 0, 7),
|
||||
+ INIT_REGMAP_IRQ(AXP313A, PEK_FAL_EDGE, 0, 6),
|
||||
+ INIT_REGMAP_IRQ(AXP313A, PEK_SHORT, 0, 5),
|
||||
+ INIT_REGMAP_IRQ(AXP313A, PEK_LONG, 0, 4),
|
||||
+ INIT_REGMAP_IRQ(AXP313A, DCDC3_V_LOW, 0, 3),
|
||||
+ INIT_REGMAP_IRQ(AXP313A, DCDC2_V_LOW, 0, 2),
|
||||
+ INIT_REGMAP_IRQ(AXP313A, DIE_TEMP_HIGH, 0, 0),
|
||||
+};
|
||||
+
|
||||
static const struct regmap_irq axp803_regmap_irqs[] = {
|
||||
INIT_REGMAP_IRQ(AXP803, ACIN_OVER_V, 0, 7),
|
||||
INIT_REGMAP_IRQ(AXP803, ACIN_PLUGIN, 0, 6),
|
||||
@@ -610,6 +654,17 @@ static const struct regmap_irq_chip axp2
|
||||
|
||||
};
|
||||
|
||||
+static const struct regmap_irq_chip axp313a_regmap_irq_chip = {
|
||||
+ .name = "axp313a_irq_chip",
|
||||
+ .status_base = AXP313A_IRQ_STATE,
|
||||
+ .ack_base = AXP313A_IRQ_STATE,
|
||||
+ .unmask_base = AXP313A_IRQ_EN,
|
||||
+ .init_ack_masked = true,
|
||||
+ .irqs = axp313a_regmap_irqs,
|
||||
+ .num_irqs = ARRAY_SIZE(axp313a_regmap_irqs),
|
||||
+ .num_regs = 1,
|
||||
+};
|
||||
+
|
||||
static const struct regmap_irq_chip axp803_regmap_irq_chip = {
|
||||
.name = "axp803",
|
||||
.status_base = AXP20X_IRQ1_STATE,
|
||||
@@ -752,6 +807,11 @@ static const struct mfd_cell axp152_cell
|
||||
},
|
||||
};
|
||||
|
||||
+static struct mfd_cell axp313a_cells[] = {
|
||||
+ MFD_CELL_NAME("axp20x-regulator"),
|
||||
+ MFD_CELL_RES("axp313a-pek", axp313a_pek_resources),
|
||||
+};
|
||||
+
|
||||
static const struct resource axp288_adc_resources[] = {
|
||||
DEFINE_RES_IRQ_NAMED(AXP288_IRQ_GPADC, "GPADC"),
|
||||
};
|
||||
@@ -921,8 +981,18 @@ static const struct mfd_cell axp_regulat
|
||||
static int axp20x_power_off(struct sys_off_data *data)
|
||||
{
|
||||
struct axp20x_dev *axp20x = data->cb_data;
|
||||
+ unsigned int shutdown_reg;
|
||||
|
||||
- regmap_write(axp20x->regmap, AXP20X_OFF_CTRL, AXP20X_OFF);
|
||||
+ switch (axp20x->variant) {
|
||||
+ case AXP313A_ID:
|
||||
+ shutdown_reg = AXP313A_SHUTDOWN_CTRL;
|
||||
+ break;
|
||||
+ default:
|
||||
+ shutdown_reg = AXP20X_OFF_CTRL;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ regmap_write(axp20x->regmap, shutdown_reg, AXP20X_OFF);
|
||||
|
||||
/* Give capacitors etc. time to drain to avoid kernel panic msg. */
|
||||
mdelay(500);
|
||||
@@ -985,6 +1055,12 @@ int axp20x_match_device(struct axp20x_de
|
||||
axp20x->regmap_irq_chip = &axp288_regmap_irq_chip;
|
||||
axp20x->irq_flags = IRQF_TRIGGER_LOW;
|
||||
break;
|
||||
+ case AXP313A_ID:
|
||||
+ axp20x->nr_cells = ARRAY_SIZE(axp313a_cells);
|
||||
+ axp20x->cells = axp313a_cells;
|
||||
+ axp20x->regmap_cfg = &axp313a_regmap_config;
|
||||
+ axp20x->regmap_irq_chip = &axp313a_regmap_irq_chip;
|
||||
+ break;
|
||||
case AXP803_ID:
|
||||
axp20x->nr_cells = ARRAY_SIZE(axp803_cells);
|
||||
axp20x->cells = axp803_cells;
|
||||
--- a/include/linux/mfd/axp20x.h
|
||||
+++ b/include/linux/mfd/axp20x.h
|
||||
@@ -17,6 +17,7 @@ enum axp20x_variants {
|
||||
AXP221_ID,
|
||||
AXP223_ID,
|
||||
AXP288_ID,
|
||||
+ AXP313A_ID,
|
||||
AXP803_ID,
|
||||
AXP806_ID,
|
||||
AXP809_ID,
|
||||
@@ -92,6 +93,17 @@ enum axp20x_variants {
|
||||
#define AXP22X_ALDO3_V_OUT 0x2a
|
||||
#define AXP22X_CHRG_CTRL3 0x35
|
||||
|
||||
+#define AXP313A_ON_INDICATE 0x00
|
||||
+#define AXP313A_OUTPUT_CONTROL 0x10
|
||||
+#define AXP313A_DCDC1_CONRTOL 0x13
|
||||
+#define AXP313A_DCDC2_CONRTOL 0x14
|
||||
+#define AXP313A_DCDC3_CONRTOL 0x15
|
||||
+#define AXP313A_ALDO1_CONRTOL 0x16
|
||||
+#define AXP313A_DLDO1_CONRTOL 0x17
|
||||
+#define AXP313A_SHUTDOWN_CTRL 0x1a
|
||||
+#define AXP313A_IRQ_EN 0x20
|
||||
+#define AXP313A_IRQ_STATE 0x21
|
||||
+
|
||||
#define AXP806_STARTUP_SRC 0x00
|
||||
#define AXP806_CHIP_ID 0x03
|
||||
#define AXP806_PWR_OUT_CTRL1 0x10
|
||||
@@ -364,6 +376,16 @@ enum {
|
||||
};
|
||||
|
||||
enum {
|
||||
+ AXP313A_DCDC1 = 0,
|
||||
+ AXP313A_DCDC2,
|
||||
+ AXP313A_DCDC3,
|
||||
+ AXP313A_ALDO1,
|
||||
+ AXP313A_DLDO1,
|
||||
+ AXP313A_RTC_LDO,
|
||||
+ AXP313A_REG_ID_MAX,
|
||||
+};
|
||||
+
|
||||
+enum {
|
||||
AXP806_DCDCA = 0,
|
||||
AXP806_DCDCB,
|
||||
AXP806_DCDCC,
|
||||
@@ -616,6 +638,16 @@ enum axp288_irqs {
|
||||
AXP288_IRQ_BC_USB_CHNG,
|
||||
};
|
||||
|
||||
+enum axp313a_irqs {
|
||||
+ AXP313A_IRQ_DIE_TEMP_HIGH,
|
||||
+ AXP313A_IRQ_DCDC2_V_LOW = 2,
|
||||
+ AXP313A_IRQ_DCDC3_V_LOW,
|
||||
+ AXP313A_IRQ_PEK_LONG,
|
||||
+ AXP313A_IRQ_PEK_SHORT,
|
||||
+ AXP313A_IRQ_PEK_FAL_EDGE,
|
||||
+ AXP313A_IRQ_PEK_RIS_EDGE,
|
||||
+};
|
||||
+
|
||||
enum axp803_irqs {
|
||||
AXP803_IRQ_ACIN_OVER_V = 1,
|
||||
AXP803_IRQ_ACIN_PLUGIN,
|
@ -0,0 +1,129 @@
|
||||
From 60fd7eb89670d2636ac3156881acbd103c6eba6a Mon Sep 17 00:00:00 2001
|
||||
From: Martin Botka <martin.botka@somainline.org>
|
||||
Date: Wed, 24 May 2023 01:00:11 +0100
|
||||
Subject: [PATCH] regulator: axp20x: Add support for AXP313a variant
|
||||
|
||||
The AXP313a is your typical I2C controlled PMIC, although in a lighter
|
||||
fashion compared to the other X-Powers PMICs: it has only three DCDC
|
||||
rails, three LDOs, and no battery charging support.
|
||||
|
||||
The AXP313a datasheet does not describe a register to change the DCDC
|
||||
switching frequency, and talks of it being fixed at 3 MHz. Check that
|
||||
the property allowing to change that frequency is absent from the DT,
|
||||
and bail out otherwise.
|
||||
|
||||
The third LDO, RTCLDO, is fixed, and cannot even be turned on or off,
|
||||
programmatically. On top of that, its voltage is customisable (either
|
||||
1.8V or 3.3V), which we cannot describe easily using the existing
|
||||
regulator wrapper functions. This should be fixed properly, using
|
||||
regulator-{min,max}-microvolt in the DT, but this requires more changes
|
||||
to the code. As some other PMICs (AXP2xx, AXP803) seem to paper over the
|
||||
same problem as well, we follow suit here and pretend it's a fixed 1.8V
|
||||
regulator. A proper fix can follow later. The BSP code seems to ignore
|
||||
this regulator altogether.
|
||||
|
||||
Describe the AXP313A's voltage settings and switch registers, how the
|
||||
voltages are encoded, and connect this to the MFD device via its
|
||||
regulator ID.
|
||||
|
||||
Signed-off-by: Martin Botka <martin.botka@somainline.org>
|
||||
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
|
||||
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
|
||||
Reviewed-by: Mark Brown <broonie@kernel.org>
|
||||
Tested-by: Shengyu Qu <wiagn233@outlook.com>
|
||||
Link: https://lore.kernel.org/r/20230524000012.15028-3-andre.przywara@arm.com
|
||||
Signed-off-by: Mark Brown <broonie@kernel.org>
|
||||
---
|
||||
drivers/regulator/axp20x-regulator.c | 60 ++++++++++++++++++++++++++++
|
||||
1 file changed, 60 insertions(+)
|
||||
|
||||
--- a/drivers/regulator/axp20x-regulator.c
|
||||
+++ b/drivers/regulator/axp20x-regulator.c
|
||||
@@ -134,6 +134,11 @@
|
||||
#define AXP22X_PWR_OUT_DLDO4_MASK BIT_MASK(6)
|
||||
#define AXP22X_PWR_OUT_ALDO3_MASK BIT_MASK(7)
|
||||
|
||||
+#define AXP313A_DCDC1_NUM_VOLTAGES 107
|
||||
+#define AXP313A_DCDC23_NUM_VOLTAGES 88
|
||||
+#define AXP313A_DCDC_V_OUT_MASK GENMASK(6, 0)
|
||||
+#define AXP313A_LDO_V_OUT_MASK GENMASK(4, 0)
|
||||
+
|
||||
#define AXP803_PWR_OUT_DCDC1_MASK BIT_MASK(0)
|
||||
#define AXP803_PWR_OUT_DCDC2_MASK BIT_MASK(1)
|
||||
#define AXP803_PWR_OUT_DCDC3_MASK BIT_MASK(2)
|
||||
@@ -638,6 +643,48 @@ static const struct regulator_desc axp22
|
||||
.ops = &axp20x_ops_sw,
|
||||
};
|
||||
|
||||
+static const struct linear_range axp313a_dcdc1_ranges[] = {
|
||||
+ REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000),
|
||||
+ REGULATOR_LINEAR_RANGE(1220000, 71, 87, 20000),
|
||||
+ REGULATOR_LINEAR_RANGE(1600000, 88, 106, 100000),
|
||||
+};
|
||||
+
|
||||
+static const struct linear_range axp313a_dcdc2_ranges[] = {
|
||||
+ REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000),
|
||||
+ REGULATOR_LINEAR_RANGE(1220000, 71, 87, 20000),
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * This is deviating from the datasheet. The values here are taken from the
|
||||
+ * BSP driver and have been confirmed by measurements.
|
||||
+ */
|
||||
+static const struct linear_range axp313a_dcdc3_ranges[] = {
|
||||
+ REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000),
|
||||
+ REGULATOR_LINEAR_RANGE(1220000, 71, 102, 20000),
|
||||
+};
|
||||
+
|
||||
+static const struct regulator_desc axp313a_regulators[] = {
|
||||
+ AXP_DESC_RANGES(AXP313A, DCDC1, "dcdc1", "vin1",
|
||||
+ axp313a_dcdc1_ranges, AXP313A_DCDC1_NUM_VOLTAGES,
|
||||
+ AXP313A_DCDC1_CONRTOL, AXP313A_DCDC_V_OUT_MASK,
|
||||
+ AXP313A_OUTPUT_CONTROL, BIT(0)),
|
||||
+ AXP_DESC_RANGES(AXP313A, DCDC2, "dcdc2", "vin2",
|
||||
+ axp313a_dcdc2_ranges, AXP313A_DCDC23_NUM_VOLTAGES,
|
||||
+ AXP313A_DCDC2_CONRTOL, AXP313A_DCDC_V_OUT_MASK,
|
||||
+ AXP313A_OUTPUT_CONTROL, BIT(1)),
|
||||
+ AXP_DESC_RANGES(AXP313A, DCDC3, "dcdc3", "vin3",
|
||||
+ axp313a_dcdc3_ranges, AXP313A_DCDC23_NUM_VOLTAGES,
|
||||
+ AXP313A_DCDC3_CONRTOL, AXP313A_DCDC_V_OUT_MASK,
|
||||
+ AXP313A_OUTPUT_CONTROL, BIT(2)),
|
||||
+ AXP_DESC(AXP313A, ALDO1, "aldo1", "vin1", 500, 3500, 100,
|
||||
+ AXP313A_ALDO1_CONRTOL, AXP313A_LDO_V_OUT_MASK,
|
||||
+ AXP313A_OUTPUT_CONTROL, BIT(3)),
|
||||
+ AXP_DESC(AXP313A, DLDO1, "dldo1", "vin1", 500, 3500, 100,
|
||||
+ AXP313A_DLDO1_CONRTOL, AXP313A_LDO_V_OUT_MASK,
|
||||
+ AXP313A_OUTPUT_CONTROL, BIT(4)),
|
||||
+ AXP_DESC_FIXED(AXP313A, RTC_LDO, "rtc-ldo", "vin1", 1800),
|
||||
+};
|
||||
+
|
||||
/* DCDC ranges shared with AXP813 */
|
||||
static const struct linear_range axp803_dcdc234_ranges[] = {
|
||||
REGULATOR_LINEAR_RANGE(500000,
|
||||
@@ -1040,6 +1087,15 @@ static int axp20x_set_dcdc_freq(struct p
|
||||
def = 3000;
|
||||
step = 150;
|
||||
break;
|
||||
+ case AXP313A_ID:
|
||||
+ /* The DCDC PWM frequency seems to be fixed to 3 MHz. */
|
||||
+ if (dcdcfreq != 0) {
|
||||
+ dev_err(&pdev->dev,
|
||||
+ "DCDC frequency on AXP313a is fixed to 3 MHz.\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
default:
|
||||
dev_err(&pdev->dev,
|
||||
"Setting DCDC frequency for unsupported AXP variant\n");
|
||||
@@ -1232,6 +1288,10 @@ static int axp20x_regulator_probe(struct
|
||||
drivevbus = of_property_read_bool(pdev->dev.parent->of_node,
|
||||
"x-powers,drive-vbus-en");
|
||||
break;
|
||||
+ case AXP313A_ID:
|
||||
+ regulators = axp313a_regulators;
|
||||
+ nregulators = AXP313A_REG_ID_MAX;
|
||||
+ break;
|
||||
case AXP803_ID:
|
||||
regulators = axp803_regulators;
|
||||
nregulators = AXP803_REG_ID_MAX;
|
@ -1,30 +1,35 @@
|
||||
From 1b017f3376a5df4a2cd5a120c16723e777fc9a36 Mon Sep 17 00:00:00 2001
|
||||
From: "ziv.xu" <ziv.xu@starfive.com>
|
||||
Date: Fri, 4 Aug 2023 13:55:23 +0800
|
||||
Subject: [PATCH 118/122] driver: regulator: axp20x: Support AXP15060 variant.
|
||||
From 9e72869d0fe12aba8cd489e485d93912b3f5c248 Mon Sep 17 00:00:00 2001
|
||||
From: Shengyu Qu <wiagn233@outlook.com>
|
||||
Date: Wed, 24 May 2023 01:00:12 +0100
|
||||
Subject: [PATCH] regulator: axp20x: Add AXP15060 support
|
||||
|
||||
Add axp15060 variant support to axp20x
|
||||
The AXP15060 is a typical I2C-controlled PMIC, seen on multiple boards
|
||||
with different default register value. Current driver is tested on
|
||||
Starfive Visionfive 2.
|
||||
|
||||
Signed-off-by: ziv.xu <ziv.xu@starfive.com>
|
||||
The RTCLDO is fixed, and cannot even be turned on or off. On top of
|
||||
that, its voltage is customisable (either 1.8V or 3.3V). We pretend it's
|
||||
a fixed 1.8V regulator since other AXP driver also do like this. Also,
|
||||
BSP code ignores this regulator and it's not used according to VF2
|
||||
schematic.
|
||||
|
||||
Describe the AXP15060's voltage settings and switch registers, how the
|
||||
voltages are encoded, and connect this to the MFD device via its
|
||||
regulator ID.
|
||||
|
||||
Signed-off-by: Shengyu Qu <wiagn233@outlook.com>
|
||||
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
|
||||
Reviewed-by: Mark Brown <broonie@kernel.org>
|
||||
Tested-by: Shengyu Qu <wiagn233@outlook.com>
|
||||
Link: https://lore.kernel.org/r/20230524000012.15028-4-andre.przywara@arm.com
|
||||
Signed-off-by: Mark Brown <broonie@kernel.org>
|
||||
---
|
||||
drivers/regulator/axp20x-regulator.c | 291 ++++++++++++++++++++++++++-
|
||||
1 file changed, 283 insertions(+), 8 deletions(-)
|
||||
drivers/regulator/axp20x-regulator.c | 232 +++++++++++++++++++++++++--
|
||||
1 file changed, 223 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/drivers/regulator/axp20x-regulator.c
|
||||
+++ b/drivers/regulator/axp20x-regulator.c
|
||||
@@ -134,6 +134,11 @@
|
||||
#define AXP22X_PWR_OUT_DLDO4_MASK BIT_MASK(6)
|
||||
#define AXP22X_PWR_OUT_ALDO3_MASK BIT_MASK(7)
|
||||
|
||||
+#define AXP313A_DCDC1_NUM_VOLTAGES 107
|
||||
+#define AXP313A_DCDC23_NUM_VOLTAGES 88
|
||||
+#define AXP313A_DCDC_V_OUT_MASK GENMASK(6, 0)
|
||||
+#define AXP313A_LDO_V_OUT_MASK GENMASK(4, 0)
|
||||
+
|
||||
#define AXP803_PWR_OUT_DCDC1_MASK BIT_MASK(0)
|
||||
#define AXP803_PWR_OUT_DCDC2_MASK BIT_MASK(1)
|
||||
#define AXP803_PWR_OUT_DCDC3_MASK BIT_MASK(2)
|
||||
@@ -270,6 +275,74 @@
|
||||
@@ -275,6 +275,74 @@
|
||||
|
||||
#define AXP813_PWR_OUT_DCDC7_MASK BIT_MASK(6)
|
||||
|
||||
@ -99,56 +104,7 @@ Signed-off-by: ziv.xu <ziv.xu@starfive.com>
|
||||
#define AXP_DESC_IO(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
|
||||
_vmask, _ereg, _emask, _enable_val, _disable_val) \
|
||||
[_family##_##_id] = { \
|
||||
@@ -638,6 +711,48 @@ static const struct regulator_desc axp22
|
||||
.ops = &axp20x_ops_sw,
|
||||
};
|
||||
|
||||
+static const struct linear_range axp313a_dcdc1_ranges[] = {
|
||||
+ REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000),
|
||||
+ REGULATOR_LINEAR_RANGE(1220000, 71, 87, 20000),
|
||||
+ REGULATOR_LINEAR_RANGE(1600000, 88, 106, 100000),
|
||||
+};
|
||||
+
|
||||
+static const struct linear_range axp313a_dcdc2_ranges[] = {
|
||||
+ REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000),
|
||||
+ REGULATOR_LINEAR_RANGE(1220000, 71, 87, 20000),
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * This is deviating from the datasheet. The values here are taken from the
|
||||
+ * BSP driver and have been confirmed by measurements.
|
||||
+ */
|
||||
+static const struct linear_range axp313a_dcdc3_ranges[] = {
|
||||
+ REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000),
|
||||
+ REGULATOR_LINEAR_RANGE(1220000, 71, 102, 20000),
|
||||
+};
|
||||
+
|
||||
+static const struct regulator_desc axp313a_regulators[] = {
|
||||
+ AXP_DESC_RANGES(AXP313A, DCDC1, "dcdc1", "vin1",
|
||||
+ axp313a_dcdc1_ranges, AXP313A_DCDC1_NUM_VOLTAGES,
|
||||
+ AXP313A_DCDC1_CONRTOL, AXP313A_DCDC_V_OUT_MASK,
|
||||
+ AXP313A_OUTPUT_CONTROL, BIT(0)),
|
||||
+ AXP_DESC_RANGES(AXP313A, DCDC2, "dcdc2", "vin2",
|
||||
+ axp313a_dcdc2_ranges, AXP313A_DCDC23_NUM_VOLTAGES,
|
||||
+ AXP313A_DCDC2_CONRTOL, AXP313A_DCDC_V_OUT_MASK,
|
||||
+ AXP313A_OUTPUT_CONTROL, BIT(1)),
|
||||
+ AXP_DESC_RANGES(AXP313A, DCDC3, "dcdc3", "vin3",
|
||||
+ axp313a_dcdc3_ranges, AXP313A_DCDC23_NUM_VOLTAGES,
|
||||
+ AXP313A_DCDC3_CONRTOL, AXP313A_DCDC_V_OUT_MASK,
|
||||
+ AXP313A_OUTPUT_CONTROL, BIT(2)),
|
||||
+ AXP_DESC(AXP313A, ALDO1, "aldo1", "vin1", 500, 3500, 100,
|
||||
+ AXP313A_ALDO1_CONRTOL, AXP313A_LDO_V_OUT_MASK,
|
||||
+ AXP313A_OUTPUT_CONTROL, BIT(3)),
|
||||
+ AXP_DESC(AXP313A, DLDO1, "dldo1", "vin1", 500, 3500, 100,
|
||||
+ AXP313A_DLDO1_CONRTOL, AXP313A_LDO_V_OUT_MASK,
|
||||
+ AXP313A_OUTPUT_CONTROL, BIT(4)),
|
||||
+ AXP_DESC_FIXED(AXP313A, RTC_LDO, "rtc-ldo", "vin1", 1800),
|
||||
+};
|
||||
+
|
||||
/* DCDC ranges shared with AXP813 */
|
||||
static const struct linear_range axp803_dcdc234_ranges[] = {
|
||||
REGULATOR_LINEAR_RANGE(500000,
|
||||
@@ -1001,6 +1116,104 @@ static const struct regulator_desc axp81
|
||||
@@ -1048,6 +1116,104 @@ static const struct regulator_desc axp81
|
||||
AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DC1SW_MASK),
|
||||
};
|
||||
|
||||
@ -253,24 +209,20 @@ Signed-off-by: ziv.xu <ziv.xu@starfive.com>
|
||||
static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
|
||||
{
|
||||
struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
|
||||
@@ -1040,6 +1253,16 @@ static int axp20x_set_dcdc_freq(struct p
|
||||
def = 3000;
|
||||
@@ -1088,10 +1254,11 @@ static int axp20x_set_dcdc_freq(struct p
|
||||
step = 150;
|
||||
break;
|
||||
+ case AXP313A_ID:
|
||||
case AXP313A_ID:
|
||||
+ case AXP15060_ID:
|
||||
+ /* The DCDC PWM frequency seems to be fixed to 3 MHz. */
|
||||
+ if (dcdcfreq != 0) {
|
||||
+ dev_err(&pdev->dev,
|
||||
+ "DCDC frequency on this PMIC is fixed to 3 MHz.\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
default:
|
||||
/* The DCDC PWM frequency seems to be fixed to 3 MHz. */
|
||||
if (dcdcfreq != 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"Setting DCDC frequency for unsupported AXP variant\n");
|
||||
@@ -1145,6 +1368,15 @@ static int axp20x_set_dcdc_workmode(stru
|
||||
- "DCDC frequency on AXP313a is fixed to 3 MHz.\n");
|
||||
+ "DCDC frequency on this PMIC is fixed to 3 MHz.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -1201,6 +1368,15 @@ static int axp20x_set_dcdc_workmode(stru
|
||||
workmode <<= id - AXP813_DCDC1;
|
||||
break;
|
||||
|
||||
@ -286,7 +238,7 @@ Signed-off-by: ziv.xu <ziv.xu@starfive.com>
|
||||
default:
|
||||
/* should not happen */
|
||||
WARN_ON(1);
|
||||
@@ -1164,7 +1396,7 @@ static bool axp20x_is_polyphase_slave(st
|
||||
@@ -1220,7 +1396,7 @@ static bool axp20x_is_polyphase_slave(st
|
||||
|
||||
/*
|
||||
* Currently in our supported AXP variants, only AXP803, AXP806,
|
||||
@ -295,7 +247,7 @@ Signed-off-by: ziv.xu <ziv.xu@starfive.com>
|
||||
*/
|
||||
switch (axp20x->variant) {
|
||||
case AXP803_ID:
|
||||
@@ -1196,6 +1428,17 @@ static bool axp20x_is_polyphase_slave(st
|
||||
@@ -1252,6 +1428,17 @@ static bool axp20x_is_polyphase_slave(st
|
||||
}
|
||||
break;
|
||||
|
||||
@ -313,7 +265,7 @@ Signed-off-by: ziv.xu <ziv.xu@starfive.com>
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -1217,6 +1460,7 @@ static int axp20x_regulator_probe(struct
|
||||
@@ -1273,6 +1460,7 @@ static int axp20x_regulator_probe(struct
|
||||
u32 workmode;
|
||||
const char *dcdc1_name = axp22x_regulators[AXP22X_DCDC1].name;
|
||||
const char *dcdc5_name = axp22x_regulators[AXP22X_DCDC5].name;
|
||||
@ -321,18 +273,7 @@ Signed-off-by: ziv.xu <ziv.xu@starfive.com>
|
||||
bool drivevbus = false;
|
||||
|
||||
switch (axp20x->variant) {
|
||||
@@ -1232,6 +1476,10 @@ static int axp20x_regulator_probe(struct
|
||||
drivevbus = of_property_read_bool(pdev->dev.parent->of_node,
|
||||
"x-powers,drive-vbus-en");
|
||||
break;
|
||||
+ case AXP313A_ID:
|
||||
+ regulators = axp313a_regulators;
|
||||
+ nregulators = AXP313A_REG_ID_MAX;
|
||||
+ break;
|
||||
case AXP803_ID:
|
||||
regulators = axp803_regulators;
|
||||
nregulators = AXP803_REG_ID_MAX;
|
||||
@@ -1252,6 +1500,10 @@ static int axp20x_regulator_probe(struct
|
||||
@@ -1312,6 +1500,10 @@ static int axp20x_regulator_probe(struct
|
||||
drivevbus = of_property_read_bool(pdev->dev.parent->of_node,
|
||||
"x-powers,drive-vbus-en");
|
||||
break;
|
||||
@ -343,7 +284,7 @@ Signed-off-by: ziv.xu <ziv.xu@starfive.com>
|
||||
default:
|
||||
dev_err(&pdev->dev, "Unsupported AXP variant: %ld\n",
|
||||
axp20x->variant);
|
||||
@@ -1278,8 +1530,9 @@ static int axp20x_regulator_probe(struct
|
||||
@@ -1338,8 +1530,9 @@ static int axp20x_regulator_probe(struct
|
||||
continue;
|
||||
|
||||
/*
|
||||
@ -355,7 +296,7 @@ Signed-off-by: ziv.xu <ziv.xu@starfive.com>
|
||||
*
|
||||
* We always register the regulators in proper sequence,
|
||||
* so the supply names are correctly read. See the last
|
||||
@@ -1288,7 +1541,8 @@ static int axp20x_regulator_probe(struct
|
||||
@@ -1348,7 +1541,8 @@ static int axp20x_regulator_probe(struct
|
||||
*/
|
||||
if ((regulators == axp22x_regulators && i == AXP22X_DC1SW) ||
|
||||
(regulators == axp803_regulators && i == AXP803_DC1SW) ||
|
||||
@ -365,7 +306,7 @@ Signed-off-by: ziv.xu <ziv.xu@starfive.com>
|
||||
new_desc = devm_kzalloc(&pdev->dev, sizeof(*desc),
|
||||
GFP_KERNEL);
|
||||
if (!new_desc)
|
||||
@@ -1300,7 +1554,8 @@ static int axp20x_regulator_probe(struct
|
||||
@@ -1360,7 +1554,8 @@ static int axp20x_regulator_probe(struct
|
||||
}
|
||||
|
||||
if ((regulators == axp22x_regulators && i == AXP22X_DC5LDO) ||
|
||||
@ -375,7 +316,7 @@ Signed-off-by: ziv.xu <ziv.xu@starfive.com>
|
||||
new_desc = devm_kzalloc(&pdev->dev, sizeof(*desc),
|
||||
GFP_KERNEL);
|
||||
if (!new_desc)
|
||||
@@ -1311,6 +1566,18 @@ static int axp20x_regulator_probe(struct
|
||||
@@ -1371,6 +1566,18 @@ static int axp20x_regulator_probe(struct
|
||||
desc = new_desc;
|
||||
}
|
||||
|
||||
@ -394,7 +335,7 @@ Signed-off-by: ziv.xu <ziv.xu@starfive.com>
|
||||
rdev = devm_regulator_register(&pdev->dev, desc, &config);
|
||||
if (IS_ERR(rdev)) {
|
||||
dev_err(&pdev->dev, "Failed to register %s\n",
|
||||
@@ -1329,19 +1596,26 @@ static int axp20x_regulator_probe(struct
|
||||
@@ -1389,19 +1596,26 @@ static int axp20x_regulator_probe(struct
|
||||
}
|
||||
|
||||
/*
|
||||
@ -424,11 +365,3 @@ Signed-off-by: ziv.xu <ziv.xu@starfive.com>
|
||||
}
|
||||
|
||||
if (drivevbus) {
|
||||
@@ -1364,6 +1638,7 @@ static struct platform_driver axp20x_reg
|
||||
.probe = axp20x_regulator_probe,
|
||||
.driver = {
|
||||
.name = "axp20x-regulator",
|
||||
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
},
|
||||
};
|
||||
|
@ -0,0 +1,383 @@
|
||||
From 63eeabbc9dbddd7381409feccd9082e5ffabfe59 Mon Sep 17 00:00:00 2001
|
||||
From: Aidan MacDonald <aidanmacdonald.0x0@gmail.com>
|
||||
Date: Thu, 11 May 2023 10:26:08 +0100
|
||||
Subject: [PATCH] mfd: axp20x: Add support for AXP192
|
||||
|
||||
The AXP192 PMIC is similar to the AXP202/AXP209, but with different
|
||||
regulators, additional GPIOs, and a different IRQ register layout.
|
||||
|
||||
Signed-off-by: Aidan MacDonald <aidanmacdonald.0x0@gmail.com>
|
||||
Link: https://lore.kernel.org/r/20230511092609.76183-1-aidanmacdonald.0x0@gmail.com
|
||||
Signed-off-by: Lee Jones <lee@kernel.org>
|
||||
---
|
||||
drivers/mfd/axp20x-i2c.c | 2 +
|
||||
drivers/mfd/axp20x.c | 141 +++++++++++++++++++++++++++++++++++++
|
||||
include/linux/mfd/axp20x.h | 84 ++++++++++++++++++++++
|
||||
3 files changed, 227 insertions(+)
|
||||
|
||||
--- a/drivers/mfd/axp20x-i2c.c
|
||||
+++ b/drivers/mfd/axp20x-i2c.c
|
||||
@@ -60,6 +60,7 @@ static void axp20x_i2c_remove(struct i2c
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id axp20x_i2c_of_match[] = {
|
||||
{ .compatible = "x-powers,axp152", .data = (void *)AXP152_ID },
|
||||
+ { .compatible = "x-powers,axp192", .data = (void *)AXP192_ID },
|
||||
{ .compatible = "x-powers,axp202", .data = (void *)AXP202_ID },
|
||||
{ .compatible = "x-powers,axp209", .data = (void *)AXP209_ID },
|
||||
{ .compatible = "x-powers,axp221", .data = (void *)AXP221_ID },
|
||||
@@ -75,6 +76,7 @@ MODULE_DEVICE_TABLE(of, axp20x_i2c_of_ma
|
||||
|
||||
static const struct i2c_device_id axp20x_i2c_id[] = {
|
||||
{ "axp152", 0 },
|
||||
+ { "axp192", 0 },
|
||||
{ "axp202", 0 },
|
||||
{ "axp209", 0 },
|
||||
{ "axp221", 0 },
|
||||
--- a/drivers/mfd/axp20x.c
|
||||
+++ b/drivers/mfd/axp20x.c
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
static const char * const axp20x_model_names[] = {
|
||||
"AXP152",
|
||||
+ "AXP192",
|
||||
"AXP202",
|
||||
"AXP209",
|
||||
"AXP221",
|
||||
@@ -94,6 +95,35 @@ static const struct regmap_access_table
|
||||
.n_yes_ranges = ARRAY_SIZE(axp20x_volatile_ranges),
|
||||
};
|
||||
|
||||
+static const struct regmap_range axp192_writeable_ranges[] = {
|
||||
+ regmap_reg_range(AXP192_DATACACHE(0), AXP192_DATACACHE(5)),
|
||||
+ regmap_reg_range(AXP192_PWR_OUT_CTRL, AXP192_IRQ5_STATE),
|
||||
+ regmap_reg_range(AXP20X_DCDC_MODE, AXP192_N_RSTO_CTRL),
|
||||
+ regmap_reg_range(AXP20X_CC_CTRL, AXP20X_CC_CTRL),
|
||||
+};
|
||||
+
|
||||
+static const struct regmap_range axp192_volatile_ranges[] = {
|
||||
+ regmap_reg_range(AXP20X_PWR_INPUT_STATUS, AXP192_USB_OTG_STATUS),
|
||||
+ regmap_reg_range(AXP192_IRQ1_STATE, AXP192_IRQ4_STATE),
|
||||
+ regmap_reg_range(AXP192_IRQ5_STATE, AXP192_IRQ5_STATE),
|
||||
+ regmap_reg_range(AXP20X_ACIN_V_ADC_H, AXP20X_IPSOUT_V_HIGH_L),
|
||||
+ regmap_reg_range(AXP20X_TIMER_CTRL, AXP20X_TIMER_CTRL),
|
||||
+ regmap_reg_range(AXP192_GPIO2_0_STATE, AXP192_GPIO2_0_STATE),
|
||||
+ regmap_reg_range(AXP192_GPIO4_3_STATE, AXP192_GPIO4_3_STATE),
|
||||
+ regmap_reg_range(AXP192_N_RSTO_CTRL, AXP192_N_RSTO_CTRL),
|
||||
+ regmap_reg_range(AXP20X_CHRG_CC_31_24, AXP20X_CC_CTRL),
|
||||
+};
|
||||
+
|
||||
+static const struct regmap_access_table axp192_writeable_table = {
|
||||
+ .yes_ranges = axp192_writeable_ranges,
|
||||
+ .n_yes_ranges = ARRAY_SIZE(axp192_writeable_ranges),
|
||||
+};
|
||||
+
|
||||
+static const struct regmap_access_table axp192_volatile_table = {
|
||||
+ .yes_ranges = axp192_volatile_ranges,
|
||||
+ .n_yes_ranges = ARRAY_SIZE(axp192_volatile_ranges),
|
||||
+};
|
||||
+
|
||||
/* AXP22x ranges are shared with the AXP809, as they cover the same range */
|
||||
static const struct regmap_range axp22x_writeable_ranges[] = {
|
||||
regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE),
|
||||
@@ -220,6 +250,19 @@ static const struct resource axp152_pek_
|
||||
DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_FAL_EDGE, "PEK_DBF"),
|
||||
};
|
||||
|
||||
+static const struct resource axp192_ac_power_supply_resources[] = {
|
||||
+ DEFINE_RES_IRQ_NAMED(AXP192_IRQ_ACIN_PLUGIN, "ACIN_PLUGIN"),
|
||||
+ DEFINE_RES_IRQ_NAMED(AXP192_IRQ_ACIN_REMOVAL, "ACIN_REMOVAL"),
|
||||
+ DEFINE_RES_IRQ_NAMED(AXP192_IRQ_ACIN_OVER_V, "ACIN_OVER_V"),
|
||||
+};
|
||||
+
|
||||
+static const struct resource axp192_usb_power_supply_resources[] = {
|
||||
+ DEFINE_RES_IRQ_NAMED(AXP192_IRQ_VBUS_PLUGIN, "VBUS_PLUGIN"),
|
||||
+ DEFINE_RES_IRQ_NAMED(AXP192_IRQ_VBUS_REMOVAL, "VBUS_REMOVAL"),
|
||||
+ DEFINE_RES_IRQ_NAMED(AXP192_IRQ_VBUS_VALID, "VBUS_VALID"),
|
||||
+ DEFINE_RES_IRQ_NAMED(AXP192_IRQ_VBUS_NOT_VALID, "VBUS_NOT_VALID"),
|
||||
+};
|
||||
+
|
||||
static const struct resource axp20x_ac_power_supply_resources[] = {
|
||||
DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_ACIN_PLUGIN, "ACIN_PLUGIN"),
|
||||
DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_ACIN_REMOVAL, "ACIN_REMOVAL"),
|
||||
@@ -302,6 +345,15 @@ static const struct regmap_config axp152
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
+static const struct regmap_config axp192_regmap_config = {
|
||||
+ .reg_bits = 8,
|
||||
+ .val_bits = 8,
|
||||
+ .wr_table = &axp192_writeable_table,
|
||||
+ .volatile_table = &axp192_volatile_table,
|
||||
+ .max_register = AXP20X_CC_CTRL,
|
||||
+ .cache_type = REGCACHE_RBTREE,
|
||||
+};
|
||||
+
|
||||
static const struct regmap_config axp20x_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
@@ -379,6 +431,42 @@ static const struct regmap_irq axp152_re
|
||||
INIT_REGMAP_IRQ(AXP152, GPIO0_INPUT, 2, 0),
|
||||
};
|
||||
|
||||
+static const struct regmap_irq axp192_regmap_irqs[] = {
|
||||
+ INIT_REGMAP_IRQ(AXP192, ACIN_OVER_V, 0, 7),
|
||||
+ INIT_REGMAP_IRQ(AXP192, ACIN_PLUGIN, 0, 6),
|
||||
+ INIT_REGMAP_IRQ(AXP192, ACIN_REMOVAL, 0, 5),
|
||||
+ INIT_REGMAP_IRQ(AXP192, VBUS_OVER_V, 0, 4),
|
||||
+ INIT_REGMAP_IRQ(AXP192, VBUS_PLUGIN, 0, 3),
|
||||
+ INIT_REGMAP_IRQ(AXP192, VBUS_REMOVAL, 0, 2),
|
||||
+ INIT_REGMAP_IRQ(AXP192, VBUS_V_LOW, 0, 1),
|
||||
+ INIT_REGMAP_IRQ(AXP192, BATT_PLUGIN, 1, 7),
|
||||
+ INIT_REGMAP_IRQ(AXP192, BATT_REMOVAL, 1, 6),
|
||||
+ INIT_REGMAP_IRQ(AXP192, BATT_ENT_ACT_MODE, 1, 5),
|
||||
+ INIT_REGMAP_IRQ(AXP192, BATT_EXIT_ACT_MODE, 1, 4),
|
||||
+ INIT_REGMAP_IRQ(AXP192, CHARG, 1, 3),
|
||||
+ INIT_REGMAP_IRQ(AXP192, CHARG_DONE, 1, 2),
|
||||
+ INIT_REGMAP_IRQ(AXP192, BATT_TEMP_HIGH, 1, 1),
|
||||
+ INIT_REGMAP_IRQ(AXP192, BATT_TEMP_LOW, 1, 0),
|
||||
+ INIT_REGMAP_IRQ(AXP192, DIE_TEMP_HIGH, 2, 7),
|
||||
+ INIT_REGMAP_IRQ(AXP192, CHARG_I_LOW, 2, 6),
|
||||
+ INIT_REGMAP_IRQ(AXP192, DCDC1_V_LONG, 2, 5),
|
||||
+ INIT_REGMAP_IRQ(AXP192, DCDC2_V_LONG, 2, 4),
|
||||
+ INIT_REGMAP_IRQ(AXP192, DCDC3_V_LONG, 2, 3),
|
||||
+ INIT_REGMAP_IRQ(AXP192, PEK_SHORT, 2, 1),
|
||||
+ INIT_REGMAP_IRQ(AXP192, PEK_LONG, 2, 0),
|
||||
+ INIT_REGMAP_IRQ(AXP192, N_OE_PWR_ON, 3, 7),
|
||||
+ INIT_REGMAP_IRQ(AXP192, N_OE_PWR_OFF, 3, 6),
|
||||
+ INIT_REGMAP_IRQ(AXP192, VBUS_VALID, 3, 5),
|
||||
+ INIT_REGMAP_IRQ(AXP192, VBUS_NOT_VALID, 3, 4),
|
||||
+ INIT_REGMAP_IRQ(AXP192, VBUS_SESS_VALID, 3, 3),
|
||||
+ INIT_REGMAP_IRQ(AXP192, VBUS_SESS_END, 3, 2),
|
||||
+ INIT_REGMAP_IRQ(AXP192, LOW_PWR_LVL, 3, 0),
|
||||
+ INIT_REGMAP_IRQ(AXP192, TIMER, 4, 7),
|
||||
+ INIT_REGMAP_IRQ(AXP192, GPIO2_INPUT, 4, 2),
|
||||
+ INIT_REGMAP_IRQ(AXP192, GPIO1_INPUT, 4, 1),
|
||||
+ INIT_REGMAP_IRQ(AXP192, GPIO0_INPUT, 4, 0),
|
||||
+};
|
||||
+
|
||||
static const struct regmap_irq axp20x_regmap_irqs[] = {
|
||||
INIT_REGMAP_IRQ(AXP20X, ACIN_OVER_V, 0, 7),
|
||||
INIT_REGMAP_IRQ(AXP20X, ACIN_PLUGIN, 0, 6),
|
||||
@@ -616,6 +704,32 @@ static const struct regmap_irq_chip axp1
|
||||
.num_regs = 3,
|
||||
};
|
||||
|
||||
+static unsigned int axp192_get_irq_reg(struct regmap_irq_chip_data *data,
|
||||
+ unsigned int base, int index)
|
||||
+{
|
||||
+ /* linear mapping for IRQ1 to IRQ4 */
|
||||
+ if (index < 4)
|
||||
+ return base + index;
|
||||
+
|
||||
+ /* handle IRQ5 separately */
|
||||
+ if (base == AXP192_IRQ1_EN)
|
||||
+ return AXP192_IRQ5_EN;
|
||||
+
|
||||
+ return AXP192_IRQ5_STATE;
|
||||
+}
|
||||
+
|
||||
+static const struct regmap_irq_chip axp192_regmap_irq_chip = {
|
||||
+ .name = "axp192_irq_chip",
|
||||
+ .status_base = AXP192_IRQ1_STATE,
|
||||
+ .ack_base = AXP192_IRQ1_STATE,
|
||||
+ .unmask_base = AXP192_IRQ1_EN,
|
||||
+ .init_ack_masked = true,
|
||||
+ .irqs = axp192_regmap_irqs,
|
||||
+ .num_irqs = ARRAY_SIZE(axp192_regmap_irqs),
|
||||
+ .num_regs = 5,
|
||||
+ .get_irq_reg = axp192_get_irq_reg,
|
||||
+};
|
||||
+
|
||||
static const struct regmap_irq_chip axp20x_regmap_irq_chip = {
|
||||
.name = "axp20x_irq_chip",
|
||||
.status_base = AXP20X_IRQ1_STATE,
|
||||
@@ -712,6 +826,27 @@ static const struct regmap_irq_chip axp1
|
||||
.num_regs = 2,
|
||||
};
|
||||
|
||||
+static const struct mfd_cell axp192_cells[] = {
|
||||
+ {
|
||||
+ .name = "axp192-adc",
|
||||
+ .of_compatible = "x-powers,axp192-adc",
|
||||
+ }, {
|
||||
+ .name = "axp20x-battery-power-supply",
|
||||
+ .of_compatible = "x-powers,axp192-battery-power-supply",
|
||||
+ }, {
|
||||
+ .name = "axp20x-ac-power-supply",
|
||||
+ .of_compatible = "x-powers,axp202-ac-power-supply",
|
||||
+ .num_resources = ARRAY_SIZE(axp192_ac_power_supply_resources),
|
||||
+ .resources = axp192_ac_power_supply_resources,
|
||||
+ }, {
|
||||
+ .name = "axp20x-usb-power-supply",
|
||||
+ .of_compatible = "x-powers,axp192-usb-power-supply",
|
||||
+ .num_resources = ARRAY_SIZE(axp192_usb_power_supply_resources),
|
||||
+ .resources = axp192_usb_power_supply_resources,
|
||||
+ },
|
||||
+ { .name = "axp20x-regulator" },
|
||||
+};
|
||||
+
|
||||
static const struct mfd_cell axp20x_cells[] = {
|
||||
{
|
||||
.name = "axp20x-gpio",
|
||||
@@ -1029,6 +1164,12 @@ int axp20x_match_device(struct axp20x_de
|
||||
axp20x->regmap_cfg = &axp152_regmap_config;
|
||||
axp20x->regmap_irq_chip = &axp152_regmap_irq_chip;
|
||||
break;
|
||||
+ case AXP192_ID:
|
||||
+ axp20x->nr_cells = ARRAY_SIZE(axp192_cells);
|
||||
+ axp20x->cells = axp192_cells;
|
||||
+ axp20x->regmap_cfg = &axp192_regmap_config;
|
||||
+ axp20x->regmap_irq_chip = &axp192_regmap_irq_chip;
|
||||
+ break;
|
||||
case AXP202_ID:
|
||||
case AXP209_ID:
|
||||
axp20x->nr_cells = ARRAY_SIZE(axp20x_cells);
|
||||
--- a/include/linux/mfd/axp20x.h
|
||||
+++ b/include/linux/mfd/axp20x.h
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
enum axp20x_variants {
|
||||
AXP152_ID = 0,
|
||||
+ AXP192_ID,
|
||||
AXP202_ID,
|
||||
AXP209_ID,
|
||||
AXP221_ID,
|
||||
@@ -26,6 +27,7 @@ enum axp20x_variants {
|
||||
NR_AXP20X_VARIANTS,
|
||||
};
|
||||
|
||||
+#define AXP192_DATACACHE(m) (0x06 + (m))
|
||||
#define AXP20X_DATACACHE(m) (0x04 + (m))
|
||||
|
||||
/* Power supply */
|
||||
@@ -47,6 +49,13 @@ enum axp20x_variants {
|
||||
#define AXP152_DCDC_FREQ 0x37
|
||||
#define AXP152_DCDC_MODE 0x80
|
||||
|
||||
+#define AXP192_USB_OTG_STATUS 0x04
|
||||
+#define AXP192_PWR_OUT_CTRL 0x12
|
||||
+#define AXP192_DCDC2_V_OUT 0x23
|
||||
+#define AXP192_DCDC1_V_OUT 0x26
|
||||
+#define AXP192_DCDC3_V_OUT 0x27
|
||||
+#define AXP192_LDO2_3_V_OUT 0x28
|
||||
+
|
||||
#define AXP20X_PWR_INPUT_STATUS 0x00
|
||||
#define AXP20X_PWR_OP_MODE 0x01
|
||||
#define AXP20X_USB_OTG_STATUS 0x02
|
||||
@@ -185,6 +194,17 @@ enum axp20x_variants {
|
||||
#define AXP152_IRQ2_STATE 0x49
|
||||
#define AXP152_IRQ3_STATE 0x4a
|
||||
|
||||
+#define AXP192_IRQ1_EN 0x40
|
||||
+#define AXP192_IRQ2_EN 0x41
|
||||
+#define AXP192_IRQ3_EN 0x42
|
||||
+#define AXP192_IRQ4_EN 0x43
|
||||
+#define AXP192_IRQ1_STATE 0x44
|
||||
+#define AXP192_IRQ2_STATE 0x45
|
||||
+#define AXP192_IRQ3_STATE 0x46
|
||||
+#define AXP192_IRQ4_STATE 0x47
|
||||
+#define AXP192_IRQ5_EN 0x4a
|
||||
+#define AXP192_IRQ5_STATE 0x4d
|
||||
+
|
||||
#define AXP20X_IRQ1_EN 0x40
|
||||
#define AXP20X_IRQ2_EN 0x41
|
||||
#define AXP20X_IRQ3_EN 0x42
|
||||
@@ -204,6 +224,11 @@ enum axp20x_variants {
|
||||
#define AXP15060_IRQ2_STATE 0x49
|
||||
|
||||
/* ADC */
|
||||
+#define AXP192_GPIO2_V_ADC_H 0x68
|
||||
+#define AXP192_GPIO2_V_ADC_L 0x69
|
||||
+#define AXP192_GPIO3_V_ADC_H 0x6a
|
||||
+#define AXP192_GPIO3_V_ADC_L 0x6b
|
||||
+
|
||||
#define AXP20X_ACIN_V_ADC_H 0x56
|
||||
#define AXP20X_ACIN_V_ADC_L 0x57
|
||||
#define AXP20X_ACIN_I_ADC_H 0x58
|
||||
@@ -233,6 +258,8 @@ enum axp20x_variants {
|
||||
#define AXP20X_IPSOUT_V_HIGH_L 0x7f
|
||||
|
||||
/* Power supply */
|
||||
+#define AXP192_GPIO30_IN_RANGE 0x85
|
||||
+
|
||||
#define AXP20X_DCDC_MODE 0x80
|
||||
#define AXP20X_ADC_EN1 0x82
|
||||
#define AXP20X_ADC_EN2 0x83
|
||||
@@ -261,6 +288,16 @@ enum axp20x_variants {
|
||||
#define AXP152_PWM1_FREQ_Y 0x9c
|
||||
#define AXP152_PWM1_DUTY_CYCLE 0x9d
|
||||
|
||||
+#define AXP192_GPIO0_CTRL 0x90
|
||||
+#define AXP192_LDO_IO0_V_OUT 0x91
|
||||
+#define AXP192_GPIO1_CTRL 0x92
|
||||
+#define AXP192_GPIO2_CTRL 0x93
|
||||
+#define AXP192_GPIO2_0_STATE 0x94
|
||||
+#define AXP192_GPIO4_3_CTRL 0x95
|
||||
+#define AXP192_GPIO4_3_STATE 0x96
|
||||
+#define AXP192_GPIO2_0_PULL 0x97
|
||||
+#define AXP192_N_RSTO_CTRL 0x9e
|
||||
+
|
||||
#define AXP20X_GPIO0_CTRL 0x90
|
||||
#define AXP20X_LDO5_V_OUT 0x91
|
||||
#define AXP20X_GPIO1_CTRL 0x92
|
||||
@@ -341,6 +378,17 @@ enum axp20x_variants {
|
||||
|
||||
/* Regulators IDs */
|
||||
enum {
|
||||
+ AXP192_DCDC1 = 0,
|
||||
+ AXP192_DCDC2,
|
||||
+ AXP192_DCDC3,
|
||||
+ AXP192_LDO1,
|
||||
+ AXP192_LDO2,
|
||||
+ AXP192_LDO3,
|
||||
+ AXP192_LDO_IO0,
|
||||
+ AXP192_REG_ID_MAX
|
||||
+};
|
||||
+
|
||||
+enum {
|
||||
AXP20X_LDO1 = 0,
|
||||
AXP20X_LDO2,
|
||||
AXP20X_LDO3,
|
||||
@@ -531,6 +579,42 @@ enum {
|
||||
AXP152_IRQ_GPIO0_INPUT,
|
||||
};
|
||||
|
||||
+enum axp192_irqs {
|
||||
+ AXP192_IRQ_ACIN_OVER_V = 1,
|
||||
+ AXP192_IRQ_ACIN_PLUGIN,
|
||||
+ AXP192_IRQ_ACIN_REMOVAL,
|
||||
+ AXP192_IRQ_VBUS_OVER_V,
|
||||
+ AXP192_IRQ_VBUS_PLUGIN,
|
||||
+ AXP192_IRQ_VBUS_REMOVAL,
|
||||
+ AXP192_IRQ_VBUS_V_LOW,
|
||||
+ AXP192_IRQ_BATT_PLUGIN,
|
||||
+ AXP192_IRQ_BATT_REMOVAL,
|
||||
+ AXP192_IRQ_BATT_ENT_ACT_MODE,
|
||||
+ AXP192_IRQ_BATT_EXIT_ACT_MODE,
|
||||
+ AXP192_IRQ_CHARG,
|
||||
+ AXP192_IRQ_CHARG_DONE,
|
||||
+ AXP192_IRQ_BATT_TEMP_HIGH,
|
||||
+ AXP192_IRQ_BATT_TEMP_LOW,
|
||||
+ AXP192_IRQ_DIE_TEMP_HIGH,
|
||||
+ AXP192_IRQ_CHARG_I_LOW,
|
||||
+ AXP192_IRQ_DCDC1_V_LONG,
|
||||
+ AXP192_IRQ_DCDC2_V_LONG,
|
||||
+ AXP192_IRQ_DCDC3_V_LONG,
|
||||
+ AXP192_IRQ_PEK_SHORT = 22,
|
||||
+ AXP192_IRQ_PEK_LONG,
|
||||
+ AXP192_IRQ_N_OE_PWR_ON,
|
||||
+ AXP192_IRQ_N_OE_PWR_OFF,
|
||||
+ AXP192_IRQ_VBUS_VALID,
|
||||
+ AXP192_IRQ_VBUS_NOT_VALID,
|
||||
+ AXP192_IRQ_VBUS_SESS_VALID,
|
||||
+ AXP192_IRQ_VBUS_SESS_END,
|
||||
+ AXP192_IRQ_LOW_PWR_LVL = 31,
|
||||
+ AXP192_IRQ_TIMER,
|
||||
+ AXP192_IRQ_GPIO2_INPUT = 37,
|
||||
+ AXP192_IRQ_GPIO1_INPUT,
|
||||
+ AXP192_IRQ_GPIO0_INPUT,
|
||||
+};
|
||||
+
|
||||
enum {
|
||||
AXP20X_IRQ_ACIN_OVER_V = 1,
|
||||
AXP20X_IRQ_ACIN_PLUGIN,
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user