Commit 18490cdb authored by Lee Jones's avatar Lee Jones

Merge branches 'ib-mfd-drm-5.6' and 'ib-mfd-clk-gpio-regulator-rtc-5.6' into ibs-for-mfd-merged

parents 10f91676 c31f625d
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/leds/rohm,bd71828-leds.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ROHM BD71828 Power Management Integrated Circuit LED driver
maintainers:
- Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
description: |
This module is part of the ROHM BD71828 MFD device. For more details
see Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml.
The LED controller is represented as a sub-node of the PMIC node on the device
tree.
The device has two LED outputs referred as GRNLED and AMBLED in data-sheet.
select: false
properties:
compatible:
const: rohm,bd71828-leds
patternProperties:
"^led-[1-2]$":
type: object
description:
Properties for a single LED.
properties:
#allOf:
#- $ref: "common.yaml#"
rohm,led-compatible:
description: LED identification string
allOf:
- $ref: "/schemas/types.yaml#/definitions/string"
- enum:
- bd71828-ambled
- bd71828-grnled
function:
description:
Purpose of LED as defined in dt-bindings/leds/common.h
$ref: "/schemas/types.yaml#/definitions/string"
color:
description:
LED colour as defined in dt-bindings/leds/common.h
$ref: "/schemas/types.yaml#/definitions/uint32"
required:
- compatible
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/mfd/rohm,bd71828-pmic.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ROHM BD71828 Power Management Integrated Circuit bindings
maintainers:
- Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
description: |
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.
properties:
compatible:
const: rohm,bd71828
reg:
description:
I2C slave address.
maxItems: 1
interrupts:
maxItems: 1
gpio-controller: true
"#gpio-cells":
const: 2
description: |
The first cell is the pin number and the second cell is used to specify
flags. See ../gpio/gpio.txt for more information.
clocks:
maxItems: 1
"#clock-cells":
const: 0
rohm,charger-sense-resistor-ohms:
minimum: 10000000
maximum: 50000000
description: |
BD71827 and BD71828 have SAR ADC for measuring charging currents.
External sense resistor (RSENSE in data sheet) should be used. If some
other but 30MOhm resistor is used the resistance value should be given
here in Ohms.
regulators:
$ref: ../regulator/rohm,bd71828-regulator.yaml
description:
List of child nodes that specify the regulators.
leds:
$ref: ../leds/rohm,bd71828-leds.yaml
gpio-reserved-ranges:
description: |
Usage of BD71828 GPIO pins can be changed via OTP. This property can be
used to mark the pins which should not be configured for GPIO. Please see
the ../gpio/gpio.txt for more information.
required:
- compatible
- reg
- interrupts
- clocks
- "#clock-cells"
- regulators
- gpio-controller
- "#gpio-cells"
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/leds/common.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
pmic: pmic@4b {
compatible = "rohm,bd71828";
reg = <0x4b>;
interrupt-parent = <&gpio1>;
interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
clocks = <&osc 0>;
#clock-cells = <0>;
clock-output-names = "bd71828-32k-out";
gpio-controller;
#gpio-cells = <2>;
gpio-reserved-ranges = <0 1>, <2 1>;
rohm,charger-sense-resistor-ohms = <10000000>;
regulators {
buck1: BUCK1 {
regulator-name = "buck1";
regulator-min-microvolt = <500000>;
regulator-max-microvolt = <2000000>;
regulator-ramp-delay = <2500>;
};
buck2: BUCK2 {
regulator-name = "buck2";
regulator-min-microvolt = <500000>;
regulator-max-microvolt = <2000000>;
regulator-ramp-delay = <2500>;
};
buck3: BUCK3 {
regulator-name = "buck3";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <2000000>;
};
buck4: BUCK4 {
regulator-name = "buck4";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1800000>;
};
buck5: BUCK5 {
regulator-name = "buck5";
regulator-min-microvolt = <2500000>;
regulator-max-microvolt = <3300000>;
};
buck6: BUCK6 {
regulator-name = "buck6";
regulator-min-microvolt = <500000>;
regulator-max-microvolt = <2000000>;
regulator-ramp-delay = <2500>;
};
buck7: BUCK7 {
regulator-name = "buck7";
regulator-min-microvolt = <500000>;
regulator-max-microvolt = <2000000>;
regulator-ramp-delay = <2500>;
};
ldo1: LDO1 {
regulator-name = "ldo1";
regulator-min-microvolt = <800000>;
regulator-max-microvolt = <3300000>;
};
ldo2: LDO2 {
regulator-name = "ldo2";
regulator-min-microvolt = <800000>;
regulator-max-microvolt = <3300000>;
};
ldo3: LDO3 {
regulator-name = "ldo3";
regulator-min-microvolt = <800000>;
regulator-max-microvolt = <3300000>;
};
ldo4: LDO4 {
regulator-name = "ldo4";
regulator-min-microvolt = <800000>;
regulator-max-microvolt = <3300000>;
};
ldo5: LDO5 {
regulator-name = "ldo5";
regulator-min-microvolt = <800000>;
regulator-max-microvolt = <3300000>;
};
ldo6: LDO6 {
regulator-name = "ldo6";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
ldo7_reg: LDO7 {
regulator-name = "ldo7";
regulator-min-microvolt = <800000>;
regulator-max-microvolt = <3300000>;
};
};
leds {
compatible = "rohm,bd71828-leds";
led-1 {
rohm,led-compatible = "bd71828-grnled";
function = LED_FUNCTION_INDICATOR;
color = <LED_COLOR_ID_GREEN>;
};
led-2 {
rohm,led-compatible = "bd71828-ambled";
function = LED_FUNCTION_CHARGING;
color = <LED_COLOR_ID_AMBER>;
};
};
};
};
......@@ -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
......
......@@ -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);
......
......@@ -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
......
......@@ -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
......
// 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");
......@@ -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
......
......@@ -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
......@@ -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");
......
This diff is collapsed.
......@@ -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);
......
......@@ -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
......
......@@ -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
......
......@@ -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 @@ static int bd718xx_probe(struct platform_device *pdev)
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);
......
// 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");
......@@ -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.
......
This diff is collapsed.
......@@ -7,6 +7,7 @@
#include <linux/bits.h>
#include <linux/device.h>
#include <linux/mfd/rohm-generic.h>
#include <linux/mfd/rohm-shared.h>
#include <linux/regmap.h>
enum {
......@@ -89,10 +90,6 @@ struct bd70528_data {
#define BD70528_REG_GPIO3_OUT 0x52
#define BD70528_REG_GPIO4_OUT 0x54
/* clk control */
#define BD70528_REG_CLK_OUT 0x2c
/* RTC */
#define BD70528_REG_RTC_COUNT_H 0x2d
......@@ -309,21 +306,8 @@ enum {
#define BD70528_GPIO_IN_STATE_BASE 1
#define BD70528_CLK_OUT_EN_MASK 0x1
/* RTC masks to mask out reserved bits */
#define BD70528_MASK_RTC_SEC 0x7f
#define BD70528_MASK_RTC_MINUTE 0x7f
#define BD70528_MASK_RTC_HOUR_24H 0x80
#define BD70528_MASK_RTC_HOUR_PM 0x20
#define BD70528_MASK_RTC_HOUR 0x1f
#define BD70528_MASK_RTC_DAY 0x3f
#define BD70528_MASK_RTC_WEEK 0x07
#define BD70528_MASK_RTC_MONTH 0x1f
#define BD70528_MASK_RTC_YEAR 0xff
#define BD70528_MASK_RTC_COUNT_L 0x7f
#define BD70528_MASK_ELAPSED_TIMER_EN 0x1
/* Mask second, min and hour fields
* HW would support ALM irq for over 24h
......@@ -332,7 +316,6 @@ enum {
* wake-up we limit ALM to 24H and only
* unmask sec, min and hour
*/
#define BD70528_MASK_ALM_EN 0x7
#define BD70528_MASK_WAKE_EN 0x1
/* WDT masks */
......
This diff is collapsed.
......@@ -191,12 +191,6 @@ enum {
#define IRQ_ON_REQ 0x02
#define IRQ_STBY_REQ 0x01
/* BD718XX_REG_OUT32K bits */
#define BD718XX_OUT32K_EN 0x01
/* BD7183XX gated clock rate */
#define BD718XX_CLK_RATE 32768
/* ROHM BD718XX irqs */
enum {
BD718XX_INT_STBY_REQ,
......
......@@ -4,17 +4,83 @@
#ifndef __LINUX_MFD_ROHM_H__
#define __LINUX_MFD_ROHM_H__
enum {
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
enum rohm_chip_type {
ROHM_CHIP_TYPE_BD71837 = 0,
ROHM_CHIP_TYPE_BD71847,
ROHM_CHIP_TYPE_BD70528,
ROHM_CHIP_TYPE_BD71828,
ROHM_CHIP_TYPE_AMOUNT
};
struct rohm_regmap_dev {
unsigned int chip_type;
struct device *dev;
struct regmap *regmap;
};
enum {
ROHM_DVS_LEVEL_UNKNOWN,
ROHM_DVS_LEVEL_RUN,
ROHM_DVS_LEVEL_IDLE,
ROHM_DVS_LEVEL_SUSPEND,
ROHM_DVS_LEVEL_LPSR,
ROHM_DVS_LEVEL_MAX = ROHM_DVS_LEVEL_LPSR,
};
/**
* struct rohm_dvs_config - dynamic voltage scaling register descriptions
*
* @level_map: bitmap representing supported run-levels for this
* regulator
* @run_reg: register address for regulator config at 'run' state
* @run_mask: value mask for regulator voltages at 'run' state
* @run_on_mask: enable mask for regulator at 'run' state
* @idle_reg: register address for regulator config at 'idle' state
* @idle_mask: value mask for regulator voltages at 'idle' state
* @idle_on_mask: enable mask for regulator at 'idle' state
* @suspend_reg: register address for regulator config at 'suspend' state
* @suspend_mask: value mask for regulator voltages at 'suspend' state
* @suspend_on_mask: enable mask for regulator at 'suspend' state
* @lpsr_reg: register address for regulator config at 'lpsr' state
* @lpsr_mask: value mask for regulator voltages at 'lpsr' state
* @lpsr_on_mask: enable mask for regulator at 'lpsr' state
*
* Description of ROHM PMICs voltage configuration registers for different
* system states. This is used to correctly configure the PMIC at startup
* based on values read from DT.
*/
struct rohm_dvs_config {
uint64_t level_map;
unsigned int run_reg;
unsigned int run_mask;
unsigned int run_on_mask;
unsigned int idle_reg;
unsigned int idle_mask;
unsigned int idle_on_mask;
unsigned int suspend_reg;
unsigned int suspend_mask;
unsigned int suspend_on_mask;
unsigned int lpsr_reg;
unsigned int lpsr_mask;
unsigned int lpsr_on_mask;
};
#if IS_ENABLED(CONFIG_REGULATOR_ROHM)
int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs,
struct device_node *np,
const struct regulator_desc *desc,
struct regmap *regmap);
#else
static inline int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs,
struct device_node *np,
const struct regulator_desc *desc,
struct regmap *regmap)
{
return 0;
}
#endif
#endif
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Copyright (C) 2020 ROHM Semiconductors */
#ifndef __LINUX_MFD_ROHM_SHARED_H__
#define __LINUX_MFD_ROHM_SHARED_H__
/* RTC definitions shared between BD70528 and BD71828 */
#define BD70528_MASK_RTC_SEC 0x7f
#define BD70528_MASK_RTC_MINUTE 0x7f
#define BD70528_MASK_RTC_HOUR_24H 0x80
#define BD70528_MASK_RTC_HOUR_PM 0x20
#define BD70528_MASK_RTC_HOUR 0x3f
#define BD70528_MASK_RTC_DAY 0x3f
#define BD70528_MASK_RTC_WEEK 0x07
#define BD70528_MASK_RTC_MONTH 0x1f
#define BD70528_MASK_RTC_YEAR 0xff
#define BD70528_MASK_ALM_EN 0x7
#endif /* __LINUX_MFD_ROHM_SHARED_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment