From f736d2c0caa8348b0bcd897972e470f7a596caad Mon Sep 17 00:00:00 2001 From: David Virag Date: Tue, 31 Jan 2023 19:30:06 +0100 Subject: mfd: sec: Remove PMICs without compatibles The S5M8751 and S5M8763 PMIC chips have no corresponding compatible values, so since board file support was removed for this driver, there is no way to specify these PMICs as present in boards anymore. Remove leftovers of these chips since it's dead code. Signed-off-by: David Virag Reviewed-by: Krzysztof Kozlowski Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230131183008.4451-2-virag.david003@gmail.com --- include/linux/mfd/samsung/core.h | 1 - include/linux/mfd/samsung/s5m8763.h | 90 ------------------------------------- 2 files changed, 91 deletions(-) delete mode 100644 include/linux/mfd/samsung/s5m8763.h (limited to 'include/linux') diff --git a/include/linux/mfd/samsung/core.h b/include/linux/mfd/samsung/core.h index f92fe090473d..07aae649a86f 100644 --- a/include/linux/mfd/samsung/core.h +++ b/include/linux/mfd/samsung/core.h @@ -36,7 +36,6 @@ struct gpio_desc; enum sec_device_type { - S5M8751X, S5M8763X, S5M8767X, S2MPA01, diff --git a/include/linux/mfd/samsung/s5m8763.h b/include/linux/mfd/samsung/s5m8763.h deleted file mode 100644 index c534f086ca16..000000000000 --- a/include/linux/mfd/samsung/s5m8763.h +++ /dev/null @@ -1,90 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 2011 Samsung Electronics Co., Ltd - * http://www.samsung.com - */ - -#ifndef __LINUX_MFD_S5M8763_H -#define __LINUX_MFD_S5M8763_H - -/* S5M8763 registers */ -enum s5m8763_reg { - S5M8763_REG_IRQ1, - S5M8763_REG_IRQ2, - S5M8763_REG_IRQ3, - S5M8763_REG_IRQ4, - S5M8763_REG_IRQM1, - S5M8763_REG_IRQM2, - S5M8763_REG_IRQM3, - S5M8763_REG_IRQM4, - S5M8763_REG_STATUS1, - S5M8763_REG_STATUS2, - S5M8763_REG_STATUSM1, - S5M8763_REG_STATUSM2, - S5M8763_REG_CHGR1, - S5M8763_REG_CHGR2, - S5M8763_REG_LDO_ACTIVE_DISCHARGE1, - S5M8763_REG_LDO_ACTIVE_DISCHARGE2, - S5M8763_REG_BUCK_ACTIVE_DISCHARGE3, - S5M8763_REG_ONOFF1, - S5M8763_REG_ONOFF2, - S5M8763_REG_ONOFF3, - S5M8763_REG_ONOFF4, - S5M8763_REG_BUCK1_VOLTAGE1, - S5M8763_REG_BUCK1_VOLTAGE2, - S5M8763_REG_BUCK1_VOLTAGE3, - S5M8763_REG_BUCK1_VOLTAGE4, - S5M8763_REG_BUCK2_VOLTAGE1, - S5M8763_REG_BUCK2_VOLTAGE2, - S5M8763_REG_BUCK3, - S5M8763_REG_BUCK4, - S5M8763_REG_LDO1_LDO2, - S5M8763_REG_LDO3, - S5M8763_REG_LDO4, - S5M8763_REG_LDO5, - S5M8763_REG_LDO6, - S5M8763_REG_LDO7, - S5M8763_REG_LDO7_LDO8, - S5M8763_REG_LDO9_LDO10, - S5M8763_REG_LDO11, - S5M8763_REG_LDO12, - S5M8763_REG_LDO13, - S5M8763_REG_LDO14, - S5M8763_REG_LDO15, - S5M8763_REG_LDO16, - S5M8763_REG_BKCHR, - S5M8763_REG_LBCNFG1, - S5M8763_REG_LBCNFG2, -}; - -/* S5M8763 regulator ids */ -enum s5m8763_regulators { - S5M8763_LDO1, - S5M8763_LDO2, - S5M8763_LDO3, - S5M8763_LDO4, - S5M8763_LDO5, - S5M8763_LDO6, - S5M8763_LDO7, - S5M8763_LDO8, - S5M8763_LDO9, - S5M8763_LDO10, - S5M8763_LDO11, - S5M8763_LDO12, - S5M8763_LDO13, - S5M8763_LDO14, - S5M8763_LDO15, - S5M8763_LDO16, - S5M8763_BUCK1, - S5M8763_BUCK2, - S5M8763_BUCK3, - S5M8763_BUCK4, - S5M8763_AP_EN32KHZ, - S5M8763_CP_EN32KHZ, - S5M8763_ENCHGVI, - S5M8763_ESAFEUSB1, - S5M8763_ESAFEUSB2, -}; - -#define S5M8763_ENRAMP (1 << 4) -#endif /* __LINUX_MFD_S5M8763_H */ -- cgit v1.2.3 From a3165abaa9bda3e729b434a3e684fcfa205f252a Mon Sep 17 00:00:00 2001 From: David Virag Date: Tue, 31 Jan 2023 19:30:07 +0100 Subject: rtc: s5m: Drop S5M8763 support The S5M8763 MFD has no device tree compatible, and since board file support for it was removed, there's no way to use this MFD. After removing the remaining code for it from the MFD driver, also remove support for it in the s5m RTC driver, and all remaining references to it. Signed-off-by: David Virag Acked-by: Alexandre Belloni Reviewed-by: Krzysztof Kozlowski Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230131183008.4451-3-virag.david003@gmail.com --- drivers/rtc/rtc-s5m.c | 82 ++-------------------------------------- include/linux/mfd/samsung/core.h | 1 - include/linux/mfd/samsung/irq.h | 50 ------------------------ 3 files changed, 3 insertions(+), 130 deletions(-) (limited to 'include/linux') diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index 4243fe6d3842..dad294a0ce2a 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -85,7 +85,7 @@ struct s5m_rtc_reg_config { unsigned int write_alarm_udr_mask; }; -/* Register map for S5M8763 and S5M8767 */ +/* Register map for S5M8767 */ static const struct s5m_rtc_reg_config s5m_rtc_regs = { .regs_count = 8, .time = S5M_RTC_SEC, @@ -236,7 +236,6 @@ static int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info, switch (info->device_type) { case S5M8767X: - case S5M8763X: ret = regmap_read(info->regmap, S5M_RTC_STATUS, &val); val &= S5M_ALARM0_STATUS; break; @@ -299,7 +298,6 @@ static int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) data |= info->regs->write_alarm_udr_mask; switch (info->device_type) { - case S5M8763X: case S5M8767X: data &= ~S5M_RTC_TIME_EN_MASK; break; @@ -329,38 +327,6 @@ static int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) return ret; } -static void s5m8763_data_to_tm(u8 *data, struct rtc_time *tm) -{ - tm->tm_sec = bcd2bin(data[RTC_SEC]); - tm->tm_min = bcd2bin(data[RTC_MIN]); - - if (data[RTC_HOUR] & HOUR_12) { - tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x1f); - if (data[RTC_HOUR] & HOUR_PM) - tm->tm_hour += 12; - } else { - tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x3f); - } - - tm->tm_wday = data[RTC_WEEKDAY] & 0x07; - tm->tm_mday = bcd2bin(data[RTC_DATE]); - tm->tm_mon = bcd2bin(data[RTC_MONTH]); - tm->tm_year = bcd2bin(data[RTC_YEAR1]) + bcd2bin(data[RTC_YEAR2]) * 100; - tm->tm_year -= 1900; -} - -static void s5m8763_tm_to_data(struct rtc_time *tm, u8 *data) -{ - data[RTC_SEC] = bin2bcd(tm->tm_sec); - data[RTC_MIN] = bin2bcd(tm->tm_min); - data[RTC_HOUR] = bin2bcd(tm->tm_hour); - data[RTC_WEEKDAY] = tm->tm_wday; - data[RTC_DATE] = bin2bcd(tm->tm_mday); - data[RTC_MONTH] = bin2bcd(tm->tm_mon); - data[RTC_YEAR1] = bin2bcd(tm->tm_year % 100); - data[RTC_YEAR2] = bin2bcd((tm->tm_year + 1900) / 100); -} - static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct s5m_rtc_info *info = dev_get_drvdata(dev); @@ -385,10 +351,6 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) return ret; switch (info->device_type) { - case S5M8763X: - s5m8763_data_to_tm(data, tm); - break; - case S5M8767X: case S2MPS15X: case S2MPS14X: @@ -412,9 +374,6 @@ static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm) int ret = 0; switch (info->device_type) { - case S5M8763X: - s5m8763_tm_to_data(tm, data); - break; case S5M8767X: case S2MPS15X: case S2MPS14X: @@ -444,7 +403,6 @@ static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct s5m_rtc_info *info = dev_get_drvdata(dev); u8 data[RTC_MAX_NUM_TIME_REGS]; - unsigned int val; int ret, i; ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data, @@ -453,15 +411,6 @@ static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) return ret; switch (info->device_type) { - case S5M8763X: - s5m8763_data_to_tm(data, &alrm->time); - ret = regmap_read(info->regmap, S5M_ALARM0_CONF, &val); - if (ret < 0) - return ret; - - alrm->enabled = !!val; - break; - case S5M8767X: case S2MPS15X: case S2MPS14X: @@ -500,10 +449,6 @@ static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info) dev_dbg(info->dev, "%s: %ptR(%d)\n", __func__, &tm, tm.tm_wday); switch (info->device_type) { - case S5M8763X: - ret = regmap_write(info->regmap, S5M_ALARM0_CONF, 0); - break; - case S5M8767X: case S2MPS15X: case S2MPS14X: @@ -531,7 +476,6 @@ static int s5m_rtc_start_alarm(struct s5m_rtc_info *info) { int ret; u8 data[RTC_MAX_NUM_TIME_REGS]; - u8 alarm0_conf; struct rtc_time tm; ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data, @@ -543,11 +487,6 @@ static int s5m_rtc_start_alarm(struct s5m_rtc_info *info) dev_dbg(info->dev, "%s: %ptR(%d)\n", __func__, &tm, tm.tm_wday); switch (info->device_type) { - case S5M8763X: - alarm0_conf = 0x77; - ret = regmap_write(info->regmap, S5M_ALARM0_CONF, alarm0_conf); - break; - case S5M8767X: case S2MPS15X: case S2MPS14X: @@ -585,10 +524,6 @@ static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) int ret; switch (info->device_type) { - case S5M8763X: - s5m8763_tm_to_data(&alrm->time, data); - break; - case S5M8767X: case S2MPS15X: case S2MPS14X: @@ -655,7 +590,6 @@ static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info) int ret; switch (info->device_type) { - case S5M8763X: case S5M8767X: /* UDR update time. Default of 7.32 ms is too long. */ ret = regmap_update_bits(info->regmap, S5M_RTC_UDR_CON, @@ -729,11 +663,6 @@ static int s5m_rtc_probe(struct platform_device *pdev) info->regs = &s2mps13_rtc_regs; alarm_irq = S2MPS14_IRQ_RTCA0; break; - case S5M8763X: - regmap_cfg = &s5m_rtc_regmap_config; - info->regs = &s5m_rtc_regs; - alarm_irq = S5M8763_IRQ_ALARM0; - break; case S5M8767X: regmap_cfg = &s5m_rtc_regmap_config; info->regs = &s5m_rtc_regs; @@ -786,13 +715,8 @@ static int s5m_rtc_probe(struct platform_device *pdev) info->rtc_dev->ops = &s5m_rtc_ops; - if (info->device_type == S5M8763X) { - info->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_0000; - info->rtc_dev->range_max = RTC_TIMESTAMP_END_9999; - } else { - info->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_2000; - info->rtc_dev->range_max = RTC_TIMESTAMP_END_2099; - } + info->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_2000; + info->rtc_dev->range_max = RTC_TIMESTAMP_END_2099; if (!info->irq) { clear_bit(RTC_FEATURE_ALARM, info->rtc_dev->features); diff --git a/include/linux/mfd/samsung/core.h b/include/linux/mfd/samsung/core.h index 07aae649a86f..a212b9f72bc9 100644 --- a/include/linux/mfd/samsung/core.h +++ b/include/linux/mfd/samsung/core.h @@ -36,7 +36,6 @@ struct gpio_desc; enum sec_device_type { - S5M8763X, S5M8767X, S2MPA01, S2MPS11X, diff --git a/include/linux/mfd/samsung/irq.h b/include/linux/mfd/samsung/irq.h index 6cfe4201a106..3fd2775eb9bb 100644 --- a/include/linux/mfd/samsung/irq.h +++ b/include/linux/mfd/samsung/irq.h @@ -194,54 +194,4 @@ enum s5m8767_irq { #define S5M8767_IRQ_RTC1S_MASK (1 << 4) #define S5M8767_IRQ_WTSR_MASK (1 << 5) -enum s5m8763_irq { - S5M8763_IRQ_DCINF, - S5M8763_IRQ_DCINR, - S5M8763_IRQ_JIGF, - S5M8763_IRQ_JIGR, - S5M8763_IRQ_PWRONF, - S5M8763_IRQ_PWRONR, - - S5M8763_IRQ_WTSREVNT, - S5M8763_IRQ_SMPLEVNT, - S5M8763_IRQ_ALARM1, - S5M8763_IRQ_ALARM0, - - S5M8763_IRQ_ONKEY1S, - S5M8763_IRQ_TOPOFFR, - S5M8763_IRQ_DCINOVPR, - S5M8763_IRQ_CHGRSTF, - S5M8763_IRQ_DONER, - S5M8763_IRQ_CHGFAULT, - - S5M8763_IRQ_LOBAT1, - S5M8763_IRQ_LOBAT2, - - S5M8763_IRQ_NR, -}; - -#define S5M8763_IRQ_DCINF_MASK (1 << 2) -#define S5M8763_IRQ_DCINR_MASK (1 << 3) -#define S5M8763_IRQ_JIGF_MASK (1 << 4) -#define S5M8763_IRQ_JIGR_MASK (1 << 5) -#define S5M8763_IRQ_PWRONF_MASK (1 << 6) -#define S5M8763_IRQ_PWRONR_MASK (1 << 7) - -#define S5M8763_IRQ_WTSREVNT_MASK (1 << 0) -#define S5M8763_IRQ_SMPLEVNT_MASK (1 << 1) -#define S5M8763_IRQ_ALARM1_MASK (1 << 2) -#define S5M8763_IRQ_ALARM0_MASK (1 << 3) - -#define S5M8763_IRQ_ONKEY1S_MASK (1 << 0) -#define S5M8763_IRQ_TOPOFFR_MASK (1 << 2) -#define S5M8763_IRQ_DCINOVPR_MASK (1 << 3) -#define S5M8763_IRQ_CHGRSTF_MASK (1 << 4) -#define S5M8763_IRQ_DONER_MASK (1 << 5) -#define S5M8763_IRQ_CHGFAULT_MASK (1 << 7) - -#define S5M8763_IRQ_LOBAT1_MASK (1 << 0) -#define S5M8763_IRQ_LOBAT2_MASK (1 << 1) - -#define S5M8763_ENRAMP (1 << 4) - #endif /* __LINUX_MFD_SEC_IRQ_H */ -- cgit v1.2.3 From 86c6bb0edffa9fc02b4e3801b48c8e82114f1352 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Tue, 14 Feb 2023 09:58:59 +0100 Subject: mfd: core: Reorder fields in 'struct mfd_cell' to save some memory Group some variables based on their sizes to reduce hole and avoid padding. On x86_64, this shrinks the size from 144 to 128 bytes. As an example: $ size drivers/mfd/as3722.o (Before) text data bss dec hex filename 9441 680 16 10137 2799 drivers/mfd/as3722.o $ size drivers/mfd/as3722.o (After) text data bss dec hex filename 9345 680 16 10041 2739 drivers/mfd/as3722.o Signed-off-by: Christophe JAILLET Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/bb631974888dfe1af593b6280cf30fb913d2d1a4.1676365116.git.christophe.jaillet@wanadoo.fr --- include/linux/mfd/core.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h index 14ca7b471576..fc4a0e9fb3bb 100644 --- a/include/linux/mfd/core.h +++ b/include/linux/mfd/core.h @@ -78,6 +78,9 @@ struct mfd_cell { void *platform_data; size_t pdata_size; + /* Matches ACPI */ + const struct mfd_cell_acpi_match *acpi_match; + /* Software node for the device. */ const struct software_node *swnode; @@ -97,9 +100,6 @@ struct mfd_cell { /* Set to 'true' to use 'of_reg' (above) - allows for of_reg=0 */ bool use_of_reg; - /* Matches ACPI */ - const struct mfd_cell_acpi_match *acpi_match; - /* * These resources can be specified relative to the parent device. * For accessing hardware you should use resources from the platform dev @@ -119,8 +119,8 @@ struct mfd_cell { /* A list of regulator supplies that should be mapped to the MFD * device rather than the child device when requested */ - const char * const *parent_supplies; int num_parent_supplies; + const char * const *parent_supplies; }; /* -- cgit v1.2.3 From b8fd17d9505e18001d10ceaa350c118a82b467bb Mon Sep 17 00:00:00 2001 From: Jakob Hauser Date: Tue, 28 Feb 2023 23:32:20 +0100 Subject: mfd: rt5033: Fix comments and style in includes Fix comments and remove some empty lines in rt5033-private.h. Align struct rt5033_charger in rt5033.h. Signed-off-by: Jakob Hauser Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/606950da6f4b36f5a124ff13756c78644fc89804.1677620677.git.jahau@rocketmail.com --- include/linux/mfd/rt5033-private.h | 17 +++++++---------- include/linux/mfd/rt5033.h | 7 +++---- 2 files changed, 10 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mfd/rt5033-private.h b/include/linux/mfd/rt5033-private.h index 2d1895c3efbf..6bb432f6a96c 100644 --- a/include/linux/mfd/rt5033-private.h +++ b/include/linux/mfd/rt5033-private.h @@ -107,14 +107,13 @@ enum rt5033_reg { #define RT5033_LDO_CTRL_MASK 0x1f /* RT5033 charger property - model, manufacturer */ - #define RT5033_CHARGER_MODEL "RT5033WSC Charger" #define RT5033_MANUFACTURER "Richtek Technology Corporation" /* - * RT5033 charger fast-charge current lmits (as in CHGCTRL1 register), - * AICR mode limits the input current for example, - * the AIRC 100 mode limits the input current to 100 mA. + * While RT5033 charger can limit the fast-charge current (as in CHGCTRL1 + * register), AICR mode limits the input current. For example, the AIRC 100 + * mode limits the input current to 100 mA. */ #define RT5033_AICR_100_MODE 0x20 #define RT5033_AICR_500_MODE 0x40 @@ -139,10 +138,9 @@ enum rt5033_reg { #define RT5033_TE_ENABLE_MASK 0x08 /* - * RT5033 charger opa mode. RT50300 have two opa mode charger mode - * and boost mode for OTG + * RT5033 charger opa mode. RT5033 has two opa modes for OTG: charger mode + * and boost mode. */ - #define RT5033_CHARGER_MODE 0x00 #define RT5033_BOOST_MODE 0x01 @@ -181,18 +179,17 @@ enum rt5033_reg { * RT5033 charger pre-charge threshold volt limits * (as in CHGCTRL5 register), uV */ - #define RT5033_CHARGER_PRE_THRESHOLD_LIMIT_MIN 2300000U #define RT5033_CHARGER_PRE_THRESHOLD_STEP_NUM 100000U #define RT5033_CHARGER_PRE_THRESHOLD_LIMIT_MAX 3800000U /* - * RT5033 charger enable UUG, If UUG enable MOS auto control by H/W charger + * RT5033 charger UUG. It enables MOS auto control by H/W charger * circuit. */ #define RT5033_CHARGER_UUG_ENABLE 0x02 -/* RT5033 charger High impedance mode */ +/* RT5033 charger high impedance mode */ #define RT5033_CHARGER_HZ_DISABLE 0x00 #define RT5033_CHARGER_HZ_ENABLE 0x01 diff --git a/include/linux/mfd/rt5033.h b/include/linux/mfd/rt5033.h index 3c23b6220c04..8f306ac15a27 100644 --- a/include/linux/mfd/rt5033.h +++ b/include/linux/mfd/rt5033.h @@ -49,10 +49,9 @@ struct rt5033_charger_data { }; struct rt5033_charger { - struct device *dev; - struct rt5033_dev *rt5033; - struct power_supply psy; - + struct device *dev; + struct rt5033_dev *rt5033; + struct power_supply psy; struct rt5033_charger_data *chg; }; -- cgit v1.2.3 From 0742c2a6335281608ac9e9aee67493e9e30f6195 Mon Sep 17 00:00:00 2001 From: Patrick Rudolph Date: Tue, 7 Mar 2023 13:12:45 +0100 Subject: mfd: max597x: Add support for MAX5970 and MAX5978 Implement a regulator driver with IRQ support for fault management. Written against documentation [1] and [2] and tested on real hardware. Every channel has it's own regulator supply nammed 'vss1-supply' and 'vss2-supply'. The regulator supply is used to determine the output voltage, as the smart switch provides no output regulation. The driver requires the 'shunt-resistor-micro-ohms' to be present in the devicetree to properly calculate current related values. You must specify compatible devictree layout: regulator@3a { reg = <0x3a>; vss1-supply = <&p3v3>; compatible = "maxim,max5978"; ... regulators { sw0_ref: SW0 { regulator-compatible = "SW0"; shunt-resistor-micro-ohms = <12000>; ... } } } 1: https://datasheets.maximintegrated.com/en/ds/MAX5970.pdf 2: https://datasheets.maximintegrated.com/en/ds/MAX5978.pdf ... Changes in V12: - Use simple_mfd_i2c driver and remove previous implementation. - Remove newline - Use _MFD_MAX597X_H in header file - Successfull build need following patch from regulator: https://lore.kernel.org/r/20230216075302.68935-1-Naresh.Solanki@9elements.com https://lore.kernel.org/r/20230210163225.1208035-1-Naresh.Solanki@9elements.com Signed-off-by: Patrick Rudolph Signed-off-by: Marcello Sylvester Bauer Signed-off-by: Naresh Solanki Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230307121246.127425-2-Naresh.Solanki@9elements.com --- drivers/mfd/Kconfig | 10 +++++ drivers/mfd/simple-mfd-i2c.c | 13 ++++++ include/linux/mfd/max597x.h | 96 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100644 include/linux/mfd/max597x.h (limited to 'include/linux') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index fcc141e067b9..d381d0e63455 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -266,6 +266,16 @@ config MFD_MADERA_SPI Support for the Cirrus Logic Madera platform audio SoC core functionality controlled via SPI. +config MFD_MAX597X + tristate "Maxim 597x power switch and monitor" + depends on (I2C && OF) + select MFD_SIMPLE_MFD_I2C + help + This driver controls a Maxim 5970/5978 switch via I2C bus. + The MAX5970/5978 is a smart switch with no output regulation, but + fault protection and voltage and current monitoring capabilities. + Also it supports upto 4 indication leds. + config MFD_CS47L15 bool "Cirrus Logic CS47L15" select PINCTRL_CS47L15 diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c index e31f13fd6a79..20782b4dd172 100644 --- a/drivers/mfd/simple-mfd-i2c.c +++ b/drivers/mfd/simple-mfd-i2c.c @@ -72,9 +72,22 @@ static const struct simple_mfd_data silergy_sy7636a = { .mfd_cell_size = ARRAY_SIZE(sy7636a_cells), }; +static const struct mfd_cell max597x_cells[] = { + { .name = "max597x-regulator", }, + { .name = "max597x-iio", }, + { .name = "max597x-led", }, +}; + +static const struct simple_mfd_data maxim_max597x = { + .mfd_cell = max597x_cells, + .mfd_cell_size = ARRAY_SIZE(max597x_cells), +}; + static const struct of_device_id simple_mfd_i2c_of_match[] = { { .compatible = "kontron,sl28cpld" }, { .compatible = "silergy,sy7636a", .data = &silergy_sy7636a}, + { .compatible = "maxim,max5970", .data = &maxim_max597x}, + { .compatible = "maxim,max5978", .data = &maxim_max597x}, {} }; MODULE_DEVICE_TABLE(of, simple_mfd_i2c_of_match); diff --git a/include/linux/mfd/max597x.h b/include/linux/mfd/max597x.h new file mode 100644 index 000000000000..a850b2e02e6a --- /dev/null +++ b/include/linux/mfd/max597x.h @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Device driver for regulators in MAX5970 and MAX5978 IC + * + * Copyright (c) 2022 9elements GmbH + * + * Author: Patrick Rudolph + */ + +#ifndef _MFD_MAX597X_H +#define _MFD_MAX597X_H + +#include + +#define MAX5970_NUM_SWITCHES 2 +#define MAX5978_NUM_SWITCHES 1 +#define MAX597X_NUM_LEDS 4 + +struct max597x_data { + int num_switches; + u32 irng[MAX5970_NUM_SWITCHES]; + u32 mon_rng[MAX5970_NUM_SWITCHES]; + u32 shunt_micro_ohms[MAX5970_NUM_SWITCHES]; +}; + +enum max597x_chip_type { + MAX597x_TYPE_MAX5978 = 1, + MAX597x_TYPE_MAX5970, +}; + +#define MAX5970_REG_CURRENT_L(ch) (0x01 + (ch) * 4) +#define MAX5970_REG_CURRENT_H(ch) (0x00 + (ch) * 4) +#define MAX5970_REG_VOLTAGE_L(ch) (0x03 + (ch) * 4) +#define MAX5970_REG_VOLTAGE_H(ch) (0x02 + (ch) * 4) +#define MAX5970_REG_MON_RANGE 0x18 +#define MAX5970_MON_MASK 0x3 +#define MAX5970_MON(reg, ch) (((reg) >> ((ch) * 2)) & MAX5970_MON_MASK) +#define MAX5970_MON_MAX_RANGE_UV 16000000 + +#define MAX5970_REG_CH_UV_WARN_H(ch) (0x1A + (ch) * 10) +#define MAX5970_REG_CH_UV_WARN_L(ch) (0x1B + (ch) * 10) +#define MAX5970_REG_CH_UV_CRIT_H(ch) (0x1C + (ch) * 10) +#define MAX5970_REG_CH_UV_CRIT_L(ch) (0x1D + (ch) * 10) +#define MAX5970_REG_CH_OV_WARN_H(ch) (0x1E + (ch) * 10) +#define MAX5970_REG_CH_OV_WARN_L(ch) (0x1F + (ch) * 10) +#define MAX5970_REG_CH_OV_CRIT_H(ch) (0x20 + (ch) * 10) +#define MAX5970_REG_CH_OV_CRIT_L(ch) (0x21 + (ch) * 10) + +#define MAX5970_VAL2REG_H(x) (((x) >> 2) & 0xFF) +#define MAX5970_VAL2REG_L(x) ((x) & 0x3) + +#define MAX5970_REG_DAC_FAST(ch) (0x2E + (ch)) + +#define MAX5970_FAST2SLOW_RATIO 200 + +#define MAX5970_REG_STATUS0 0x31 +#define MAX5970_CB_IFAULTF(ch) (1 << (ch)) +#define MAX5970_CB_IFAULTS(ch) (1 << ((ch) + 4)) + +#define MAX5970_REG_STATUS1 0x32 +#define STATUS1_PROT_MASK 0x3 +#define STATUS1_PROT(reg) \ + (((reg) >> 6) & STATUS1_PROT_MASK) +#define STATUS1_PROT_SHUTDOWN 0 +#define STATUS1_PROT_CLEAR_PG 1 +#define STATUS1_PROT_ALERT_ONLY 2 + +#define MAX5970_REG_STATUS2 0x33 +#define MAX5970_IRNG_MASK 0x3 +#define MAX5970_IRNG(reg, ch) \ + (((reg) >> ((ch) * 2)) & MAX5970_IRNG_MASK) + +#define MAX5970_REG_STATUS3 0x34 +#define MAX5970_STATUS3_ALERT BIT(4) +#define MAX5970_STATUS3_PG(ch) BIT(ch) + +#define MAX5970_REG_FAULT0 0x35 +#define UV_STATUS_WARN(ch) (1 << (ch)) +#define UV_STATUS_CRIT(ch) (1 << ((ch) + 4)) + +#define MAX5970_REG_FAULT1 0x36 +#define OV_STATUS_WARN(ch) (1 << (ch)) +#define OV_STATUS_CRIT(ch) (1 << ((ch) + 4)) + +#define MAX5970_REG_FAULT2 0x37 +#define OC_STATUS_WARN(ch) (1 << (ch)) + +#define MAX5970_REG_CHXEN 0x3b +#define CHXEN(ch) (3 << ((ch) * 2)) + +#define MAX5970_REG_LED_FLASH 0x43 + +#define MAX_REGISTERS 0x49 +#define ADC_MASK 0x3FF + +#endif /* _MFD_MAX597X_H */ -- cgit v1.2.3 From a0b9becad8a7d62a81530035a69f744c0e389737 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 8 Mar 2023 10:12:57 +0100 Subject: mfd: core: Remove .enable() and .disable() callbacks With commit dd77f5fa97d3 ("mfd: Remove toshiba tmio drivers") the last mfd driver that implements these callbacks is gone and since commit 652719b1003a ("w1: remove ds1wm driver") the last user is gone. The corresponding functions mfd_cell_enable() and mfd_cell_disable() are also unused (since commit 0ca222c81977 ("leds: Remove asic3 driver")). Signed-off-by: Uwe Kleine-König Acked-by: Arnd Bergmann Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230308091257.2404932-1-u.kleine-koenig@pengutronix.de --- drivers/mfd/mfd-core.c | 26 -------------------------- include/linux/mfd/core.h | 12 ------------ 2 files changed, 38 deletions(-) (limited to 'include/linux') diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 16d1861e9682..695d50b3bac6 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -33,32 +33,6 @@ static struct device_type mfd_dev_type = { .name = "mfd_device", }; -int mfd_cell_enable(struct platform_device *pdev) -{ - const struct mfd_cell *cell = mfd_get_cell(pdev); - - if (!cell->enable) { - dev_dbg(&pdev->dev, "No .enable() call-back registered\n"); - return 0; - } - - return cell->enable(pdev); -} -EXPORT_SYMBOL(mfd_cell_enable); - -int mfd_cell_disable(struct platform_device *pdev) -{ - const struct mfd_cell *cell = mfd_get_cell(pdev); - - if (!cell->disable) { - dev_dbg(&pdev->dev, "No .disable() call-back registered\n"); - return 0; - } - - return cell->disable(pdev); -} -EXPORT_SYMBOL(mfd_cell_disable); - #if IS_ENABLED(CONFIG_ACPI) struct match_ids_walk_data { struct acpi_device_id *ids; diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h index fc4a0e9fb3bb..47e7a3a61ce6 100644 --- a/include/linux/mfd/core.h +++ b/include/linux/mfd/core.h @@ -68,9 +68,6 @@ struct mfd_cell { int id; int level; - int (*enable)(struct platform_device *dev); - int (*disable)(struct platform_device *dev); - int (*suspend)(struct platform_device *dev); int (*resume)(struct platform_device *dev); @@ -123,15 +120,6 @@ struct mfd_cell { const char * const *parent_supplies; }; -/* - * Convenience functions for clients using shared cells. Refcounting - * happens automatically, with the cell's enable/disable callbacks - * being called only when a device is first being enabled or no other - * clients are making use of it. - */ -extern int mfd_cell_enable(struct platform_device *pdev); -extern int mfd_cell_disable(struct platform_device *pdev); - /* * Given a platform device that's been created by mfd_add_devices(), fetch * the mfd_cell that created it. -- cgit v1.2.3 From 67d6c76fc815cddc77de9529221f9ff8dd1fb10e Mon Sep 17 00:00:00 2001 From: Min Li Date: Mon, 27 Mar 2023 14:39:53 -0400 Subject: mfd: rsmu: Support 32-bit address space We used to assume 0x2010xxxx address. Now that we need to access 0x2011xxxx address, we need to support read/write the whole 32-bit address space. Also defined RSMU_MAX_WRITE_COUNT and RSMU_MAX_READ_COUNT for readability Signed-off-by: Min Li Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/MW5PR03MB693295AF31ABCAF6AE52EE74A08B9@MW5PR03MB6932.namprd03.prod.outlook.com --- drivers/mfd/rsmu.h | 2 + drivers/mfd/rsmu_i2c.c | 171 +++++++++++++++++++++++++++++++++++++---------- drivers/mfd/rsmu_spi.c | 52 ++++++++------ include/linux/mfd/rsmu.h | 5 +- 4 files changed, 174 insertions(+), 56 deletions(-) (limited to 'include/linux') diff --git a/drivers/mfd/rsmu.h b/drivers/mfd/rsmu.h index bb88597d189f..1bb04cafa45d 100644 --- a/drivers/mfd/rsmu.h +++ b/drivers/mfd/rsmu.h @@ -10,6 +10,8 @@ #include +#define RSMU_CM_SCSR_BASE 0x20100000 + int rsmu_core_init(struct rsmu_ddata *rsmu); void rsmu_core_exit(struct rsmu_ddata *rsmu); diff --git a/drivers/mfd/rsmu_i2c.c b/drivers/mfd/rsmu_i2c.c index 15d25b081434..221023faaadf 100644 --- a/drivers/mfd/rsmu_i2c.c +++ b/drivers/mfd/rsmu_i2c.c @@ -18,11 +18,12 @@ #include "rsmu.h" /* - * 16-bit register address: the lower 8 bits of the register address come - * from the offset addr byte and the upper 8 bits come from the page register. + * 32-bit register address: the lower 8 bits of the register address come + * from the offset addr byte and the upper 24 bits come from the page register. */ -#define RSMU_CM_PAGE_ADDR 0xFD -#define RSMU_CM_PAGE_WINDOW 256 +#define RSMU_CM_PAGE_ADDR 0xFC +#define RSMU_CM_PAGE_MASK 0xFFFFFF00 +#define RSMU_CM_ADDRESS_MASK 0x000000FF /* * 15-bit register address: the lower 7 bits of the register address come @@ -31,18 +32,6 @@ #define RSMU_SABRE_PAGE_ADDR 0x7F #define RSMU_SABRE_PAGE_WINDOW 128 -static const struct regmap_range_cfg rsmu_cm_range_cfg[] = { - { - .range_min = 0, - .range_max = 0xD000, - .selector_reg = RSMU_CM_PAGE_ADDR, - .selector_mask = 0xFF, - .selector_shift = 0, - .window_start = 0, - .window_len = RSMU_CM_PAGE_WINDOW, - } -}; - static const struct regmap_range_cfg rsmu_sabre_range_cfg[] = { { .range_min = 0, @@ -55,35 +44,141 @@ static const struct regmap_range_cfg rsmu_sabre_range_cfg[] = { } }; -static bool rsmu_cm_volatile_reg(struct device *dev, unsigned int reg) +static bool rsmu_sabre_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { - case RSMU_CM_PAGE_ADDR: + case RSMU_SABRE_PAGE_ADDR: return false; default: return true; } } -static bool rsmu_sabre_volatile_reg(struct device *dev, unsigned int reg) +static int rsmu_read_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u16 bytes) { - switch (reg) { - case RSMU_SABRE_PAGE_ADDR: - return false; - default: - return true; + struct i2c_client *client = to_i2c_client(rsmu->dev); + struct i2c_msg msg[2]; + int cnt; + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = 1; + msg[0].buf = ® + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = bytes; + msg[1].buf = buf; + + cnt = i2c_transfer(client->adapter, msg, 2); + + if (cnt < 0) { + dev_err(rsmu->dev, "i2c_transfer failed at addr: %04x!", reg); + return cnt; + } else if (cnt != 2) { + dev_err(rsmu->dev, + "i2c_transfer sent only %d of 2 messages", cnt); + return -EIO; + } + + return 0; +} + +static int rsmu_write_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u16 bytes) +{ + struct i2c_client *client = to_i2c_client(rsmu->dev); + u8 msg[RSMU_MAX_WRITE_COUNT + 1]; /* 1 Byte added for the device register */ + int cnt; + + if (bytes > RSMU_MAX_WRITE_COUNT) + return -EINVAL; + + msg[0] = reg; + memcpy(&msg[1], buf, bytes); + + cnt = i2c_master_send(client, msg, bytes + 1); + + if (cnt < 0) { + dev_err(&client->dev, + "i2c_master_send failed at addr: %04x!", reg); + return cnt; } + + return 0; +} + +static int rsmu_write_page_register(struct rsmu_ddata *rsmu, u32 reg) +{ + u32 page = reg & RSMU_CM_PAGE_MASK; + u8 buf[4]; + int err; + + /* Do not modify offset register for none-scsr registers */ + if (reg < RSMU_CM_SCSR_BASE) + return 0; + + /* Simply return if we are on the same page */ + if (rsmu->page == page) + return 0; + + buf[0] = 0x0; + buf[1] = (u8)((page >> 8) & 0xFF); + buf[2] = (u8)((page >> 16) & 0xFF); + buf[3] = (u8)((page >> 24) & 0xFF); + + err = rsmu_write_device(rsmu, RSMU_CM_PAGE_ADDR, buf, sizeof(buf)); + if (err) + dev_err(rsmu->dev, "Failed to set page offset 0x%x\n", page); + else + /* Remember the last page */ + rsmu->page = page; + + return err; +} + +static int rsmu_reg_read(void *context, unsigned int reg, unsigned int *val) +{ + struct rsmu_ddata *rsmu = i2c_get_clientdata((struct i2c_client *)context); + u8 addr = (u8)(reg & RSMU_CM_ADDRESS_MASK); + int err; + + err = rsmu_write_page_register(rsmu, reg); + if (err) + return err; + + err = rsmu_read_device(rsmu, addr, (u8 *)val, 1); + if (err) + dev_err(rsmu->dev, "Failed to read offset address 0x%x\n", addr); + + return err; +} + +static int rsmu_reg_write(void *context, unsigned int reg, unsigned int val) +{ + struct rsmu_ddata *rsmu = i2c_get_clientdata((struct i2c_client *)context); + u8 addr = (u8)(reg & RSMU_CM_ADDRESS_MASK); + u8 data = (u8)val; + int err; + + err = rsmu_write_page_register(rsmu, reg); + if (err) + return err; + + err = rsmu_write_device(rsmu, addr, &data, 1); + if (err) + dev_err(rsmu->dev, + "Failed to write offset address 0x%x\n", addr); + + return err; } static const struct regmap_config rsmu_cm_regmap_config = { - .reg_bits = 8, + .reg_bits = 32, .val_bits = 8, - .max_register = 0xD000, - .ranges = rsmu_cm_range_cfg, - .num_ranges = ARRAY_SIZE(rsmu_cm_range_cfg), - .volatile_reg = rsmu_cm_volatile_reg, - .cache_type = REGCACHE_RBTREE, - .can_multi_write = true, + .max_register = 0x20120000, + .reg_read = rsmu_reg_read, + .reg_write = rsmu_reg_write, + .cache_type = REGCACHE_NONE, }; static const struct regmap_config rsmu_sabre_regmap_config = { @@ -101,14 +196,14 @@ static const struct regmap_config rsmu_sl_regmap_config = { .reg_bits = 16, .val_bits = 8, .reg_format_endian = REGMAP_ENDIAN_BIG, - .max_register = 0x339, + .max_register = 0x340, .cache_type = REGCACHE_NONE, .can_multi_write = true, }; -static int rsmu_i2c_probe(struct i2c_client *client) +static int rsmu_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); const struct regmap_config *cfg; struct rsmu_ddata *rsmu; int ret; @@ -136,7 +231,11 @@ static int rsmu_i2c_probe(struct i2c_client *client) dev_err(rsmu->dev, "Unsupported RSMU device type: %d\n", rsmu->type); return -ENODEV; } - rsmu->regmap = devm_regmap_init_i2c(client, cfg); + + if (rsmu->type == RSMU_CM) + rsmu->regmap = devm_regmap_init(&client->dev, NULL, client, cfg); + else + rsmu->regmap = devm_regmap_init_i2c(client, cfg); if (IS_ERR(rsmu->regmap)) { ret = PTR_ERR(rsmu->regmap); dev_err(rsmu->dev, "Failed to allocate register map: %d\n", ret); @@ -180,7 +279,7 @@ static struct i2c_driver rsmu_i2c_driver = { .name = "rsmu-i2c", .of_match_table = of_match_ptr(rsmu_i2c_of_match), }, - .probe_new = rsmu_i2c_probe, + .probe = rsmu_i2c_probe, .remove = rsmu_i2c_remove, .id_table = rsmu_i2c_id, }; diff --git a/drivers/mfd/rsmu_spi.c b/drivers/mfd/rsmu_spi.c index 2428aaa9aaed..a4a595bb8d0d 100644 --- a/drivers/mfd/rsmu_spi.c +++ b/drivers/mfd/rsmu_spi.c @@ -19,19 +19,21 @@ #define RSMU_CM_PAGE_ADDR 0x7C #define RSMU_SABRE_PAGE_ADDR 0x7F -#define RSMU_HIGHER_ADDR_MASK 0xFF80 -#define RSMU_HIGHER_ADDR_SHIFT 7 -#define RSMU_LOWER_ADDR_MASK 0x7F +#define RSMU_PAGE_MASK 0xFFFFFF80 +#define RSMU_ADDR_MASK 0x7F static int rsmu_read_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u16 bytes) { struct spi_device *client = to_spi_device(rsmu->dev); struct spi_transfer xfer = {0}; struct spi_message msg; - u8 cmd[256] = {0}; - u8 rsp[256] = {0}; + u8 cmd[RSMU_MAX_READ_COUNT + 1] = {0}; + u8 rsp[RSMU_MAX_READ_COUNT + 1] = {0}; int ret; + if (bytes > RSMU_MAX_READ_COUNT) + return -EINVAL; + cmd[0] = reg | 0x80; xfer.rx_buf = rsp; xfer.len = bytes + 1; @@ -66,7 +68,10 @@ static int rsmu_write_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u16 bytes struct spi_device *client = to_spi_device(rsmu->dev); struct spi_transfer xfer = {0}; struct spi_message msg; - u8 cmd[256] = {0}; + u8 cmd[RSMU_MAX_WRITE_COUNT + 1] = {0}; + + if (bytes > RSMU_MAX_WRITE_COUNT) + return -EINVAL; cmd[0] = reg; memcpy(&cmd[1], buf, bytes); @@ -86,26 +91,35 @@ static int rsmu_write_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u16 bytes * 16-bit register address: the lower 7 bits of the register address come * from the offset addr byte and the upper 9 bits come from the page register. */ -static int rsmu_write_page_register(struct rsmu_ddata *rsmu, u16 reg) +static int rsmu_write_page_register(struct rsmu_ddata *rsmu, u32 reg) { u8 page_reg; - u8 buf[2]; + u8 buf[4]; u16 bytes; - u16 page; + u32 page; int err; switch (rsmu->type) { case RSMU_CM: + /* Do not modify page register for none-scsr registers */ + if (reg < RSMU_CM_SCSR_BASE) + return 0; page_reg = RSMU_CM_PAGE_ADDR; - page = reg & RSMU_HIGHER_ADDR_MASK; + page = reg & RSMU_PAGE_MASK; buf[0] = (u8)(page & 0xff); buf[1] = (u8)((page >> 8) & 0xff); - bytes = 2; + buf[2] = (u8)((page >> 16) & 0xff); + buf[3] = (u8)((page >> 24) & 0xff); + bytes = 4; break; case RSMU_SABRE: + /* Do not modify page register if reg is page register itself */ + if ((reg & RSMU_ADDR_MASK) == RSMU_ADDR_MASK) + return 0; page_reg = RSMU_SABRE_PAGE_ADDR; - page = reg >> RSMU_HIGHER_ADDR_SHIFT; - buf[0] = (u8)(page & 0xff); + page = reg & RSMU_PAGE_MASK; + /* The three page bits are located in the single Page Register */ + buf[0] = (u8)((page >> 7) & 0x7); bytes = 1; break; default: @@ -129,8 +143,8 @@ static int rsmu_write_page_register(struct rsmu_ddata *rsmu, u16 reg) static int rsmu_reg_read(void *context, unsigned int reg, unsigned int *val) { - struct rsmu_ddata *rsmu = spi_get_drvdata(context); - u8 addr = (u8)(reg & RSMU_LOWER_ADDR_MASK); + struct rsmu_ddata *rsmu = spi_get_drvdata((struct spi_device *)context); + u8 addr = (u8)(reg & RSMU_ADDR_MASK); int err; err = rsmu_write_page_register(rsmu, reg); @@ -146,8 +160,8 @@ static int rsmu_reg_read(void *context, unsigned int reg, unsigned int *val) static int rsmu_reg_write(void *context, unsigned int reg, unsigned int val) { - struct rsmu_ddata *rsmu = spi_get_drvdata(context); - u8 addr = (u8)(reg & RSMU_LOWER_ADDR_MASK); + struct rsmu_ddata *rsmu = spi_get_drvdata((struct spi_device *)context); + u8 addr = (u8)(reg & RSMU_ADDR_MASK); u8 data = (u8)val; int err; @@ -164,9 +178,9 @@ static int rsmu_reg_write(void *context, unsigned int reg, unsigned int val) } static const struct regmap_config rsmu_cm_regmap_config = { - .reg_bits = 16, + .reg_bits = 32, .val_bits = 8, - .max_register = 0xD000, + .max_register = 0x20120000, .reg_read = rsmu_reg_read, .reg_write = rsmu_reg_write, .cache_type = REGCACHE_NONE, diff --git a/include/linux/mfd/rsmu.h b/include/linux/mfd/rsmu.h index 6870de608233..0379aa207428 100644 --- a/include/linux/mfd/rsmu.h +++ b/include/linux/mfd/rsmu.h @@ -8,6 +8,9 @@ #ifndef __LINUX_MFD_RSMU_H #define __LINUX_MFD_RSMU_H +#define RSMU_MAX_WRITE_COUNT (255) +#define RSMU_MAX_READ_COUNT (255) + /* The supported devices are ClockMatrix, Sabre and SnowLotus */ enum rsmu_type { RSMU_CM = 0x34000, @@ -31,6 +34,6 @@ struct rsmu_ddata { struct regmap *regmap; struct mutex lock; enum rsmu_type type; - u16 page; + u32 page; }; #endif /* __LINUX_MFD_RSMU_H */ -- cgit v1.2.3 From 654c293e1687b31819f9bf1ac71b5a85a8053210 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 30 Mar 2023 12:16:28 +0100 Subject: mfd: Add Renesas RZ/G2L MTU3a core driver The RZ/G2L multi-function timer pulse unit 3 (MTU3a) is embedded in the Renesas RZ/G2L family SoCs. It consists of eight 16-bit timer channels and one 32-bit timer channel. It supports the following functions - Counter - Timer - PWM The 8/16/32 bit registers are mixed in each channel. Add MTU3a core driver for RZ/G2L SoC. The core driver shares the clk and channel register access for the other child devices like Counter, PWM and Clock event. Signed-off-by: Biju Das Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230330111632.169434-3-biju.das.jz@bp.renesas.com --- drivers/mfd/Kconfig | 10 ++ drivers/mfd/Makefile | 1 + drivers/mfd/rz-mtu3.c | 391 ++++++++++++++++++++++++++++++++++++++++++++ drivers/mfd/rz-mtu3.h | 147 +++++++++++++++++ include/linux/mfd/rz-mtu3.h | 257 +++++++++++++++++++++++++++++ 5 files changed, 806 insertions(+) create mode 100644 drivers/mfd/rz-mtu3.c create mode 100644 drivers/mfd/rz-mtu3.h create mode 100644 include/linux/mfd/rz-mtu3.h (limited to 'include/linux') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 51d54a1b8673..e90463c4441c 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1315,6 +1315,16 @@ config MFD_SC27XX_PMIC This driver provides common support for accessing the SC27xx PMICs, and it also adds the irq_chip parts for handling the PMIC chip events. +config RZ_MTU3 + bool "Renesas RZ/G2L MTU3a core driver" + depends on (ARCH_RZG2L && OF) || COMPILE_TEST + help + Select this option to enable Renesas RZ/G2L MTU3a core driver for + the Multi-Function Timer Pulse Unit 3 (MTU3a) hardware available + on SoCs from Renesas. The core driver shares the clk and channel + register access for the other child devices like Counter, PWM, + Clock Source, and Clock event. + config ABX500_CORE bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions" depends on ARCH_U8500 || COMPILE_TEST diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 2f6c89d1e277..1d2392f06f78 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -174,6 +174,7 @@ pcf50633-objs := pcf50633-core.o pcf50633-irq.o obj-$(CONFIG_MFD_PCF50633) += pcf50633.o obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o +obj-$(CONFIG_RZ_MTU3) += rz-mtu3.o obj-$(CONFIG_ABX500_CORE) += abx500-core.o obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o # ab8500-core need to come after db8500-prcmu (which provides the channel) diff --git a/drivers/mfd/rz-mtu3.c b/drivers/mfd/rz-mtu3.c new file mode 100644 index 000000000000..04006f4aa702 --- /dev/null +++ b/drivers/mfd/rz-mtu3.c @@ -0,0 +1,391 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas RZ/G2L Multi-Function Timer Pulse Unit 3(MTU3a) Core driver + * + * Copyright (C) 2023 Renesas Electronics Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rz-mtu3.h" + +struct rz_mtu3_priv { + void __iomem *mmio; + struct reset_control *rstc; + raw_spinlock_t lock; +}; + +/******* MTU3 registers (original offset is +0x1200) *******/ +static const unsigned long rz_mtu3_8bit_ch_reg_offs[][13] = { + [RZ_MTU3_CHAN_0] = MTU_8BIT_CH_0(0x104, 0x090, 0x100, 0x128, 0x101, 0x102, 0x103, 0x126), + [RZ_MTU3_CHAN_1] = MTU_8BIT_CH_1_2(0x184, 0x091, 0x185, 0x180, 0x194, 0x181, 0x182), + [RZ_MTU3_CHAN_2] = MTU_8BIT_CH_1_2(0x204, 0x092, 0x205, 0x200, 0x20c, 0x201, 0x202), + [RZ_MTU3_CHAN_3] = MTU_8BIT_CH_3_4_6_7(0x008, 0x093, 0x02c, 0x000, 0x04c, 0x002, 0x004, 0x005, 0x038), + [RZ_MTU3_CHAN_4] = MTU_8BIT_CH_3_4_6_7(0x009, 0x094, 0x02d, 0x001, 0x04d, 0x003, 0x006, 0x007, 0x039), + [RZ_MTU3_CHAN_5] = MTU_8BIT_CH_5(0xab2, 0x1eb, 0xab4, 0xab6, 0xa84, 0xa85, 0xa86, 0xa94, 0xa95, 0xa96, 0xaa4, 0xaa5, 0xaa6), + [RZ_MTU3_CHAN_6] = MTU_8BIT_CH_3_4_6_7(0x808, 0x893, 0x82c, 0x800, 0x84c, 0x802, 0x804, 0x805, 0x838), + [RZ_MTU3_CHAN_7] = MTU_8BIT_CH_3_4_6_7(0x809, 0x894, 0x82d, 0x801, 0x84d, 0x803, 0x806, 0x807, 0x839), + [RZ_MTU3_CHAN_8] = MTU_8BIT_CH_8(0x404, 0x098, 0x400, 0x406, 0x401, 0x402, 0x403) +}; + +static const unsigned long rz_mtu3_16bit_ch_reg_offs[][12] = { + [RZ_MTU3_CHAN_0] = MTU_16BIT_CH_0(0x106, 0x108, 0x10a, 0x10c, 0x10e, 0x120, 0x122), + [RZ_MTU3_CHAN_1] = MTU_16BIT_CH_1_2(0x186, 0x188, 0x18a), + [RZ_MTU3_CHAN_2] = MTU_16BIT_CH_1_2(0x206, 0x208, 0x20a), + [RZ_MTU3_CHAN_3] = MTU_16BIT_CH_3_6(0x010, 0x018, 0x01a, 0x024, 0x026, 0x072), + [RZ_MTU3_CHAN_4] = MTU_16BIT_CH_4_7(0x012, 0x01c, 0x01e, 0x028, 0x2a, 0x074, 0x076, 0x040, 0x044, 0x046, 0x048, 0x04a), + [RZ_MTU3_CHAN_5] = MTU_16BIT_CH_5(0xa80, 0xa82, 0xa90, 0xa92, 0xaa0, 0xaa2), + [RZ_MTU3_CHAN_6] = MTU_16BIT_CH_3_6(0x810, 0x818, 0x81a, 0x824, 0x826, 0x872), + [RZ_MTU3_CHAN_7] = MTU_16BIT_CH_4_7(0x812, 0x81c, 0x81e, 0x828, 0x82a, 0x874, 0x876, 0x840, 0x844, 0x846, 0x848, 0x84a) +}; + +static const unsigned long rz_mtu3_32bit_ch_reg_offs[][5] = { + [RZ_MTU3_CHAN_1] = MTU_32BIT_CH_1(0x1a0, 0x1a4, 0x1a8), + [RZ_MTU3_CHAN_8] = MTU_32BIT_CH_8(0x408, 0x40c, 0x410, 0x414, 0x418) +}; + +static bool rz_mtu3_is_16bit_shared_reg(u16 offset) +{ + return (offset == RZ_MTU3_TDDRA || offset == RZ_MTU3_TDDRB || + offset == RZ_MTU3_TCDRA || offset == RZ_MTU3_TCDRB || + offset == RZ_MTU3_TCBRA || offset == RZ_MTU3_TCBRB || + offset == RZ_MTU3_TCNTSA || offset == RZ_MTU3_TCNTSB); +} + +u16 rz_mtu3_shared_reg_read(struct rz_mtu3_channel *ch, u16 offset) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + + if (rz_mtu3_is_16bit_shared_reg(offset)) + return readw(priv->mmio + offset); + else + return readb(priv->mmio + offset); +} +EXPORT_SYMBOL_GPL(rz_mtu3_shared_reg_read); + +u8 rz_mtu3_8bit_ch_read(struct rz_mtu3_channel *ch, u16 offset) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + u16 ch_offs; + + ch_offs = rz_mtu3_8bit_ch_reg_offs[ch->channel_number][offset]; + + return readb(priv->mmio + ch_offs); +} +EXPORT_SYMBOL_GPL(rz_mtu3_8bit_ch_read); + +u16 rz_mtu3_16bit_ch_read(struct rz_mtu3_channel *ch, u16 offset) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + u16 ch_offs; + + /* MTU8 doesn't have 16-bit registers */ + if (ch->channel_number == RZ_MTU3_CHAN_8) + return 0; + + ch_offs = rz_mtu3_16bit_ch_reg_offs[ch->channel_number][offset]; + + return readw(priv->mmio + ch_offs); +} +EXPORT_SYMBOL_GPL(rz_mtu3_16bit_ch_read); + +u32 rz_mtu3_32bit_ch_read(struct rz_mtu3_channel *ch, u16 offset) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + u16 ch_offs; + + if (ch->channel_number != RZ_MTU3_CHAN_1 && ch->channel_number != RZ_MTU3_CHAN_8) + return 0; + + ch_offs = rz_mtu3_32bit_ch_reg_offs[ch->channel_number][offset]; + + return readl(priv->mmio + ch_offs); +} +EXPORT_SYMBOL_GPL(rz_mtu3_32bit_ch_read); + +void rz_mtu3_8bit_ch_write(struct rz_mtu3_channel *ch, u16 offset, u8 val) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + u16 ch_offs; + + ch_offs = rz_mtu3_8bit_ch_reg_offs[ch->channel_number][offset]; + writeb(val, priv->mmio + ch_offs); +} +EXPORT_SYMBOL_GPL(rz_mtu3_8bit_ch_write); + +void rz_mtu3_16bit_ch_write(struct rz_mtu3_channel *ch, u16 offset, u16 val) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + u16 ch_offs; + + /* MTU8 doesn't have 16-bit registers */ + if (ch->channel_number == RZ_MTU3_CHAN_8) + return; + + ch_offs = rz_mtu3_16bit_ch_reg_offs[ch->channel_number][offset]; + writew(val, priv->mmio + ch_offs); +} +EXPORT_SYMBOL_GPL(rz_mtu3_16bit_ch_write); + +void rz_mtu3_32bit_ch_write(struct rz_mtu3_channel *ch, u16 offset, u32 val) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + u16 ch_offs; + + if (ch->channel_number != RZ_MTU3_CHAN_1 && ch->channel_number != RZ_MTU3_CHAN_8) + return; + + ch_offs = rz_mtu3_32bit_ch_reg_offs[ch->channel_number][offset]; + writel(val, priv->mmio + ch_offs); +} +EXPORT_SYMBOL_GPL(rz_mtu3_32bit_ch_write); + +void rz_mtu3_shared_reg_write(struct rz_mtu3_channel *ch, u16 offset, u16 value) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + + if (rz_mtu3_is_16bit_shared_reg(offset)) + writew(value, priv->mmio + offset); + else + writeb((u8)value, priv->mmio + offset); +} +EXPORT_SYMBOL_GPL(rz_mtu3_shared_reg_write); + +void rz_mtu3_shared_reg_update_bit(struct rz_mtu3_channel *ch, u16 offset, + u16 pos, u8 val) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + unsigned long tmdr, flags; + + raw_spin_lock_irqsave(&priv->lock, flags); + tmdr = rz_mtu3_shared_reg_read(ch, offset); + __assign_bit(pos, &tmdr, !!val); + rz_mtu3_shared_reg_write(ch, offset, tmdr); + raw_spin_unlock_irqrestore(&priv->lock, flags); +} +EXPORT_SYMBOL_GPL(rz_mtu3_shared_reg_update_bit); + +static u16 rz_mtu3_get_tstr_offset(struct rz_mtu3_channel *ch) +{ + u16 offset; + + switch (ch->channel_number) { + case RZ_MTU3_CHAN_0: + case RZ_MTU3_CHAN_1: + case RZ_MTU3_CHAN_2: + case RZ_MTU3_CHAN_3: + case RZ_MTU3_CHAN_4: + case RZ_MTU3_CHAN_8: + offset = RZ_MTU3_TSTRA; + break; + case RZ_MTU3_CHAN_5: + offset = RZ_MTU3_TSTR; + break; + case RZ_MTU3_CHAN_6: + case RZ_MTU3_CHAN_7: + offset = RZ_MTU3_TSTRB; + break; + default: + offset = 0; + break; + } + + return offset; +} + +static u8 rz_mtu3_get_tstr_bit_pos(struct rz_mtu3_channel *ch) +{ + u8 bitpos; + + switch (ch->channel_number) { + case RZ_MTU3_CHAN_0: + case RZ_MTU3_CHAN_1: + case RZ_MTU3_CHAN_2: + case RZ_MTU3_CHAN_6: + case RZ_MTU3_CHAN_7: + bitpos = ch->channel_number; + break; + case RZ_MTU3_CHAN_3: + bitpos = 6; + break; + case RZ_MTU3_CHAN_4: + bitpos = 7; + break; + case RZ_MTU3_CHAN_5: + bitpos = 2; + break; + case RZ_MTU3_CHAN_8: + bitpos = 3; + break; + default: + bitpos = 0; + break; + } + + return bitpos; +} + +static void rz_mtu3_start_stop_ch(struct rz_mtu3_channel *ch, bool start) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + unsigned long flags, tstr; + u16 offset; + u8 bitpos; + + /* start stop register shared by multiple timer channels */ + raw_spin_lock_irqsave(&priv->lock, flags); + + offset = rz_mtu3_get_tstr_offset(ch); + bitpos = rz_mtu3_get_tstr_bit_pos(ch); + tstr = rz_mtu3_shared_reg_read(ch, offset); + __assign_bit(bitpos, &tstr, start); + rz_mtu3_shared_reg_write(ch, offset, tstr); + + raw_spin_unlock_irqrestore(&priv->lock, flags); +} + +bool rz_mtu3_is_enabled(struct rz_mtu3_channel *ch) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(ch->dev->parent); + struct rz_mtu3_priv *priv = mtu->priv_data; + unsigned long flags, tstr; + bool ret = false; + u16 offset; + u8 bitpos; + + /* start stop register shared by multiple timer channels */ + raw_spin_lock_irqsave(&priv->lock, flags); + + offset = rz_mtu3_get_tstr_offset(ch); + bitpos = rz_mtu3_get_tstr_bit_pos(ch); + tstr = rz_mtu3_shared_reg_read(ch, offset); + ret = tstr & BIT(bitpos); + + raw_spin_unlock_irqrestore(&priv->lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(rz_mtu3_is_enabled); + +int rz_mtu3_enable(struct rz_mtu3_channel *ch) +{ + /* enable channel */ + rz_mtu3_start_stop_ch(ch, true); + + return 0; +} +EXPORT_SYMBOL_GPL(rz_mtu3_enable); + +void rz_mtu3_disable(struct rz_mtu3_channel *ch) +{ + /* disable channel */ + rz_mtu3_start_stop_ch(ch, false); +} +EXPORT_SYMBOL_GPL(rz_mtu3_disable); + +static void rz_mtu3_reset_assert(void *data) +{ + struct rz_mtu3 *mtu = dev_get_drvdata(data); + struct rz_mtu3_priv *priv = mtu->priv_data; + + mfd_remove_devices(data); + reset_control_assert(priv->rstc); +} + +static const struct mfd_cell rz_mtu3_devs[] = { + { + .name = "rz-mtu3-counter", + }, + { + .name = "pwm-rz-mtu3", + }, +}; + +static int rz_mtu3_probe(struct platform_device *pdev) +{ + struct rz_mtu3_priv *priv; + struct rz_mtu3 *ddata; + unsigned int i; + int ret; + + ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); + if (!ddata) + return -ENOMEM; + + ddata->priv_data = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!ddata->priv_data) + return -ENOMEM; + + priv = ddata->priv_data; + + priv->mmio = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->mmio)) + return PTR_ERR(priv->mmio); + + priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); + if (IS_ERR(priv->rstc)) + return PTR_ERR(priv->rstc); + + ddata->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(ddata->clk)) + return PTR_ERR(ddata->clk); + + reset_control_deassert(priv->rstc); + raw_spin_lock_init(&priv->lock); + platform_set_drvdata(pdev, ddata); + + for (i = 0; i < RZ_MTU_NUM_CHANNELS; i++) { + ddata->channels[i].channel_number = i; + ddata->channels[i].is_busy = false; + mutex_init(&ddata->channels[i].lock); + } + + ret = mfd_add_devices(&pdev->dev, 0, rz_mtu3_devs, + ARRAY_SIZE(rz_mtu3_devs), NULL, 0, NULL); + if (ret < 0) + goto err_assert; + + return devm_add_action_or_reset(&pdev->dev, rz_mtu3_reset_assert, + &pdev->dev); + +err_assert: + reset_control_assert(priv->rstc); + return ret; +} + +static const struct of_device_id rz_mtu3_of_match[] = { + { .compatible = "renesas,rz-mtu3", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rz_mtu3_of_match); + +static struct platform_driver rz_mtu3_driver = { + .probe = rz_mtu3_probe, + .driver = { + .name = "rz-mtu3", + .of_match_table = rz_mtu3_of_match, + }, +}; +module_platform_driver(rz_mtu3_driver); + +MODULE_AUTHOR("Biju Das "); +MODULE_DESCRIPTION("Renesas RZ/G2L MTU3a Core Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/rz-mtu3.h b/drivers/mfd/rz-mtu3.h new file mode 100644 index 000000000000..51a1298b0613 --- /dev/null +++ b/drivers/mfd/rz-mtu3.h @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * MFD internals for Renesas RZ/G2L MTU3 Core driver + * + * Copyright (C) 2023 Renesas Electronics Corporation + */ + +#ifndef RZ_MTU3_MFD_H +#define RZ_MTU3_MFD_H + +#define MTU_8BIT_CH_0(_tier, _nfcr, _tcr, _tcr2, _tmdr1, _tiorh, _tiorl, _tbtm) \ + { \ + [RZ_MTU3_TIER] = _tier, \ + [RZ_MTU3_NFCR] = _nfcr, \ + [RZ_MTU3_TCR] = _tcr, \ + [RZ_MTU3_TCR2] = _tcr2, \ + [RZ_MTU3_TMDR1] = _tmdr1, \ + [RZ_MTU3_TIORH] = _tiorh, \ + [RZ_MTU3_TIORL] = _tiorl, \ + [RZ_MTU3_TBTM] = _tbtm \ + } + +#define MTU_8BIT_CH_1_2(_tier, _nfcr, _tsr, _tcr, _tcr2, _tmdr1, _tior) \ + { \ + [RZ_MTU3_TIER] = _tier, \ + [RZ_MTU3_NFCR] = _nfcr, \ + [RZ_MTU3_TSR] = _tsr, \ + [RZ_MTU3_TCR] = _tcr, \ + [RZ_MTU3_TCR2] = _tcr2, \ + [RZ_MTU3_TMDR1] = _tmdr1, \ + [RZ_MTU3_TIOR] = _tior \ + } \ + +#define MTU_8BIT_CH_3_4_6_7(_tier, _nfcr, _tsr, _tcr, _tcr2, _tmdr1, _tiorh, _tiorl, _tbtm) \ + { \ + [RZ_MTU3_TIER] = _tier, \ + [RZ_MTU3_NFCR] = _nfcr, \ + [RZ_MTU3_TSR] = _tsr, \ + [RZ_MTU3_TCR] = _tcr, \ + [RZ_MTU3_TCR2] = _tcr2, \ + [RZ_MTU3_TMDR1] = _tmdr1, \ + [RZ_MTU3_TIORH] = _tiorh, \ + [RZ_MTU3_TIORL] = _tiorl, \ + [RZ_MTU3_TBTM] = _tbtm \ + } \ + +#define MTU_8BIT_CH_5(_tier, _nfcr, _tstr, _tcntcmpclr, _tcru, _tcr2u, _tioru, \ + _tcrv, _tcr2v, _tiorv, _tcrw, _tcr2w, _tiorw) \ + { \ + [RZ_MTU3_TIER] = _tier, \ + [RZ_MTU3_NFCR] = _nfcr, \ + [RZ_MTU3_TSTR] = _tstr, \ + [RZ_MTU3_TCNTCMPCLR] = _tcntcmpclr, \ + [RZ_MTU3_TCRU] = _tcru, \ + [RZ_MTU3_TCR2U] = _tcr2u, \ + [RZ_MTU3_TIORU] = _tioru, \ + [RZ_MTU3_TCRV] = _tcrv, \ + [RZ_MTU3_TCR2V] = _tcr2v, \ + [RZ_MTU3_TIORV] = _tiorv, \ + [RZ_MTU3_TCRW] = _tcrw, \ + [RZ_MTU3_TCR2W] = _tcr2w, \ + [RZ_MTU3_TIORW] = _tiorw \ + } \ + +#define MTU_8BIT_CH_8(_tier, _nfcr, _tcr, _tcr2, _tmdr1, _tiorh, _tiorl) \ + { \ + [RZ_MTU3_TIER] = _tier, \ + [RZ_MTU3_NFCR] = _nfcr, \ + [RZ_MTU3_TCR] = _tcr, \ + [RZ_MTU3_TCR2] = _tcr2, \ + [RZ_MTU3_TMDR1] = _tmdr1, \ + [RZ_MTU3_TIORH] = _tiorh, \ + [RZ_MTU3_TIORL] = _tiorl \ + } \ + +#define MTU_16BIT_CH_0(_tcnt, _tgra, _tgrb, _tgrc, _tgrd, _tgre, _tgrf) \ + { \ + [RZ_MTU3_TCNT] = _tcnt, \ + [RZ_MTU3_TGRA] = _tgra, \ + [RZ_MTU3_TGRB] = _tgrb, \ + [RZ_MTU3_TGRC] = _tgrc, \ + [RZ_MTU3_TGRD] = _tgrd, \ + [RZ_MTU3_TGRE] = _tgre, \ + [RZ_MTU3_TGRF] = _tgrf \ + } + +#define MTU_16BIT_CH_1_2(_tcnt, _tgra, _tgrb) \ + { \ + [RZ_MTU3_TCNT] = _tcnt, \ + [RZ_MTU3_TGRA] = _tgra, \ + [RZ_MTU3_TGRB] = _tgrb \ + } + +#define MTU_16BIT_CH_3_6(_tcnt, _tgra, _tgrb, _tgrc, _tgrd, _tgre) \ + { \ + [RZ_MTU3_TCNT] = _tcnt, \ + [RZ_MTU3_TGRA] = _tgra, \ + [RZ_MTU3_TGRB] = _tgrb, \ + [RZ_MTU3_TGRC] = _tgrc, \ + [RZ_MTU3_TGRD] = _tgrd, \ + [RZ_MTU3_TGRE] = _tgre \ + } + +#define MTU_16BIT_CH_4_7(_tcnt, _tgra, _tgrb, _tgrc, _tgrd, _tgre, _tgrf, \ + _tadcr, _tadcora, _tadcorb, _tadcobra, _tadcobrb) \ + { \ + [RZ_MTU3_TCNT] = _tcnt, \ + [RZ_MTU3_TGRA] = _tgra, \ + [RZ_MTU3_TGRB] = _tgrb, \ + [RZ_MTU3_TGRC] = _tgrc, \ + [RZ_MTU3_TGRD] = _tgrd, \ + [RZ_MTU3_TGRE] = _tgre, \ + [RZ_MTU3_TGRF] = _tgrf, \ + [RZ_MTU3_TADCR] = _tadcr, \ + [RZ_MTU3_TADCORA] = _tadcora, \ + [RZ_MTU3_TADCORB] = _tadcorb, \ + [RZ_MTU3_TADCOBRA] = _tadcobra, \ + [RZ_MTU3_TADCOBRB] = _tadcobrb \ + } + +#define MTU_16BIT_CH_5(_tcntu, _tgru, _tcntv, _tgrv, _tcntw, _tgrw) \ + { \ + [RZ_MTU3_TCNTU] = _tcntu, \ + [RZ_MTU3_TGRU] = _tgru, \ + [RZ_MTU3_TCNTV] = _tcntv, \ + [RZ_MTU3_TGRV] = _tgrv, \ + [RZ_MTU3_TCNTW] = _tcntw, \ + [RZ_MTU3_TGRW] = _tgrw \ + } + +#define MTU_32BIT_CH_1(_tcntlw, _tgralw, _tgrblw) \ + { \ + [RZ_MTU3_TCNTLW] = _tcntlw, \ + [RZ_MTU3_TGRALW] = _tgralw, \ + [RZ_MTU3_TGRBLW] = _tgrblw \ + } + +#define MTU_32BIT_CH_8(_tcnt, _tgra, _tgrb, _tgrc, _tgrd) \ + { \ + [RZ_MTU3_TCNT] = _tcnt, \ + [RZ_MTU3_TGRA] = _tgra, \ + [RZ_MTU3_TGRB] = _tgrb, \ + [RZ_MTU3_TGRC] = _tgrc, \ + [RZ_MTU3_TGRD] = _tgrd \ + } + +#endif diff --git a/include/linux/mfd/rz-mtu3.h b/include/linux/mfd/rz-mtu3.h new file mode 100644 index 000000000000..c5173bc06270 --- /dev/null +++ b/include/linux/mfd/rz-mtu3.h @@ -0,0 +1,257 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 Renesas Electronics Corporation + */ +#ifndef __MFD_RZ_MTU3_H__ +#define __MFD_RZ_MTU3_H__ + +#include +#include +#include + +/* 8-bit shared register offsets macros */ +#define RZ_MTU3_TSTRA 0x080 /* Timer start register A */ +#define RZ_MTU3_TSTRB 0x880 /* Timer start register B */ + +/* 16-bit shared register offset macros */ +#define RZ_MTU3_TDDRA 0x016 /* Timer dead time data register A */ +#define RZ_MTU3_TDDRB 0x816 /* Timer dead time data register B */ +#define RZ_MTU3_TCDRA 0x014 /* Timer cycle data register A */ +#define RZ_MTU3_TCDRB 0x814 /* Timer cycle data register B */ +#define RZ_MTU3_TCBRA 0x022 /* Timer cycle buffer register A */ +#define RZ_MTU3_TCBRB 0x822 /* Timer cycle buffer register B */ +#define RZ_MTU3_TCNTSA 0x020 /* Timer subcounter A */ +#define RZ_MTU3_TCNTSB 0x820 /* Timer subcounter B */ + +/* + * MTU5 contains 3 timer counter registers and is totaly different + * from other channels, so we must separate its offset + */ + +/* 8-bit register offset macros of MTU3 channels except MTU5 */ +#define RZ_MTU3_TIER 0 /* Timer interrupt register */ +#define RZ_MTU3_NFCR 1 /* Noise filter control register */ +#define RZ_MTU3_TSR 2 /* Timer status register */ +#define RZ_MTU3_TCR 3 /* Timer control register */ +#define RZ_MTU3_TCR2 4 /* Timer control register 2 */ + +/* Timer mode register 1 */ +#define RZ_MTU3_TMDR1 5 +#define RZ_MTU3_TMDR1_MD GENMASK(3, 0) +#define RZ_MTU3_TMDR1_MD_NORMAL FIELD_PREP(RZ_MTU3_TMDR1_MD, 0) +#define RZ_MTU3_TMDR1_MD_PWMMODE1 FIELD_PREP(RZ_MTU3_TMDR1_MD, 2) + +#define RZ_MTU3_TIOR 6 /* Timer I/O control register */ +#define RZ_MTU3_TIORH 6 /* Timer I/O control register H */ +#define RZ_MTU3_TIORL 7 /* Timer I/O control register L */ +/* Only MTU3/4/6/7 have TBTM registers */ +#define RZ_MTU3_TBTM 8 /* Timer buffer operation transfer mode register */ + +/* 8-bit MTU5 register offset macros */ +#define RZ_MTU3_TSTR 2 /* MTU5 Timer start register */ +#define RZ_MTU3_TCNTCMPCLR 3 /* MTU5 Timer compare match clear register */ +#define RZ_MTU3_TCRU 4 /* Timer control register U */ +#define RZ_MTU3_TCR2U 5 /* Timer control register 2U */ +#define RZ_MTU3_TIORU 6 /* Timer I/O control register U */ +#define RZ_MTU3_TCRV 7 /* Timer control register V */ +#define RZ_MTU3_TCR2V 8 /* Timer control register 2V */ +#define RZ_MTU3_TIORV 9 /* Timer I/O control register V */ +#define RZ_MTU3_TCRW 10 /* Timer control register W */ +#define RZ_MTU3_TCR2W 11 /* Timer control register 2W */ +#define RZ_MTU3_TIORW 12 /* Timer I/O control register W */ + +/* 16-bit register offset macros of MTU3 channels except MTU5 */ +#define RZ_MTU3_TCNT 0 /* Timer counter */ +#define RZ_MTU3_TGRA 1 /* Timer general register A */ +#define RZ_MTU3_TGRB 2 /* Timer general register B */ +#define RZ_MTU3_TGRC 3 /* Timer general register C */ +#define RZ_MTU3_TGRD 4 /* Timer general register D */ +#define RZ_MTU3_TGRE 5 /* Timer general register E */ +#define RZ_MTU3_TGRF 6 /* Timer general register F */ +/* Timer A/D converter start request registers */ +#define RZ_MTU3_TADCR 7 /* control register */ +#define RZ_MTU3_TADCORA 8 /* cycle set register A */ +#define RZ_MTU3_TADCORB 9 /* cycle set register B */ +#define RZ_MTU3_TADCOBRA 10 /* cycle set buffer register A */ +#define RZ_MTU3_TADCOBRB 11 /* cycle set buffer register B */ + +/* 16-bit MTU5 register offset macros */ +#define RZ_MTU3_TCNTU 0 /* MTU5 Timer counter U */ +#define RZ_MTU3_TGRU 1 /* MTU5 Timer general register U */ +#define RZ_MTU3_TCNTV 2 /* MTU5 Timer counter V */ +#define RZ_MTU3_TGRV 3 /* MTU5 Timer general register V */ +#define RZ_MTU3_TCNTW 4 /* MTU5 Timer counter W */ +#define RZ_MTU3_TGRW 5 /* MTU5 Timer general register W */ + +/* 32-bit register offset */ +#define RZ_MTU3_TCNTLW 0 /* Timer longword counter */ +#define RZ_MTU3_TGRALW 1 /* Timer longword general register A */ +#define RZ_MTU3_TGRBLW 2 /* Timer longowrd general register B */ + +#define RZ_MTU3_TMDR3 0x191 /* MTU1 Timer Mode Register 3 */ + +/* Macros for setting registers */ +#define RZ_MTU3_TCR_CCLR GENMASK(7, 5) +#define RZ_MTU3_TCR_CKEG GENMASK(4, 3) +#define RZ_MTU3_TCR_TPCS GENMASK(2, 0) +#define RZ_MTU3_TCR_CCLR_TGRA BIT(5) +#define RZ_MTU3_TCR_CCLR_TGRC FIELD_PREP(RZ_MTU3_TCR_CCLR, 5) +#define RZ_MTU3_TCR_CKEG_RISING FIELD_PREP(RZ_MTU3_TCR_CKEG, 0) + +#define RZ_MTU3_TIOR_IOB GENMASK(7, 4) +#define RZ_MTU3_TIOR_IOA GENMASK(3, 0) +#define RZ_MTU3_TIOR_OC_RETAIN 0 +#define RZ_MTU3_TIOR_OC_INIT_OUT_LO_HI_OUT 2 +#define RZ_MTU3_TIOR_OC_INIT_OUT_HI_TOGGLE_OUT 7 + +#define RZ_MTU3_TIOR_OC_IOA_H_COMP_MATCH \ + FIELD_PREP(RZ_MTU3_TIOR_IOA, RZ_MTU3_TIOR_OC_INIT_OUT_LO_HI_OUT) +#define RZ_MTU3_TIOR_OC_IOB_TOGGLE \ + FIELD_PREP(RZ_MTU3_TIOR_IOB, RZ_MTU3_TIOR_OC_INIT_OUT_HI_TOGGLE_OUT) + +enum rz_mtu3_channels { + RZ_MTU3_CHAN_0, + RZ_MTU3_CHAN_1, + RZ_MTU3_CHAN_2, + RZ_MTU3_CHAN_3, + RZ_MTU3_CHAN_4, + RZ_MTU3_CHAN_5, + RZ_MTU3_CHAN_6, + RZ_MTU3_CHAN_7, + RZ_MTU3_CHAN_8, + RZ_MTU_NUM_CHANNELS +}; + +/** + * struct rz_mtu3_channel - MTU3 channel private data + * + * @dev: device handle + * @channel_number: channel number + * @lock: Lock to protect channel state + * @is_busy: channel state + */ +struct rz_mtu3_channel { + struct device *dev; + unsigned int channel_number; + struct mutex lock; + bool is_busy; +}; + +/** + * struct rz_mtu3 - MTU3 core private data + * + * @clk: MTU3 module clock + * @rz_mtu3_channel: HW channels + * @priv_data: MTU3 core driver private data + */ +struct rz_mtu3 { + struct clk *clk; + struct rz_mtu3_channel channels[RZ_MTU_NUM_CHANNELS]; + + void *priv_data; +}; + +#if IS_ENABLED(CONFIG_RZ_MTU3) +static inline bool rz_mtu3_request_channel(struct rz_mtu3_channel *ch) +{ + mutex_lock(&ch->lock); + if (ch->is_busy) { + mutex_unlock(&ch->lock); + return false; + } + + ch->is_busy = true; + mutex_unlock(&ch->lock); + + return true; +} + +static inline void rz_mtu3_release_channel(struct rz_mtu3_channel *ch) +{ + mutex_lock(&ch->lock); + ch->is_busy = false; + mutex_unlock(&ch->lock); +} + +bool rz_mtu3_is_enabled(struct rz_mtu3_channel *ch); +void rz_mtu3_disable(struct rz_mtu3_channel *ch); +int rz_mtu3_enable(struct rz_mtu3_channel *ch); + +u8 rz_mtu3_8bit_ch_read(struct rz_mtu3_channel *ch, u16 off); +u16 rz_mtu3_16bit_ch_read(struct rz_mtu3_channel *ch, u16 off); +u32 rz_mtu3_32bit_ch_read(struct rz_mtu3_channel *ch, u16 off); +u16 rz_mtu3_shared_reg_read(struct rz_mtu3_channel *ch, u16 off); + +void rz_mtu3_8bit_ch_write(struct rz_mtu3_channel *ch, u16 off, u8 val); +void rz_mtu3_16bit_ch_write(struct rz_mtu3_channel *ch, u16 off, u16 val); +void rz_mtu3_32bit_ch_write(struct rz_mtu3_channel *ch, u16 off, u32 val); +void rz_mtu3_shared_reg_write(struct rz_mtu3_channel *ch, u16 off, u16 val); +void rz_mtu3_shared_reg_update_bit(struct rz_mtu3_channel *ch, u16 off, + u16 pos, u8 val); +#else +static inline bool rz_mtu3_request_channel(struct rz_mtu3_channel *ch) +{ + return false; +} + +static inline void rz_mtu3_release_channel(struct rz_mtu3_channel *ch) +{ +} + +static inline bool rz_mtu3_is_enabled(struct rz_mtu3_channel *ch) +{ + return false; +} + +static inline void rz_mtu3_disable(struct rz_mtu3_channel *ch) +{ +} + +static inline int rz_mtu3_enable(struct rz_mtu3_channel *ch) +{ + return 0; +} + +static inline u8 rz_mtu3_8bit_ch_read(struct rz_mtu3_channel *ch, u16 off) +{ + return 0; +} + +static inline u16 rz_mtu3_16bit_ch_read(struct rz_mtu3_channel *ch, u16 off) +{ + return 0; +} + +static inline u32 rz_mtu3_32bit_ch_read(struct rz_mtu3_channel *ch, u16 off) +{ + return 0; +} + +static inline u16 rz_mtu3_shared_reg_read(struct rz_mtu3_channel *ch, u16 off) +{ + return 0; +} + +static inline void rz_mtu3_8bit_ch_write(struct rz_mtu3_channel *ch, u16 off, u8 val) +{ +} + +static inline void rz_mtu3_16bit_ch_write(struct rz_mtu3_channel *ch, u16 off, u16 val) +{ +} + +static inline void rz_mtu3_32bit_ch_write(struct rz_mtu3_channel *ch, u16 off, u32 val) +{ +} + +static inline void rz_mtu3_shared_reg_write(struct rz_mtu3_channel *ch, u16 off, u16 val) +{ +} + +static inline void rz_mtu3_shared_reg_update_bit(struct rz_mtu3_channel *ch, + u16 off, u16 pos, u8 val) +{ +} +#endif + +#endif /* __MFD_RZ_MTU3_H__ */ -- cgit v1.2.3 From e0f8ad2a705367518b5c56bf9d6da89681467c02 Mon Sep 17 00:00:00 2001 From: Shengyu Qu Date: Fri, 21 Apr 2023 23:08:15 +0800 Subject: 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 Reviewed-by: Krzysztof Kozlowski Signed-off-by: Lee Jones 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(+) (limited to 'include/linux') diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c index f49fbd307958..b4f5cb457117 100644 --- a/drivers/mfd/axp20x-i2c.c +++ b/drivers/mfd/axp20x-i2c.c @@ -65,6 +65,7 @@ static const struct of_device_id axp20x_i2c_of_match[] = { { .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); @@ -78,6 +79,7 @@ static const struct i2c_device_id axp20x_i2c_id[] = { { "axp223", 0 }, { "axp803", 0 }, { "axp806", 0 }, + { "axp15060", 0 }, { }, }; MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id); diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index 7720ac15c7d4..72b87aae60cc 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -43,6 +43,7 @@ static const char * const axp20x_model_names[] = { "AXP806", "AXP809", "AXP813", + "AXP15060", }; static const struct regmap_range axp152_writeable_ranges[] = { @@ -169,6 +170,31 @@ static const struct regmap_access_table axp806_volatile_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_resources[] = { 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_regmap_config = { .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_regmap_irqs[] = { 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, @@ -582,6 +639,17 @@ static const struct regmap_irq_chip axp809_regmap_irq_chip = { .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", @@ -826,6 +894,23 @@ static const struct mfd_cell axp813_cells[] = { }, }; +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; @@ -935,6 +1020,28 @@ int axp20x_match_device(struct axp20x_dev *axp20x) */ 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; diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h index 2058194807bd..beb3f44f85c5 100644 --- 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; -- cgit v1.2.3