diff options
author | Lee Jones <lee.jones@linaro.org> | 2020-01-24 08:33:25 +0100 |
---|---|---|
committer | Lee Jones <lee.jones@linaro.org> | 2020-01-24 08:33:25 +0100 |
commit | 18490cdb9e321a62a9c2cac6fb506843cbc84926 (patch) | |
tree | 3ffd3ca1b009e14c2d089311922034b7a04ce436 /drivers | |
parent | mfd: atmel-hlcdc: Return in case of error (diff) | |
parent | gpio: bd71828: Initial support for ROHM BD71828 PMIC GPIOs (diff) | |
download | linux-18490cdb9e321a62a9c2cac6fb506843cbc84926.tar.xz linux-18490cdb9e321a62a9c2cac6fb506843cbc84926.zip |
Merge branches 'ib-mfd-drm-5.6' and 'ib-mfd-clk-gpio-regulator-rtc-5.6' into ibs-for-mfd-merged
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/Kconfig | 6 | ||||
-rw-r--r-- | drivers/clk/clk-bd718x7.c | 50 | ||||
-rw-r--r-- | drivers/gpio/Kconfig | 12 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpio/gpio-bd71828.c | 159 | ||||
-rw-r--r-- | drivers/mfd/Kconfig | 15 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 1 | ||||
-rw-r--r-- | drivers/mfd/rohm-bd70528.c | 3 | ||||
-rw-r--r-- | drivers/mfd/rohm-bd71828.c | 344 | ||||
-rw-r--r-- | drivers/mfd/rohm-bd718x7.c | 43 | ||||
-rw-r--r-- | drivers/regulator/Kconfig | 4 | ||||
-rw-r--r-- | drivers/regulator/Makefile | 1 | ||||
-rw-r--r-- | drivers/regulator/bd718x7-regulator.c | 200 | ||||
-rw-r--r-- | drivers/regulator/rohm-regulator.c | 95 | ||||
-rw-r--r-- | drivers/rtc/Kconfig | 3 | ||||
-rw-r--r-- | drivers/rtc/rtc-bd70528.c | 220 |
16 files changed, 960 insertions, 197 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 45653a0e6ecd..ac5981ce2477 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -305,10 +305,10 @@ config COMMON_CLK_MMP2 Support for Marvell MMP2 and MMP3 SoC clocks config COMMON_CLK_BD718XX - tristate "Clock driver for ROHM BD718x7 PMIC" - depends on MFD_ROHM_BD718XX || MFD_ROHM_BD70528 + tristate "Clock driver for 32K clk gates on ROHM PMICs" + depends on MFD_ROHM_BD718XX || MFD_ROHM_BD70528 || MFD_ROHM_BD71828 help - This driver supports ROHM BD71837, ROHM BD71847 and + This driver supports ROHM BD71837, ROHM BD71847, ROHM BD71828 and ROHM BD70528 PMICs clock gates. config COMMON_CLK_FIXED_MMIO diff --git a/drivers/clk/clk-bd718x7.c b/drivers/clk/clk-bd718x7.c index 00926c587390..b52e8d6f660c 100644 --- a/drivers/clk/clk-bd718x7.c +++ b/drivers/clk/clk-bd718x7.c @@ -7,12 +7,25 @@ #include <linux/err.h> #include <linux/platform_device.h> #include <linux/slab.h> -#include <linux/mfd/rohm-bd718x7.h> -#include <linux/mfd/rohm-bd70528.h> +#include <linux/mfd/rohm-generic.h> #include <linux/clk-provider.h> #include <linux/clkdev.h> #include <linux/regmap.h> +/* clk control registers */ +/* BD70528 */ +#define BD70528_REG_OUT32K 0x2c +/* BD71828 */ +#define BD71828_REG_OUT32K 0x4B +/* BD71837 and BD71847 */ +#define BD718XX_REG_OUT32K 0x2E + +/* + * BD71837, BD71847, BD70528 and BD71828 all use bit [0] to clk output control + */ +#define CLK_OUT_EN_MASK BIT(0) + + struct bd718xx_clk { struct clk_hw hw; u8 reg; @@ -21,10 +34,8 @@ struct bd718xx_clk { struct rohm_regmap_dev *mfd; }; -static int bd71837_clk_set(struct clk_hw *hw, int status) +static int bd71837_clk_set(struct bd718xx_clk *c, unsigned int status) { - struct bd718xx_clk *c = container_of(hw, struct bd718xx_clk, hw); - return regmap_update_bits(c->mfd->regmap, c->reg, c->mask, status); } @@ -33,14 +44,16 @@ static void bd71837_clk_disable(struct clk_hw *hw) int rv; struct bd718xx_clk *c = container_of(hw, struct bd718xx_clk, hw); - rv = bd71837_clk_set(hw, 0); + rv = bd71837_clk_set(c, 0); if (rv) dev_dbg(&c->pdev->dev, "Failed to disable 32K clk (%d)\n", rv); } static int bd71837_clk_enable(struct clk_hw *hw) { - return bd71837_clk_set(hw, 1); + struct bd718xx_clk *c = container_of(hw, struct bd718xx_clk, hw); + + return bd71837_clk_set(c, 0xffffffff); } static int bd71837_clk_is_enabled(struct clk_hw *hw) @@ -74,6 +87,7 @@ static int bd71837_clk_probe(struct platform_device *pdev) .name = "bd718xx-32k-out", .ops = &bd71837_clk_ops, }; + enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data; c = devm_kzalloc(&pdev->dev, sizeof(*c), GFP_KERNEL); if (!c) @@ -87,15 +101,19 @@ static int bd71837_clk_probe(struct platform_device *pdev) dev_err(&pdev->dev, "No parent clk found\n"); return -EINVAL; } - switch (mfd->chip_type) { + switch (chip) { case ROHM_CHIP_TYPE_BD71837: case ROHM_CHIP_TYPE_BD71847: c->reg = BD718XX_REG_OUT32K; - c->mask = BD718XX_OUT32K_EN; + c->mask = CLK_OUT_EN_MASK; + break; + case ROHM_CHIP_TYPE_BD71828: + c->reg = BD71828_REG_OUT32K; + c->mask = CLK_OUT_EN_MASK; break; case ROHM_CHIP_TYPE_BD70528: - c->reg = BD70528_REG_CLK_OUT; - c->mask = BD70528_CLK_OUT_EN_MASK; + c->reg = BD70528_REG_OUT32K; + c->mask = CLK_OUT_EN_MASK; break; default: dev_err(&pdev->dev, "Unknown clk chip\n"); @@ -121,11 +139,21 @@ static int bd71837_clk_probe(struct platform_device *pdev) return rval; } +static const struct platform_device_id bd718x7_clk_id[] = { + { "bd71837-clk", ROHM_CHIP_TYPE_BD71837 }, + { "bd71847-clk", ROHM_CHIP_TYPE_BD71847 }, + { "bd70528-clk", ROHM_CHIP_TYPE_BD70528 }, + { "bd71828-clk", ROHM_CHIP_TYPE_BD71828 }, + { }, +}; +MODULE_DEVICE_TABLE(platform, bd718x7_clk_id); + static struct platform_driver bd71837_clk = { .driver = { .name = "bd718xx-clk", }, .probe = bd71837_clk_probe, + .id_table = bd718x7_clk_id, }; module_platform_driver(bd71837_clk); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 8adffd42f8cb..68adc1b94dda 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1021,6 +1021,18 @@ config GPIO_BD70528 This driver can also be built as a module. If so, the module will be called gpio-bd70528. +config GPIO_BD71828 + tristate "ROHM BD71828 GPIO support" + depends on MFD_ROHM_BD71828 + help + Support for GPIOs on ROHM BD71828 PMIC. There are three GPIOs + available on the ROHM PMIC in total. The GPIOs are limited to + outputs only and pins must be configured to GPIO outputs by + OTP. Enable this only if you want to use these pins as outputs. + + This driver can also be built as a module. If so, the module + will be called gpio-bd71828. + config GPIO_BD9571MWV tristate "ROHM BD9571 GPIO support" depends on MFD_BD9571MWV diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 34eb8b2b12dd..8629b81b5c17 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o obj-$(CONFIG_GPIO_BCM_XGS_IPROC) += gpio-xgs-iproc.o obj-$(CONFIG_GPIO_BD70528) += gpio-bd70528.o +obj-$(CONFIG_GPIO_BD71828) += gpio-bd71828.o obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o diff --git a/drivers/gpio/gpio-bd71828.c b/drivers/gpio/gpio-bd71828.c new file mode 100644 index 000000000000..04aade9e0a4d --- /dev/null +++ b/drivers/gpio/gpio-bd71828.c @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2018 ROHM Semiconductors + +#include <linux/gpio/driver.h> +#include <linux/mfd/rohm-bd71828.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +#define GPIO_OUT_REG(off) (BD71828_REG_GPIO_CTRL1 + (off)) +#define HALL_GPIO_OFFSET 3 + +/* + * These defines can be removed when + * "gpio: Add definition for GPIO direction" + * (9208b1e77d6e8e9776f34f46ef4079ecac9c3c25 in GPIO tree) gets merged, + */ +#ifndef GPIO_LINE_DIRECTION_IN + #define GPIO_LINE_DIRECTION_IN 1 + #define GPIO_LINE_DIRECTION_OUT 0 +#endif + +struct bd71828_gpio { + struct rohm_regmap_dev chip; + struct gpio_chip gpio; +}; + +static void bd71828_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + int ret; + struct bd71828_gpio *bdgpio = gpiochip_get_data(chip); + u8 val = (value) ? BD71828_GPIO_OUT_HI : BD71828_GPIO_OUT_LO; + + /* + * The HALL input pin can only be used as input. If this is the pin + * we are dealing with - then we are done + */ + if (offset == HALL_GPIO_OFFSET) + return; + + ret = regmap_update_bits(bdgpio->chip.regmap, GPIO_OUT_REG(offset), + BD71828_GPIO_OUT_MASK, val); + if (ret) + dev_err(bdgpio->chip.dev, "Could not set gpio to %d\n", value); +} + +static int bd71828_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + int ret; + unsigned int val; + struct bd71828_gpio *bdgpio = gpiochip_get_data(chip); + + if (offset == HALL_GPIO_OFFSET) + ret = regmap_read(bdgpio->chip.regmap, BD71828_REG_IO_STAT, + &val); + else + ret = regmap_read(bdgpio->chip.regmap, GPIO_OUT_REG(offset), + &val); + if (!ret) + ret = (val & BD71828_GPIO_OUT_MASK); + + return ret; +} + +static int bd71828_gpio_set_config(struct gpio_chip *chip, unsigned int offset, + unsigned long config) +{ + struct bd71828_gpio *bdgpio = gpiochip_get_data(chip); + + if (offset == HALL_GPIO_OFFSET) + return -ENOTSUPP; + + switch (pinconf_to_config_param(config)) { + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + return regmap_update_bits(bdgpio->chip.regmap, + GPIO_OUT_REG(offset), + BD71828_GPIO_DRIVE_MASK, + BD71828_GPIO_OPEN_DRAIN); + case PIN_CONFIG_DRIVE_PUSH_PULL: + return regmap_update_bits(bdgpio->chip.regmap, + GPIO_OUT_REG(offset), + BD71828_GPIO_DRIVE_MASK, + BD71828_GPIO_PUSH_PULL); + default: + break; + } + return -ENOTSUPP; +} + +static int bd71828_get_direction(struct gpio_chip *chip, unsigned int offset) +{ + /* + * Pin usage is selected by OTP data. We can't read it runtime. Hence + * we trust that if the pin is not excluded by "gpio-reserved-ranges" + * the OTP configuration is set to OUT. (Other pins but HALL input pin + * on BD71828 can't really be used for general purpose input - input + * states are used for specific cases like regulator control or + * PMIC_ON_REQ. + */ + if (offset == HALL_GPIO_OFFSET) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; +} + +static int bd71828_probe(struct platform_device *pdev) +{ + struct bd71828_gpio *bdgpio; + struct rohm_regmap_dev *bd71828; + + bd71828 = dev_get_drvdata(pdev->dev.parent); + if (!bd71828) { + dev_err(&pdev->dev, "No MFD driver data\n"); + return -EINVAL; + } + + bdgpio = devm_kzalloc(&pdev->dev, sizeof(*bdgpio), + GFP_KERNEL); + if (!bdgpio) + return -ENOMEM; + + bdgpio->chip.dev = &pdev->dev; + bdgpio->gpio.parent = pdev->dev.parent; + bdgpio->gpio.label = "bd71828-gpio"; + bdgpio->gpio.owner = THIS_MODULE; + bdgpio->gpio.get_direction = bd71828_get_direction; + bdgpio->gpio.set_config = bd71828_gpio_set_config; + bdgpio->gpio.can_sleep = true; + bdgpio->gpio.get = bd71828_gpio_get; + bdgpio->gpio.set = bd71828_gpio_set; + bdgpio->gpio.base = -1; + + /* + * See if we need some implementation to mark some PINs as + * not controllable based on DT info or if core can handle + * "gpio-reserved-ranges" and exclude them from control + */ + bdgpio->gpio.ngpio = 4; + bdgpio->gpio.of_node = pdev->dev.parent->of_node; + bdgpio->chip.regmap = bd71828->regmap; + + return devm_gpiochip_add_data(&pdev->dev, &bdgpio->gpio, + bdgpio); +} + +static struct platform_driver bd71828_gpio = { + .driver = { + .name = "bd71828-gpio" + }, + .probe = bd71828_probe, +}; + +module_platform_driver(bd71828_gpio); + +MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); +MODULE_DESCRIPTION("BD71828 voltage regulator driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:bd71828-gpio"); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 420900852166..c3c9432ef51c 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1906,6 +1906,21 @@ config MFD_ROHM_BD70528 10 bits SAR ADC for battery temperature monitor and 1S battery charger. +config MFD_ROHM_BD71828 + tristate "ROHM BD71828 Power Management IC" + depends on I2C=y + depends on OF + select REGMAP_I2C + select REGMAP_IRQ + select MFD_CORE + help + Select this option to get support for the ROHM BD71828 Power + Management IC. BD71828GW is a single-chip power management IC for + battery-powered portable devices. The IC integrates 7 buck + converters, 7 LDOs, and a 1500 mA single-cell linear charger. + Also included is a Coulomb counter, a real-time clock (RTC), and + a 32.768 kHz clock gate. + config MFD_STM32_LPTIMER tristate "Support for STM32 Low-Power Timer" depends on (ARCH_STM32 && OF) || COMPILE_TEST diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index aed99f08739f..61b3093af39d 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -252,6 +252,7 @@ obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o obj-$(CONFIG_MFD_SC27XX_PMIC) += sprd-sc27xx-spi.o obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o obj-$(CONFIG_MFD_ROHM_BD70528) += rohm-bd70528.o +obj-$(CONFIG_MFD_ROHM_BD71828) += rohm-bd71828.o obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o obj-$(CONFIG_MFD_STMFX) += stmfx.o diff --git a/drivers/mfd/rohm-bd70528.c b/drivers/mfd/rohm-bd70528.c index ef6786fd3b00..5c44d3b77b3e 100644 --- a/drivers/mfd/rohm-bd70528.c +++ b/drivers/mfd/rohm-bd70528.c @@ -48,7 +48,7 @@ static struct mfd_cell bd70528_mfd_cells[] = { * We use BD71837 driver to drive the clock block. Only differences to * BD70528 clock gate are the register address and mask. */ - { .name = "bd718xx-clk", }, + { .name = "bd70528-clk", }, { .name = "bd70528-wdt", }, { .name = "bd70528-power", @@ -236,7 +236,6 @@ static int bd70528_i2c_probe(struct i2c_client *i2c, dev_set_drvdata(&i2c->dev, &bd70528->chip); - bd70528->chip.chip_type = ROHM_CHIP_TYPE_BD70528; bd70528->chip.regmap = devm_regmap_init_i2c(i2c, &bd70528_regmap); if (IS_ERR(bd70528->chip.regmap)) { dev_err(&i2c->dev, "Failed to initialize Regmap\n"); diff --git a/drivers/mfd/rohm-bd71828.c b/drivers/mfd/rohm-bd71828.c new file mode 100644 index 000000000000..210261d026f2 --- /dev/null +++ b/drivers/mfd/rohm-bd71828.c @@ -0,0 +1,344 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright (C) 2019 ROHM Semiconductors +// +// ROHM BD71828 PMIC driver + +#include <linux/gpio_keys.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/irq.h> +#include <linux/mfd/core.h> +#include <linux/mfd/rohm-bd71828.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/regmap.h> +#include <linux/types.h> + +static struct gpio_keys_button button = { + .code = KEY_POWER, + .gpio = -1, + .type = EV_KEY, +}; + +static struct gpio_keys_platform_data bd71828_powerkey_data = { + .buttons = &button, + .nbuttons = 1, + .name = "bd71828-pwrkey", +}; + +static const struct resource rtc_irqs[] = { + DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC0, "bd71828-rtc-alm-0"), + DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC1, "bd71828-rtc-alm-1"), + DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC2, "bd71828-rtc-alm-2"), +}; + +static struct mfd_cell bd71828_mfd_cells[] = { + { .name = "bd71828-pmic", }, + { .name = "bd71828-gpio", }, + { .name = "bd71828-led", .of_compatible = "rohm,bd71828-leds" }, + /* + * We use BD71837 driver to drive the clock block. Only differences to + * BD70528 clock gate are the register address and mask. + */ + { .name = "bd71828-clk", }, + { .name = "bd71827-power", }, + { + .name = "bd71828-rtc", + .resources = rtc_irqs, + .num_resources = ARRAY_SIZE(rtc_irqs), + }, { + .name = "gpio-keys", + .platform_data = &bd71828_powerkey_data, + .pdata_size = sizeof(bd71828_powerkey_data), + }, +}; + +static const struct regmap_range volatile_ranges[] = { + { + .range_min = BD71828_REG_PS_CTRL_1, + .range_max = BD71828_REG_PS_CTRL_1, + }, { + .range_min = BD71828_REG_PS_CTRL_3, + .range_max = BD71828_REG_PS_CTRL_3, + }, { + .range_min = BD71828_REG_RTC_SEC, + .range_max = BD71828_REG_RTC_YEAR, + }, { + /* + * For now make all charger registers volatile because many + * needs to be and because the charger block is not that + * performance critical. + */ + .range_min = BD71828_REG_CHG_STATE, + .range_max = BD71828_REG_CHG_FULL, + }, { + .range_min = BD71828_REG_INT_MAIN, + .range_max = BD71828_REG_IO_STAT, + }, +}; + +static const struct regmap_access_table volatile_regs = { + .yes_ranges = &volatile_ranges[0], + .n_yes_ranges = ARRAY_SIZE(volatile_ranges), +}; + +static struct regmap_config bd71828_regmap = { + .reg_bits = 8, + .val_bits = 8, + .volatile_table = &volatile_regs, + .max_register = BD71828_MAX_REGISTER, + .cache_type = REGCACHE_RBTREE, +}; + +/* + * Mapping of main IRQ register bits to sub-IRQ register offsets so that we can + * access corect sub-IRQ registers based on bits that are set in main IRQ + * register. + */ + +static unsigned int bit0_offsets[] = {11}; /* RTC IRQ */ +static unsigned int bit1_offsets[] = {10}; /* TEMP IRQ */ +static unsigned int bit2_offsets[] = {6, 7, 8, 9}; /* BAT MON IRQ */ +static unsigned int bit3_offsets[] = {5}; /* BAT IRQ */ +static unsigned int bit4_offsets[] = {4}; /* CHG IRQ */ +static unsigned int bit5_offsets[] = {3}; /* VSYS IRQ */ +static unsigned int bit6_offsets[] = {1, 2}; /* DCIN IRQ */ +static unsigned int bit7_offsets[] = {0}; /* BUCK IRQ */ + +static struct regmap_irq_sub_irq_map bd71828_sub_irq_offsets[] = { + REGMAP_IRQ_MAIN_REG_OFFSET(bit0_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit1_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit2_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit3_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit4_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit5_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit6_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit7_offsets), +}; + +static struct regmap_irq bd71828_irqs[] = { + REGMAP_IRQ_REG(BD71828_INT_BUCK1_OCP, 0, BD71828_INT_BUCK1_OCP_MASK), + REGMAP_IRQ_REG(BD71828_INT_BUCK2_OCP, 0, BD71828_INT_BUCK2_OCP_MASK), + REGMAP_IRQ_REG(BD71828_INT_BUCK3_OCP, 0, BD71828_INT_BUCK3_OCP_MASK), + REGMAP_IRQ_REG(BD71828_INT_BUCK4_OCP, 0, BD71828_INT_BUCK4_OCP_MASK), + REGMAP_IRQ_REG(BD71828_INT_BUCK5_OCP, 0, BD71828_INT_BUCK5_OCP_MASK), + REGMAP_IRQ_REG(BD71828_INT_BUCK6_OCP, 0, BD71828_INT_BUCK6_OCP_MASK), + REGMAP_IRQ_REG(BD71828_INT_BUCK7_OCP, 0, BD71828_INT_BUCK7_OCP_MASK), + REGMAP_IRQ_REG(BD71828_INT_PGFAULT, 0, BD71828_INT_PGFAULT_MASK), + /* DCIN1 interrupts */ + REGMAP_IRQ_REG(BD71828_INT_DCIN_DET, 1, BD71828_INT_DCIN_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_DCIN_RMV, 1, BD71828_INT_DCIN_RMV_MASK), + REGMAP_IRQ_REG(BD71828_INT_CLPS_OUT, 1, BD71828_INT_CLPS_OUT_MASK), + REGMAP_IRQ_REG(BD71828_INT_CLPS_IN, 1, BD71828_INT_CLPS_IN_MASK), + /* DCIN2 interrupts */ + REGMAP_IRQ_REG(BD71828_INT_DCIN_MON_RES, 2, + BD71828_INT_DCIN_MON_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_DCIN_MON_DET, 2, + BD71828_INT_DCIN_MON_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_LONGPUSH, 2, BD71828_INT_LONGPUSH_MASK), + REGMAP_IRQ_REG(BD71828_INT_MIDPUSH, 2, BD71828_INT_MIDPUSH_MASK), + REGMAP_IRQ_REG(BD71828_INT_SHORTPUSH, 2, BD71828_INT_SHORTPUSH_MASK), + REGMAP_IRQ_REG(BD71828_INT_PUSH, 2, BD71828_INT_PUSH_MASK), + REGMAP_IRQ_REG(BD71828_INT_WDOG, 2, BD71828_INT_WDOG_MASK), + REGMAP_IRQ_REG(BD71828_INT_SWRESET, 2, BD71828_INT_SWRESET_MASK), + /* Vsys */ + REGMAP_IRQ_REG(BD71828_INT_VSYS_UV_RES, 3, + BD71828_INT_VSYS_UV_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_VSYS_UV_DET, 3, + BD71828_INT_VSYS_UV_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_VSYS_LOW_RES, 3, + BD71828_INT_VSYS_LOW_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_VSYS_LOW_DET, 3, + BD71828_INT_VSYS_LOW_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_VSYS_HALL_IN, 3, + BD71828_INT_VSYS_HALL_IN_MASK), + REGMAP_IRQ_REG(BD71828_INT_VSYS_HALL_TOGGLE, 3, + BD71828_INT_VSYS_HALL_TOGGLE_MASK), + REGMAP_IRQ_REG(BD71828_INT_VSYS_MON_RES, 3, + BD71828_INT_VSYS_MON_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_VSYS_MON_DET, 3, + BD71828_INT_VSYS_MON_DET_MASK), + /* Charger */ + REGMAP_IRQ_REG(BD71828_INT_CHG_DCIN_ILIM, 4, + BD71828_INT_CHG_DCIN_ILIM_MASK), + REGMAP_IRQ_REG(BD71828_INT_CHG_TOPOFF_TO_DONE, 4, + BD71828_INT_CHG_TOPOFF_TO_DONE_MASK), + REGMAP_IRQ_REG(BD71828_INT_CHG_WDG_TEMP, 4, + BD71828_INT_CHG_WDG_TEMP_MASK), + REGMAP_IRQ_REG(BD71828_INT_CHG_WDG_TIME, 4, + BD71828_INT_CHG_WDG_TIME_MASK), + REGMAP_IRQ_REG(BD71828_INT_CHG_RECHARGE_RES, 4, + BD71828_INT_CHG_RECHARGE_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_CHG_RECHARGE_DET, 4, + BD71828_INT_CHG_RECHARGE_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_CHG_RANGED_TEMP_TRANSITION, 4, + BD71828_INT_CHG_RANGED_TEMP_TRANSITION_MASK), + REGMAP_IRQ_REG(BD71828_INT_CHG_STATE_TRANSITION, 4, + BD71828_INT_CHG_STATE_TRANSITION_MASK), + /* Battery */ + REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_NORMAL, 5, + BD71828_INT_BAT_TEMP_NORMAL_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_ERANGE, 5, + BD71828_INT_BAT_TEMP_ERANGE_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_WARN, 5, + BD71828_INT_BAT_TEMP_WARN_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_REMOVED, 5, + BD71828_INT_BAT_REMOVED_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_DETECTED, 5, + BD71828_INT_BAT_DETECTED_MASK), + REGMAP_IRQ_REG(BD71828_INT_THERM_REMOVED, 5, + BD71828_INT_THERM_REMOVED_MASK), + REGMAP_IRQ_REG(BD71828_INT_THERM_DETECTED, 5, + BD71828_INT_THERM_DETECTED_MASK), + /* Battery Mon 1 */ + REGMAP_IRQ_REG(BD71828_INT_BAT_DEAD, 6, BD71828_INT_BAT_DEAD_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_SHORTC_RES, 6, + BD71828_INT_BAT_SHORTC_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_SHORTC_DET, 6, + BD71828_INT_BAT_SHORTC_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_LOW_VOLT_RES, 6, + BD71828_INT_BAT_LOW_VOLT_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_LOW_VOLT_DET, 6, + BD71828_INT_BAT_LOW_VOLT_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_VOLT_RES, 6, + BD71828_INT_BAT_OVER_VOLT_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_VOLT_DET, 6, + BD71828_INT_BAT_OVER_VOLT_DET_MASK), + /* Battery Mon 2 */ + REGMAP_IRQ_REG(BD71828_INT_BAT_MON_RES, 7, + BD71828_INT_BAT_MON_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_MON_DET, 7, + BD71828_INT_BAT_MON_DET_MASK), + /* Battery Mon 3 (Coulomb counter) */ + REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON1, 8, + BD71828_INT_BAT_CC_MON1_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON2, 8, + BD71828_INT_BAT_CC_MON2_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON3, 8, + BD71828_INT_BAT_CC_MON3_MASK), + /* Battery Mon 4 */ + REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_1_RES, 9, + BD71828_INT_BAT_OVER_CURR_1_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_1_DET, 9, + BD71828_INT_BAT_OVER_CURR_1_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_2_RES, 9, + BD71828_INT_BAT_OVER_CURR_2_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_2_DET, 9, + BD71828_INT_BAT_OVER_CURR_2_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_3_RES, 9, + BD71828_INT_BAT_OVER_CURR_3_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_3_DET, 9, + BD71828_INT_BAT_OVER_CURR_3_DET_MASK), + /* Temperature */ + REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_LOW_RES, 10, + BD71828_INT_TEMP_BAT_LOW_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_LOW_DET, 10, + BD71828_INT_TEMP_BAT_LOW_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_HI_RES, 10, + BD71828_INT_TEMP_BAT_HI_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_HI_DET, 10, + BD71828_INT_TEMP_BAT_HI_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_TEMP_CHIP_OVER_125_RES, 10, + BD71828_INT_TEMP_CHIP_OVER_125_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_TEMP_CHIP_OVER_125_DET, 10, + BD71828_INT_TEMP_CHIP_OVER_125_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_TEMP_CHIP_OVER_VF_DET, 10, + BD71828_INT_TEMP_CHIP_OVER_VF_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_TEMP_CHIP_OVER_VF_RES, 10, + BD71828_INT_TEMP_CHIP_OVER_VF_RES_MASK), + /* RTC Alarm */ + REGMAP_IRQ_REG(BD71828_INT_RTC0, 11, BD71828_INT_RTC0_MASK), + REGMAP_IRQ_REG(BD71828_INT_RTC1, 11, BD71828_INT_RTC1_MASK), + REGMAP_IRQ_REG(BD71828_INT_RTC2, 11, BD71828_INT_RTC2_MASK), +}; + +static struct regmap_irq_chip bd71828_irq_chip = { + .name = "bd71828_irq", + .main_status = BD71828_REG_INT_MAIN, + .irqs = &bd71828_irqs[0], + .num_irqs = ARRAY_SIZE(bd71828_irqs), + .status_base = BD71828_REG_INT_BUCK, + .mask_base = BD71828_REG_INT_MASK_BUCK, + .ack_base = BD71828_REG_INT_BUCK, + .mask_invert = true, + .init_ack_masked = true, + .num_regs = 12, + .num_main_regs = 1, + .sub_reg_offsets = &bd71828_sub_irq_offsets[0], + .num_main_status_bits = 8, + .irq_reg_stride = 1, +}; + +static int bd71828_i2c_probe(struct i2c_client *i2c) +{ + struct rohm_regmap_dev *chip; + struct regmap_irq_chip_data *irq_data; + int ret; + + if (!i2c->irq) { + dev_err(&i2c->dev, "No IRQ configured\n"); + return -EINVAL; + } + + chip = devm_kzalloc(&i2c->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + dev_set_drvdata(&i2c->dev, chip); + + chip->regmap = devm_regmap_init_i2c(i2c, &bd71828_regmap); + if (IS_ERR(chip->regmap)) { + dev_err(&i2c->dev, "Failed to initialize Regmap\n"); + return PTR_ERR(chip->regmap); + } + + ret = devm_regmap_add_irq_chip(&i2c->dev, chip->regmap, + i2c->irq, IRQF_ONESHOT, 0, + &bd71828_irq_chip, &irq_data); + if (ret) { + dev_err(&i2c->dev, "Failed to add IRQ chip\n"); + return ret; + } + + dev_dbg(&i2c->dev, "Registered %d IRQs for chip\n", + bd71828_irq_chip.num_irqs); + + ret = regmap_irq_get_virq(irq_data, BD71828_INT_SHORTPUSH); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to get the power-key IRQ\n"); + return ret; + } + + button.irq = ret; + + ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, + bd71828_mfd_cells, + ARRAY_SIZE(bd71828_mfd_cells), NULL, 0, + regmap_irq_get_domain(irq_data)); + if (ret) + dev_err(&i2c->dev, "Failed to create subdevices\n"); + + return ret; +} + +static const struct of_device_id bd71828_of_match[] = { + { .compatible = "rohm,bd71828", }, + { }, +}; +MODULE_DEVICE_TABLE(of, bd71828_of_match); + +static struct i2c_driver bd71828_drv = { + .driver = { + .name = "rohm-bd71828", + .of_match_table = bd71828_of_match, + }, + .probe_new = &bd71828_i2c_probe, +}; +module_i2c_driver(bd71828_drv); + +MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); +MODULE_DESCRIPTION("ROHM BD71828 Power Management IC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/rohm-bd718x7.c b/drivers/mfd/rohm-bd718x7.c index 85e7f5133365..c32c1b6c98fa 100644 --- a/drivers/mfd/rohm-bd718x7.c +++ b/drivers/mfd/rohm-bd718x7.c @@ -30,14 +30,24 @@ static struct gpio_keys_platform_data bd718xx_powerkey_data = { .name = "bd718xx-pwrkey", }; -static struct mfd_cell bd718xx_mfd_cells[] = { +static struct mfd_cell bd71837_mfd_cells[] = { { .name = "gpio-keys", .platform_data = &bd718xx_powerkey_data, .pdata_size = sizeof(bd718xx_powerkey_data), }, - { .name = "bd718xx-clk", }, - { .name = "bd718xx-pmic", }, + { .name = "bd71837-clk", }, + { .name = "bd71837-pmic", }, +}; + +static struct mfd_cell bd71847_mfd_cells[] = { + { + .name = "gpio-keys", + .platform_data = &bd718xx_powerkey_data, + .pdata_size = sizeof(bd718xx_powerkey_data), + }, + { .name = "bd71847-clk", }, + { .name = "bd71847-pmic", }, }; static const struct regmap_irq bd718xx_irqs[] = { @@ -124,6 +134,9 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c, { struct bd718xx *bd718xx; int ret; + unsigned int chip_type; + struct mfd_cell *mfd; + int cells; if (!i2c->irq) { dev_err(&i2c->dev, "No IRQ configured\n"); @@ -136,8 +149,21 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c, return -ENOMEM; bd718xx->chip_irq = i2c->irq; - bd718xx->chip.chip_type = (unsigned int)(uintptr_t) - of_device_get_match_data(&i2c->dev); + chip_type = (unsigned int)(uintptr_t) + of_device_get_match_data(&i2c->dev); + switch (chip_type) { + case ROHM_CHIP_TYPE_BD71837: + mfd = bd71837_mfd_cells; + cells = ARRAY_SIZE(bd71837_mfd_cells); + break; + case ROHM_CHIP_TYPE_BD71847: + mfd = bd71847_mfd_cells; + cells = ARRAY_SIZE(bd71847_mfd_cells); + break; + default: + dev_err(&i2c->dev, "Unknown device type"); + return -EINVAL; + } bd718xx->chip.dev = &i2c->dev; dev_set_drvdata(&i2c->dev, bd718xx); @@ -170,8 +196,7 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c, button.irq = ret; ret = devm_mfd_add_devices(bd718xx->chip.dev, PLATFORM_DEVID_AUTO, - bd718xx_mfd_cells, - ARRAY_SIZE(bd718xx_mfd_cells), NULL, 0, + mfd, cells, NULL, 0, regmap_irq_get_domain(bd718xx->irq_data)); if (ret) dev_err(&i2c->dev, "Failed to create subdevices\n"); @@ -188,6 +213,10 @@ static const struct of_device_id bd718xx_of_match[] = { .compatible = "rohm,bd71847", .data = (void *)ROHM_CHIP_TYPE_BD71847, }, + { + .compatible = "rohm,bd71850", + .data = (void *)ROHM_CHIP_TYPE_BD71847, + }, { } }; MODULE_DEVICE_TABLE(of, bd718xx_of_match); diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 74eb5af7295f..a4897ae52f14 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -197,6 +197,7 @@ config REGULATOR_BD70528 config REGULATOR_BD718XX tristate "ROHM BD71837 Power Regulator" depends on MFD_ROHM_BD718XX + select REGULATOR_ROHM help This driver supports voltage regulators on ROHM BD71837 PMIC. This will enable support for the software controllable buck @@ -790,6 +791,9 @@ config REGULATOR_RN5T618 Say y here to support the regulators found on Ricoh RN5T567, RN5T618 or RC5T619 PMIC. +config REGULATOR_ROHM + tristate + config REGULATOR_RT5033 tristate "Richtek RT5033 Regulators" depends on MFD_RT5033 diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 2210ba56f9bd..6bcab72c1fc7 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -99,6 +99,7 @@ obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o obj-$(CONFIG_REGULATOR_RK808) += rk808-regulator.o obj-$(CONFIG_REGULATOR_RN5T618) += rn5t618-regulator.o +obj-$(CONFIG_REGULATOR_ROHM) += rohm-regulator.o obj-$(CONFIG_REGULATOR_RT5033) += rt5033-regulator.o obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o diff --git a/drivers/regulator/bd718x7-regulator.c b/drivers/regulator/bd718x7-regulator.c index 13a43eee2e46..55decb58c777 100644 --- a/drivers/regulator/bd718x7-regulator.c +++ b/drivers/regulator/bd718x7-regulator.c @@ -318,6 +318,7 @@ struct reg_init { }; struct bd718xx_regulator_data { struct regulator_desc desc; + const struct rohm_dvs_config dvs; const struct reg_init init; const struct reg_init *additional_inits; int additional_init_amnt; @@ -349,133 +350,15 @@ static const struct reg_init bd71837_ldo6_inits[] = { }, }; -#define NUM_DVS_BUCKS 4 - -struct of_dvs_setting { - const char *prop; - unsigned int reg; -}; - -static int set_dvs_levels(const struct of_dvs_setting *dvs, - struct device_node *np, - const struct regulator_desc *desc, - struct regmap *regmap) -{ - int ret, i; - unsigned int uv; - - ret = of_property_read_u32(np, dvs->prop, &uv); - if (ret) { - if (ret != -EINVAL) - return ret; - return 0; - } - - for (i = 0; i < desc->n_voltages; i++) { - ret = regulator_desc_list_voltage_linear_range(desc, i); - if (ret < 0) - continue; - if (ret == uv) { - i <<= ffs(desc->vsel_mask) - 1; - ret = regmap_update_bits(regmap, dvs->reg, - DVS_BUCK_RUN_MASK, i); - break; - } - } - return ret; -} - -static int buck4_set_hw_dvs_levels(struct device_node *np, +static int buck_set_hw_dvs_levels(struct device_node *np, const struct regulator_desc *desc, struct regulator_config *cfg) { - int ret, i; - const struct of_dvs_setting dvs[] = { - { - .prop = "rohm,dvs-run-voltage", - .reg = BD71837_REG_BUCK4_VOLT_RUN, - }, - }; + struct bd718xx_regulator_data *data; - for (i = 0; i < ARRAY_SIZE(dvs); i++) { - ret = set_dvs_levels(&dvs[i], np, desc, cfg->regmap); - if (ret) - break; - } - return ret; -} -static int buck3_set_hw_dvs_levels(struct device_node *np, - const struct regulator_desc *desc, - struct regulator_config *cfg) -{ - int ret, i; - const struct of_dvs_setting dvs[] = { - { - .prop = "rohm,dvs-run-voltage", - .reg = BD71837_REG_BUCK3_VOLT_RUN, - }, - }; + data = container_of(desc, struct bd718xx_regulator_data, desc); - for (i = 0; i < ARRAY_SIZE(dvs); i++) { - ret = set_dvs_levels(&dvs[i], np, desc, cfg->regmap); - if (ret) - break; - } - return ret; -} - -static int buck2_set_hw_dvs_levels(struct device_node *np, - const struct regulator_desc *desc, - struct regulator_config *cfg) -{ - int ret, i; - const struct of_dvs_setting dvs[] = { - { - .prop = "rohm,dvs-run-voltage", - .reg = BD718XX_REG_BUCK2_VOLT_RUN, - }, - { - .prop = "rohm,dvs-idle-voltage", - .reg = BD718XX_REG_BUCK2_VOLT_IDLE, - }, - }; - - - - for (i = 0; i < ARRAY_SIZE(dvs); i++) { - ret = set_dvs_levels(&dvs[i], np, desc, cfg->regmap); - if (ret) - break; - } - return ret; -} - -static int buck1_set_hw_dvs_levels(struct device_node *np, - const struct regulator_desc *desc, - struct regulator_config *cfg) -{ - int ret, i; - const struct of_dvs_setting dvs[] = { - { - .prop = "rohm,dvs-run-voltage", - .reg = BD718XX_REG_BUCK1_VOLT_RUN, - }, - { - .prop = "rohm,dvs-idle-voltage", - .reg = BD718XX_REG_BUCK1_VOLT_IDLE, - }, - { - .prop = "rohm,dvs-suspend-voltage", - .reg = BD718XX_REG_BUCK1_VOLT_SUSP, - }, - }; - - for (i = 0; i < ARRAY_SIZE(dvs); i++) { - ret = set_dvs_levels(&dvs[i], np, desc, cfg->regmap); - if (ret) - break; - } - return ret; + return rohm_regulator_set_dvs_levels(&data->dvs, np, desc, cfg->regmap); } static const struct bd718xx_regulator_data bd71847_regulators[] = { @@ -496,7 +379,17 @@ static const struct bd718xx_regulator_data bd71847_regulators[] = { .enable_reg = BD718XX_REG_BUCK1_CTRL, .enable_mask = BD718XX_BUCK_EN, .owner = THIS_MODULE, - .of_parse_cb = buck1_set_hw_dvs_levels, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND, + .run_reg = BD718XX_REG_BUCK1_VOLT_RUN, + .run_mask = DVS_BUCK_RUN_MASK, + .idle_reg = BD718XX_REG_BUCK1_VOLT_IDLE, + .idle_mask = DVS_BUCK_RUN_MASK, + .suspend_reg = BD718XX_REG_BUCK1_VOLT_SUSP, + .suspend_mask = DVS_BUCK_RUN_MASK, }, .init = { .reg = BD718XX_REG_BUCK1_CTRL, @@ -520,7 +413,14 @@ static const struct bd718xx_regulator_data bd71847_regulators[] = { .enable_reg = BD718XX_REG_BUCK2_CTRL, .enable_mask = BD718XX_BUCK_EN, .owner = THIS_MODULE, - .of_parse_cb = buck2_set_hw_dvs_levels, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE, + .run_reg = BD718XX_REG_BUCK2_VOLT_RUN, + .run_mask = DVS_BUCK_RUN_MASK, + .idle_reg = BD718XX_REG_BUCK2_VOLT_IDLE, + .idle_mask = DVS_BUCK_RUN_MASK, }, .init = { .reg = BD718XX_REG_BUCK2_CTRL, @@ -792,7 +692,17 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = { .enable_reg = BD718XX_REG_BUCK1_CTRL, .enable_mask = BD718XX_BUCK_EN, .owner = THIS_MODULE, - .of_parse_cb = buck1_set_hw_dvs_levels, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND, + .run_reg = BD718XX_REG_BUCK1_VOLT_RUN, + .run_mask = DVS_BUCK_RUN_MASK, + .idle_reg = BD718XX_REG_BUCK1_VOLT_IDLE, + .idle_mask = DVS_BUCK_RUN_MASK, + .suspend_reg = BD718XX_REG_BUCK1_VOLT_SUSP, + .suspend_mask = DVS_BUCK_RUN_MASK, }, .init = { .reg = BD718XX_REG_BUCK1_CTRL, @@ -816,7 +726,14 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = { .enable_reg = BD718XX_REG_BUCK2_CTRL, .enable_mask = BD718XX_BUCK_EN, .owner = THIS_MODULE, - .of_parse_cb = buck2_set_hw_dvs_levels, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE, + .run_reg = BD718XX_REG_BUCK2_VOLT_RUN, + .run_mask = DVS_BUCK_RUN_MASK, + .idle_reg = BD718XX_REG_BUCK2_VOLT_IDLE, + .idle_mask = DVS_BUCK_RUN_MASK, }, .init = { .reg = BD718XX_REG_BUCK2_CTRL, @@ -840,7 +757,12 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = { .enable_reg = BD71837_REG_BUCK3_CTRL, .enable_mask = BD718XX_BUCK_EN, .owner = THIS_MODULE, - .of_parse_cb = buck3_set_hw_dvs_levels, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + .level_map = ROHM_DVS_LEVEL_RUN, + .run_reg = BD71837_REG_BUCK3_VOLT_RUN, + .run_mask = DVS_BUCK_RUN_MASK, }, .init = { .reg = BD71837_REG_BUCK3_CTRL, @@ -864,7 +786,12 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = { .enable_reg = BD71837_REG_BUCK4_CTRL, .enable_mask = BD718XX_BUCK_EN, .owner = THIS_MODULE, - .of_parse_cb = buck4_set_hw_dvs_levels, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + .level_map = ROHM_DVS_LEVEL_RUN, + .run_reg = BD71837_REG_BUCK4_VOLT_RUN, + .run_mask = DVS_BUCK_RUN_MASK, }, .init = { .reg = BD71837_REG_BUCK4_CTRL, @@ -1164,6 +1091,7 @@ static int bd718xx_probe(struct platform_device *pdev) int i, j, err; bool use_snvs; + enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data; mfd = dev_get_drvdata(pdev->dev.parent); if (!mfd) { @@ -1172,8 +1100,8 @@ static int bd718xx_probe(struct platform_device *pdev) goto err; } - if (mfd->chip.chip_type >= ROHM_CHIP_TYPE_AMOUNT || - !pmic_regulators[mfd->chip.chip_type].r_datas) { + if (chip >= ROHM_CHIP_TYPE_AMOUNT || chip < 0 || + !pmic_regulators[chip].r_datas) { dev_err(&pdev->dev, "Unsupported chip type\n"); err = -EINVAL; goto err; @@ -1215,13 +1143,13 @@ static int bd718xx_probe(struct platform_device *pdev) } } - for (i = 0; i < pmic_regulators[mfd->chip.chip_type].r_amount; i++) { + for (i = 0; i < pmic_regulators[chip].r_amount; i++) { const struct regulator_desc *desc; struct regulator_dev *rdev; const struct bd718xx_regulator_data *r; - r = &pmic_regulators[mfd->chip.chip_type].r_datas[i]; + r = &pmic_regulators[chip].r_datas[i]; desc = &r->desc; config.dev = pdev->dev.parent; @@ -1281,11 +1209,19 @@ err: return err; } +static const struct platform_device_id bd718x7_pmic_id[] = { + { "bd71837-pmic", ROHM_CHIP_TYPE_BD71837 }, + { "bd71847-pmic", ROHM_CHIP_TYPE_BD71847 }, + { }, +}; +MODULE_DEVICE_TABLE(platform, bd718x7_pmic_id); + static struct platform_driver bd718xx_regulator = { .driver = { .name = "bd718xx-pmic", }, .probe = bd718xx_probe, + .id_table = bd718x7_pmic_id, }; module_platform_driver(bd718xx_regulator); diff --git a/drivers/regulator/rohm-regulator.c b/drivers/regulator/rohm-regulator.c new file mode 100644 index 000000000000..399002383b28 --- /dev/null +++ b/drivers/regulator/rohm-regulator.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2020 ROHM Semiconductors + +#include <linux/errno.h> +#include <linux/mfd/rohm-generic.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> + +static int set_dvs_level(const struct regulator_desc *desc, + struct device_node *np, struct regmap *regmap, + char *prop, unsigned int reg, unsigned int mask, + unsigned int omask, unsigned int oreg) +{ + int ret, i; + uint32_t uv; + + ret = of_property_read_u32(np, prop, &uv); + if (ret) { + if (ret != -EINVAL) + return ret; + return 0; + } + + if (uv == 0) { + if (omask) + return regmap_update_bits(regmap, oreg, omask, 0); + } + for (i = 0; i < desc->n_voltages; i++) { + ret = regulator_desc_list_voltage_linear_range(desc, i); + if (ret < 0) + continue; + if (ret == uv) { + i <<= ffs(desc->vsel_mask) - 1; + ret = regmap_update_bits(regmap, reg, mask, i); + if (omask && !ret) + ret = regmap_update_bits(regmap, oreg, omask, + omask); + break; + } + } + return ret; +} + +int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs, + struct device_node *np, + const struct regulator_desc *desc, + struct regmap *regmap) +{ + int i, ret = 0; + char *prop; + unsigned int reg, mask, omask, oreg = desc->enable_reg; + + for (i = 0; i < ROHM_DVS_LEVEL_MAX && !ret; i++) { + if (dvs->level_map & (1 << i)) { + switch (i + 1) { + case ROHM_DVS_LEVEL_RUN: + prop = "rohm,dvs-run-voltage"; + reg = dvs->run_reg; + mask = dvs->run_mask; + omask = dvs->run_on_mask; + break; + case ROHM_DVS_LEVEL_IDLE: + prop = "rohm,dvs-idle-voltage"; + reg = dvs->idle_reg; + mask = dvs->idle_mask; + omask = dvs->idle_on_mask; + break; + case ROHM_DVS_LEVEL_SUSPEND: + prop = "rohm,dvs-suspend-voltage"; + reg = dvs->suspend_reg; + mask = dvs->suspend_mask; + omask = dvs->suspend_on_mask; + break; + case ROHM_DVS_LEVEL_LPSR: + prop = "rohm,dvs-lpsr-voltage"; + reg = dvs->lpsr_reg; + mask = dvs->lpsr_mask; + omask = dvs->lpsr_on_mask; + break; + default: + return -EINVAL; + } + ret = set_dvs_level(desc, np, regmap, prop, reg, mask, + omask, oreg); + } + } + return ret; +} +EXPORT_SYMBOL(rohm_regulator_set_dvs_levels); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); +MODULE_DESCRIPTION("Generic helpers for ROHM PMIC regulator drivers"); diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index d77515d8382c..df7a3843069d 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -498,12 +498,13 @@ config RTC_DRV_M41T80_WDT help If you say Y here you will get support for the watchdog timer in the ST M41T60 and M41T80 RTC chips series. + config RTC_DRV_BD70528 tristate "ROHM BD70528 PMIC RTC" depends on MFD_ROHM_BD70528 && (BD70528_WATCHDOG || !BD70528_WATCHDOG) help If you say Y here you will get support for the RTC - on ROHM BD70528 Power Management IC. + block on ROHM BD70528 and BD71828 Power Management IC. This driver can also be built as a module. If so, the module will be called rtc-bd70528. diff --git a/drivers/rtc/rtc-bd70528.c b/drivers/rtc/rtc-bd70528.c index 627037aa66a8..bbbb1f07c91f 100644 --- a/drivers/rtc/rtc-bd70528.c +++ b/drivers/rtc/rtc-bd70528.c @@ -6,6 +6,7 @@ #include <linux/bcd.h> #include <linux/mfd/rohm-bd70528.h> +#include <linux/mfd/rohm-bd71828.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> @@ -15,7 +16,7 @@ /* * We read regs RTC_SEC => RTC_YEAR * this struct is ordered according to chip registers. - * Keep it u8 only to avoid padding issues. + * Keep it u8 only (or packed) to avoid padding issues. */ struct bd70528_rtc_day { u8 sec; @@ -36,6 +37,13 @@ struct bd70528_rtc_wake { u8 ctrl; } __packed; +struct bd71828_rtc_alm { + struct bd70528_rtc_data alm0; + struct bd70528_rtc_data alm1; + u8 alm_mask; + u8 alm1_mask; +} __packed; + struct bd70528_rtc_alm { struct bd70528_rtc_data data; u8 alm_mask; @@ -43,8 +51,10 @@ struct bd70528_rtc_alm { } __packed; struct bd70528_rtc { - struct rohm_regmap_dev *mfd; + struct rohm_regmap_dev *parent; struct device *dev; + u8 reg_time_start; + bool has_rtc_timers; }; static int bd70528_set_wake(struct rohm_regmap_dev *bd70528, @@ -123,14 +133,14 @@ static int bd70528_set_rtc_based_timers(struct bd70528_rtc *r, int new_state, { int ret; - ret = bd70528_wdt_set(r->mfd, new_state & BD70528_WDT_STATE_BIT, + ret = bd70528_wdt_set(r->parent, new_state & BD70528_WDT_STATE_BIT, old_state); if (ret) { dev_err(r->dev, "Failed to disable WDG for RTC setting (%d)\n", ret); return ret; } - ret = bd70528_set_elapsed_tmr(r->mfd, + ret = bd70528_set_elapsed_tmr(r->parent, new_state & BD70528_ELAPSED_STATE_BIT, old_state); if (ret) { @@ -138,7 +148,7 @@ static int bd70528_set_rtc_based_timers(struct bd70528_rtc *r, int new_state, "Failed to disable 'elapsed timer' for RTC setting\n"); return ret; } - ret = bd70528_set_wake(r->mfd, new_state & BD70528_WAKE_STATE_BIT, + ret = bd70528_set_wake(r->parent, new_state & BD70528_WAKE_STATE_BIT, old_state); if (ret) { dev_err(r->dev, @@ -152,12 +162,18 @@ static int bd70528_set_rtc_based_timers(struct bd70528_rtc *r, int new_state, static int bd70528_re_enable_rtc_based_timers(struct bd70528_rtc *r, int old_state) { + if (!r->has_rtc_timers) + return 0; + return bd70528_set_rtc_based_timers(r, old_state, NULL); } static int bd70528_disable_rtc_based_timers(struct bd70528_rtc *r, int *old_state) { + if (!r->has_rtc_timers) + return 0; + return bd70528_set_rtc_based_timers(r, 0, old_state); } @@ -213,22 +229,52 @@ static inline void rtc2tm(struct bd70528_rtc_data *r, struct rtc_time *t) t->tm_wday = bcd2bin(r->week & BD70528_MASK_RTC_WEEK); } +static int bd71828_set_alarm(struct device *dev, struct rtc_wkalrm *a) +{ + int ret; + struct bd71828_rtc_alm alm; + struct bd70528_rtc *r = dev_get_drvdata(dev); + struct rohm_regmap_dev *parent = r->parent; + + ret = regmap_bulk_read(parent->regmap, BD71828_REG_RTC_ALM_START, + &alm, sizeof(alm)); + if (ret) { + dev_err(dev, "Failed to read alarm regs\n"); + return ret; + } + + tm2rtc(&a->time, &alm.alm0); + + if (!a->enabled) + alm.alm_mask &= ~BD70528_MASK_ALM_EN; + else + alm.alm_mask |= BD70528_MASK_ALM_EN; + + ret = regmap_bulk_write(parent->regmap, BD71828_REG_RTC_ALM_START, + &alm, sizeof(alm)); + if (ret) + dev_err(dev, "Failed to set alarm time\n"); + + return ret; + +} + static int bd70528_set_alarm(struct device *dev, struct rtc_wkalrm *a) { struct bd70528_rtc_wake wake; struct bd70528_rtc_alm alm; int ret; struct bd70528_rtc *r = dev_get_drvdata(dev); - struct rohm_regmap_dev *bd70528 = r->mfd; + struct rohm_regmap_dev *parent = r->parent; - ret = regmap_bulk_read(bd70528->regmap, BD70528_REG_RTC_WAKE_START, + ret = regmap_bulk_read(parent->regmap, BD70528_REG_RTC_WAKE_START, &wake, sizeof(wake)); if (ret) { dev_err(dev, "Failed to read wake regs\n"); return ret; } - ret = regmap_bulk_read(bd70528->regmap, BD70528_REG_RTC_ALM_START, + ret = regmap_bulk_read(parent->regmap, BD70528_REG_RTC_ALM_START, &alm, sizeof(alm)); if (ret) { dev_err(dev, "Failed to read alarm regs\n"); @@ -246,14 +292,14 @@ static int bd70528_set_alarm(struct device *dev, struct rtc_wkalrm *a) wake.ctrl &= ~BD70528_MASK_WAKE_EN; } - ret = regmap_bulk_write(bd70528->regmap, + ret = regmap_bulk_write(parent->regmap, BD70528_REG_RTC_WAKE_START, &wake, sizeof(wake)); if (ret) { dev_err(dev, "Failed to set wake time\n"); return ret; } - ret = regmap_bulk_write(bd70528->regmap, BD70528_REG_RTC_ALM_START, + ret = regmap_bulk_write(parent->regmap, BD70528_REG_RTC_ALM_START, &alm, sizeof(alm)); if (ret) dev_err(dev, "Failed to set alarm time\n"); @@ -261,14 +307,38 @@ static int bd70528_set_alarm(struct device *dev, struct rtc_wkalrm *a) return ret; } +static int bd71828_read_alarm(struct device *dev, struct rtc_wkalrm *a) +{ + int ret; + struct bd71828_rtc_alm alm; + struct bd70528_rtc *r = dev_get_drvdata(dev); + struct rohm_regmap_dev *parent = r->parent; + + ret = regmap_bulk_read(parent->regmap, BD71828_REG_RTC_ALM_START, + &alm, sizeof(alm)); + if (ret) { + dev_err(dev, "Failed to read alarm regs\n"); + return ret; + } + + rtc2tm(&alm.alm0, &a->time); + a->time.tm_mday = -1; + a->time.tm_mon = -1; + a->time.tm_year = -1; + a->enabled = !!(alm.alm_mask & BD70528_MASK_ALM_EN); + a->pending = 0; + + return 0; +} + static int bd70528_read_alarm(struct device *dev, struct rtc_wkalrm *a) { struct bd70528_rtc_alm alm; int ret; struct bd70528_rtc *r = dev_get_drvdata(dev); - struct rohm_regmap_dev *bd70528 = r->mfd; + struct rohm_regmap_dev *parent = r->parent; - ret = regmap_bulk_read(bd70528->regmap, BD70528_REG_RTC_ALM_START, + ret = regmap_bulk_read(parent->regmap, BD70528_REG_RTC_ALM_START, &alm, sizeof(alm)); if (ret) { dev_err(dev, "Failed to read alarm regs\n"); @@ -290,14 +360,14 @@ static int bd70528_set_time_locked(struct device *dev, struct rtc_time *t) int ret, tmpret, old_states; struct bd70528_rtc_data rtc_data; struct bd70528_rtc *r = dev_get_drvdata(dev); - struct rohm_regmap_dev *bd70528 = r->mfd; + struct rohm_regmap_dev *parent = r->parent; ret = bd70528_disable_rtc_based_timers(r, &old_states); if (ret) return ret; - tmpret = regmap_bulk_read(bd70528->regmap, - BD70528_REG_RTC_START, &rtc_data, + tmpret = regmap_bulk_read(parent->regmap, + r->reg_time_start, &rtc_data, sizeof(rtc_data)); if (tmpret) { dev_err(dev, "Failed to read RTC time registers\n"); @@ -305,8 +375,8 @@ static int bd70528_set_time_locked(struct device *dev, struct rtc_time *t) } tm2rtc(t, &rtc_data); - tmpret = regmap_bulk_write(bd70528->regmap, - BD70528_REG_RTC_START, &rtc_data, + tmpret = regmap_bulk_write(parent->regmap, + r->reg_time_start, &rtc_data, sizeof(rtc_data)); if (tmpret) { dev_err(dev, "Failed to set RTC time\n"); @@ -321,27 +391,32 @@ renable_out: return ret; } +static int bd71828_set_time(struct device *dev, struct rtc_time *t) +{ + return bd70528_set_time_locked(dev, t); +} + static int bd70528_set_time(struct device *dev, struct rtc_time *t) { int ret; struct bd70528_rtc *r = dev_get_drvdata(dev); - bd70528_wdt_lock(r->mfd); + bd70528_wdt_lock(r->parent); ret = bd70528_set_time_locked(dev, t); - bd70528_wdt_unlock(r->mfd); + bd70528_wdt_unlock(r->parent); return ret; } static int bd70528_get_time(struct device *dev, struct rtc_time *t) { struct bd70528_rtc *r = dev_get_drvdata(dev); - struct rohm_regmap_dev *bd70528 = r->mfd; + struct rohm_regmap_dev *parent = r->parent; struct bd70528_rtc_data rtc_data; int ret; /* read the RTC date and time registers all at once */ - ret = regmap_bulk_read(bd70528->regmap, - BD70528_REG_RTC_START, &rtc_data, + ret = regmap_bulk_read(parent->regmap, + r->reg_time_start, &rtc_data, sizeof(rtc_data)); if (ret) { dev_err(dev, "Failed to read RTC time (err %d)\n", ret); @@ -362,19 +437,36 @@ static int bd70528_alm_enable(struct device *dev, unsigned int enabled) if (enabled) enableval = 0; - bd70528_wdt_lock(r->mfd); - ret = bd70528_set_wake(r->mfd, enabled, NULL); + bd70528_wdt_lock(r->parent); + ret = bd70528_set_wake(r->parent, enabled, NULL); if (ret) { dev_err(dev, "Failed to change wake state\n"); goto out_unlock; } - ret = regmap_update_bits(r->mfd->regmap, BD70528_REG_RTC_ALM_MASK, + ret = regmap_update_bits(r->parent->regmap, BD70528_REG_RTC_ALM_MASK, BD70528_MASK_ALM_EN, enableval); if (ret) dev_err(dev, "Failed to change alarm state\n"); out_unlock: - bd70528_wdt_unlock(r->mfd); + bd70528_wdt_unlock(r->parent); + return ret; +} + +static int bd71828_alm_enable(struct device *dev, unsigned int enabled) +{ + int ret; + struct bd70528_rtc *r = dev_get_drvdata(dev); + unsigned int enableval = BD70528_MASK_ALM_EN; + + if (!enabled) + enableval = 0; + + ret = regmap_update_bits(r->parent->regmap, BD71828_REG_RTC_ALM0_MASK, + BD70528_MASK_ALM_EN, enableval); + if (ret) + dev_err(dev, "Failed to change alarm state\n"); + return ret; } @@ -386,6 +478,14 @@ static const struct rtc_class_ops bd70528_rtc_ops = { .alarm_irq_enable = bd70528_alm_enable, }; +static const struct rtc_class_ops bd71828_rtc_ops = { + .read_time = bd70528_get_time, + .set_time = bd71828_set_time, + .read_alarm = bd71828_read_alarm, + .set_alarm = bd71828_set_alarm, + .alarm_irq_enable = bd71828_alm_enable, +}; + static irqreturn_t alm_hndlr(int irq, void *data) { struct rtc_device *rtc = data; @@ -397,14 +497,19 @@ static irqreturn_t alm_hndlr(int irq, void *data) static int bd70528_probe(struct platform_device *pdev) { struct bd70528_rtc *bd_rtc; - struct rohm_regmap_dev *mfd; + const struct rtc_class_ops *rtc_ops; + struct rohm_regmap_dev *parent; + const char *irq_name; int ret; struct rtc_device *rtc; int irq; unsigned int hr; + bool enable_main_irq = false; + u8 hour_reg; + enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data; - mfd = dev_get_drvdata(pdev->dev.parent); - if (!mfd) { + parent = dev_get_drvdata(pdev->dev.parent); + if (!parent) { dev_err(&pdev->dev, "No MFD driver data\n"); return -EINVAL; } @@ -412,16 +517,39 @@ static int bd70528_probe(struct platform_device *pdev) if (!bd_rtc) return -ENOMEM; - bd_rtc->mfd = mfd; + bd_rtc->parent = parent; bd_rtc->dev = &pdev->dev; - irq = platform_get_irq_byname(pdev, "bd70528-rtc-alm"); - if (irq < 0) + switch (chip) { + case ROHM_CHIP_TYPE_BD70528: + irq_name = "bd70528-rtc-alm"; + bd_rtc->has_rtc_timers = true; + bd_rtc->reg_time_start = BD70528_REG_RTC_START; + hour_reg = BD70528_REG_RTC_HOUR; + enable_main_irq = true; + rtc_ops = &bd70528_rtc_ops; + break; + case ROHM_CHIP_TYPE_BD71828: + irq_name = "bd71828-rtc-alm-0"; + bd_rtc->reg_time_start = BD71828_REG_RTC_START; + hour_reg = BD71828_REG_RTC_HOUR; + rtc_ops = &bd71828_rtc_ops; + break; + default: + dev_err(&pdev->dev, "Unknown chip\n"); + return -ENOENT; + } + + irq = platform_get_irq_byname(pdev, irq_name); + + if (irq < 0) { + dev_err(&pdev->dev, "Failed to get irq\n"); return irq; + } platform_set_drvdata(pdev, bd_rtc); - ret = regmap_read(mfd->regmap, BD70528_REG_RTC_HOUR, &hr); + ret = regmap_read(parent->regmap, hour_reg, &hr); if (ret) { dev_err(&pdev->dev, "Failed to reag RTC clock\n"); @@ -431,10 +559,10 @@ static int bd70528_probe(struct platform_device *pdev) if (!(hr & BD70528_MASK_RTC_HOUR_24H)) { struct rtc_time t; - ret = bd70528_get_time(&pdev->dev, &t); + ret = rtc_ops->read_time(&pdev->dev, &t); if (!ret) - ret = bd70528_set_time(&pdev->dev, &t); + ret = rtc_ops->set_time(&pdev->dev, &t); if (ret) { dev_err(&pdev->dev, @@ -454,7 +582,7 @@ static int bd70528_probe(struct platform_device *pdev) rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; rtc->range_max = RTC_TIMESTAMP_END_2099; - rtc->ops = &bd70528_rtc_ops; + rtc->ops = rtc_ops; /* Request alarm IRQ prior to registerig the RTC */ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, &alm_hndlr, @@ -468,27 +596,37 @@ static int bd70528_probe(struct platform_device *pdev) * leave them enabled as irq-controller should disable irqs * from sub-registers when IRQ is disabled or freed. */ - ret = regmap_update_bits(mfd->regmap, + if (enable_main_irq) { + ret = regmap_update_bits(parent->regmap, BD70528_REG_INT_MAIN_MASK, BD70528_INT_RTC_MASK, 0); - if (ret) { - dev_err(&pdev->dev, "Failed to enable RTC interrupts\n"); - return ret; + if (ret) { + dev_err(&pdev->dev, "Failed to enable RTC interrupts\n"); + return ret; + } } return rtc_register_device(rtc); } +static const struct platform_device_id bd718x7_rtc_id[] = { + { "bd70528-rtc", ROHM_CHIP_TYPE_BD70528 }, + { "bd71828-rtc", ROHM_CHIP_TYPE_BD71828 }, + { }, +}; +MODULE_DEVICE_TABLE(platform, bd718x7_rtc_id); + static struct platform_driver bd70528_rtc = { .driver = { .name = "bd70528-rtc" }, .probe = bd70528_probe, + .id_table = bd718x7_rtc_id, }; module_platform_driver(bd70528_rtc); MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); -MODULE_DESCRIPTION("BD70528 RTC driver"); +MODULE_DESCRIPTION("ROHM BD70528 and BD71828 PMIC RTC driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:bd70528-rtc"); |