Merge branch 'regulator-4.20' into regulator-next

This commit is contained in:
Mark Brown 2018-10-21 17:00:02 +01:00
commit 4fd1f509e8
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
55 changed files with 3109 additions and 1113 deletions

View File

@ -1,16 +1,17 @@
* ROHM BD71837 Power Management Integrated Circuit bindings
* ROHM BD71837 and BD71847 Power Management Integrated Circuit bindings
BD71837MWV is a programmable Power Management IC for powering single-core,
dual-core, and quad-core SoCs such as NXP-i.MX 8M. It is optimized for
low BOM cost and compact solution footprint. It integrates 8 Buck
egulators and 7 LDOs to provide all the power rails required by the SoC and
the commonly used peripherals.
BD71837MWV and BD71847MWV are programmable Power Management ICs for powering
single-core, dual-core, and quad-core SoCs such as NXP-i.MX 8M. They are
optimized for low BOM cost and compact solution footprint. BD71837MWV
integrates 8 Buck regulators and 7 LDOs. BD71847MWV contains 6 Buck regulators
and 6 LDOs.
Datasheet for PMIC is available at:
Datasheet for BD71837 is available at:
https://www.rohm.com/datasheet/BD71837MWV/bd71837mwv-e
Required properties:
- compatible : Should be "rohm,bd71837".
- compatible : Should be "rohm,bd71837" for bd71837
"rohm,bd71847" for bd71847.
- reg : I2C slave address.
- interrupt-parent : Phandle to the parent interrupt controller.
- interrupts : The interrupt line the device is connected to.

View File

@ -26,6 +26,7 @@ Regulator nodes are identified by their compatible:
"qcom,rpm-pm8998-regulators"
"qcom,rpm-pma8084-regulators"
"qcom,rpm-pmi8998-regulators"
"qcom,rpm-pms405-regulators"
- vdd_s1-supply:
- vdd_s2-supply:
@ -188,6 +189,24 @@ Regulator nodes are identified by their compatible:
Definition: reference to regulator supplying the input pin, as
described in the data sheet
- vdd_s1-supply:
- vdd_s2-supply:
- vdd_s3-supply:
- vdd_s4-supply:
- vdd_s5-supply:
- vdd_l1_l2-supply:
- vdd_l3_l8-supply:
- vdd_l4-supply:
- vdd_l5_l6-supply:
- vdd_l7-supply:
- vdd_l3_l8-supply:
- vdd_l9-supply:
- vdd_l10_l11_l12_l13-supply:
Usage: optional (pms405 only)
Value type: <phandle>
Definition: reference to regulator supplying the input pin, as
described in the data sheet
The regulator node houses sub-nodes for each regulator within the device. Each
sub-node is identified using the node's name, with valid values listed for each
of the pmics below.
@ -222,6 +241,10 @@ pma8084:
pmi8998:
bob
pms405:
s1, s2, s3, s4, s5, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12,
l13
The content of each sub-node is defined by the standard binding for regulators -
see regulator.txt.

View File

@ -1,7 +1,9 @@
ROHM BD71837 Power Management Integrated Circuit (PMIC) regulator bindings
ROHM BD71837 and BD71847 Power Management Integrated Circuit regulator bindings
Required properties:
- regulator-name: should be "buck1", ..., "buck8" and "ldo1", ..., "ldo7"
- regulator-name: should be "buck1", ..., "buck8" and "ldo1", ..., "ldo7" for
BD71837. For BD71847 names should be "buck1", ..., "buck6"
and "ldo1", ..., "ldo6"
List of regulators provided by this controller. BD71837 regulators node
should be sub node of the BD71837 MFD node. See BD71837 MFD bindings at
@ -16,10 +18,14 @@ disabled by driver at startup. LDO5 and LDO6 are supplied by those and
if they are disabled at startup the voltage monitoring for LDO5/LDO6 will
cause PMIC to reset.
The valid names for regulator nodes are:
The valid names for BD71837 regulator nodes are:
BUCK1, BUCK2, BUCK3, BUCK4, BUCK5, BUCK6, BUCK7, BUCK8
LDO1, LDO2, LDO3, LDO4, LDO5, LDO6, LDO7
The valid names for BD71847 regulator nodes are:
BUCK1, BUCK2, BUCK3, BUCK4, BUCK5, BUCK6
LDO1, LDO2, LDO3, LDO4, LDO5, LDO6
Optional properties:
- Any optional property defined in bindings/regulator/regulator.txt

View File

@ -0,0 +1,68 @@
STMicroelectronics STPMIC1 Voltage regulators
Regulator Nodes are optional depending on needs.
Available Regulators in STPMIC1 device are:
- buck1 for Buck BUCK1
- buck2 for Buck BUCK2
- buck3 for Buck BUCK3
- buck4 for Buck BUCK4
- ldo1 for LDO LDO1
- ldo2 for LDO LDO2
- ldo3 for LDO LDO3
- ldo4 for LDO LDO4
- ldo5 for LDO LDO5
- ldo6 for LDO LDO6
- vref_ddr for LDO Vref DDR
- boost for Buck BOOST
- pwr_sw1 for VBUS_OTG switch
- pwr_sw2 for SW_OUT switch
Switches are fixed voltage regulators with only enable/disable capability.
Optional properties:
- st,mask-reset: mask reset for this regulator: the regulator configuration
is maintained during pmic reset.
- regulator-pull-down: enable high pull down
if not specified light pull down is used
- regulator-over-current-protection:
if set, all regulators are switched off in case of over-current detection
on this regulator,
if not set, the driver only sends an over-current event.
- interrupt-parent: phandle to the parent interrupt controller
- interrupts: index of current limit detection interrupt
- <regulator>-supply: phandle to the parent supply/regulator node
each regulator supply can be described except vref_ddr.
Example:
regulators {
compatible = "st,stpmic1-regulators";
ldo6-supply = <&v3v3>;
vdd_core: buck1 {
regulator-name = "vdd_core";
interrupts = <IT_CURLIM_BUCK1 0>;
interrupt-parent = <&pmic>;
st,mask-reset;
regulator-pull-down;
regulator-min-microvolt = <700000>;
regulator-max-microvolt = <1200000>;
};
v3v3: buck4 {
regulator-name = "v3v3";
interrupts = <IT_CURLIM_BUCK4 0>;
interrupt-parent = <&mypmic>;
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
v1v8: ldo6 {
regulator-name = "v1v8";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-over-current-protection;
};
};

View File

@ -18,6 +18,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/physmap.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/machine.h>
#include <linux/gpio.h>
#include <linux/regulator/fixed.h>
#include <linux/regulator/machine.h>
@ -175,6 +176,7 @@ static struct resource mx21ads_mmgpio_resource =
DEFINE_RES_MEM_NAMED(MX21ADS_IO_REG, SZ_2, "dat");
static struct bgpio_pdata mx21ads_mmgpio_pdata = {
.label = "mx21ads-mmgpio",
.base = MX21ADS_MMGPIO_BASE,
.ngpio = 16,
};
@ -203,7 +205,6 @@ static struct regulator_init_data mx21ads_lcd_regulator_init_data = {
static struct fixed_voltage_config mx21ads_lcd_regulator_pdata = {
.supply_name = "LCD",
.microvolts = 3300000,
.gpio = MX21ADS_IO_LCDON,
.enable_high = 1,
.init_data = &mx21ads_lcd_regulator_init_data,
};
@ -216,6 +217,14 @@ static struct platform_device mx21ads_lcd_regulator = {
},
};
static struct gpiod_lookup_table mx21ads_lcd_regulator_gpiod_table = {
.dev_id = "reg-fixed-voltage.0", /* Let's hope ID 0 is what we get */
.table = {
GPIO_LOOKUP("mx21ads-mmgpio", 9, NULL, GPIO_ACTIVE_HIGH),
{ },
},
};
/*
* Connected is a portrait Sharp-QVGA display
* of type: LQ035Q7DB02
@ -311,6 +320,7 @@ static void __init mx21ads_late_init(void)
{
imx21_add_mxc_mmc(0, &mx21ads_sdhc_pdata);
gpiod_add_lookup_table(&mx21ads_lcd_regulator_gpiod_table);
platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
mx21ads_cs8900_resources[1].start =

View File

@ -16,6 +16,7 @@
#include <linux/gpio/driver.h>
/* Needed for gpio_to_irq() */
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
@ -230,10 +231,17 @@ static struct regulator_init_data mx27ads_lcd_regulator_init_data = {
static struct fixed_voltage_config mx27ads_lcd_regulator_pdata = {
.supply_name = "LCD",
.microvolts = 3300000,
.gpio = MX27ADS_LCD_GPIO,
.init_data = &mx27ads_lcd_regulator_init_data,
};
static struct gpiod_lookup_table mx27ads_lcd_regulator_gpiod_table = {
.dev_id = "reg-fixed-voltage.0", /* Let's hope ID 0 is what we get */
.table = {
GPIO_LOOKUP("LCD", 0, NULL, GPIO_ACTIVE_HIGH),
{ },
},
};
static void __init mx27ads_regulator_init(void)
{
struct gpio_chip *vchip;
@ -247,6 +255,8 @@ static void __init mx27ads_regulator_init(void)
vchip->set = vgpio_set;
gpiochip_add_data(vchip, NULL);
gpiod_add_lookup_table(&mx27ads_lcd_regulator_gpiod_table);
platform_device_register_data(NULL, "reg-fixed-voltage",
PLATFORM_DEVID_AUTO,
&mx27ads_lcd_regulator_pdata,

View File

@ -15,6 +15,7 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/gpio-pxa.h>
#include <linux/gpio/machine.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/max8649.h>
#include <linux/regulator/fixed.h>
@ -148,7 +149,6 @@ static struct regulator_init_data brownstone_v_5vp_data = {
static struct fixed_voltage_config brownstone_v_5vp = {
.supply_name = "v_5vp",
.microvolts = 5000000,
.gpio = GPIO_5V_ENABLE,
.enable_high = 1,
.enabled_at_boot = 1,
.init_data = &brownstone_v_5vp_data,
@ -162,6 +162,15 @@ static struct platform_device brownstone_v_5vp_device = {
},
};
static struct gpiod_lookup_table brownstone_v_5vp_gpiod_table = {
.dev_id = "reg-fixed-voltage.1", /* .id set to 1 above */
.table = {
GPIO_LOOKUP("gpio-pxa", GPIO_5V_ENABLE,
NULL, GPIO_ACTIVE_HIGH),
{ },
},
};
static struct max8925_platform_data brownstone_max8925_info = {
.irq_base = MMP_NR_IRQS,
};
@ -217,6 +226,7 @@ static void __init brownstone_init(void)
mmp2_add_isram(&mmp2_isram_platdata);
/* enable 5v regulator */
gpiod_add_lookup_table(&brownstone_v_5vp_gpiod_table);
platform_device_register(&brownstone_v_5vp_device);
}

View File

@ -300,7 +300,6 @@ static struct regulator_init_data modem_nreset_data = {
static struct fixed_voltage_config modem_nreset_config = {
.supply_name = "modem_nreset",
.microvolts = 3300000,
.gpio = AMS_DELTA_GPIO_PIN_MODEM_NRESET,
.startup_delay = 25000,
.enable_high = 1,
.enabled_at_boot = 1,
@ -315,6 +314,15 @@ static struct platform_device modem_nreset_device = {
},
};
static struct gpiod_lookup_table ams_delta_nreset_gpiod_table = {
.dev_id = "reg-fixed-voltage",
.table = {
GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_MODEM_NRESET,
NULL, GPIO_ACTIVE_HIGH),
{ },
},
};
struct modem_private_data {
struct regulator *regulator;
};
@ -568,7 +576,6 @@ static struct regulator_init_data keybrd_pwr_initdata = {
static struct fixed_voltage_config keybrd_pwr_config = {
.supply_name = "keybrd_pwr",
.microvolts = 5000000,
.gpio = AMS_DELTA_GPIO_PIN_KEYBRD_PWR,
.enable_high = 1,
.init_data = &keybrd_pwr_initdata,
};
@ -602,6 +609,7 @@ static struct platform_device *ams_delta_devices[] __initdata = {
};
static struct gpiod_lookup_table *ams_delta_gpio_tables[] __initdata = {
&ams_delta_nreset_gpiod_table,
&ams_delta_audio_gpio_table,
&keybrd_pwr_gpio_table,
&ams_delta_lcd_gpio_table,

View File

@ -10,6 +10,7 @@
#include <linux/clk.h>
#include <linux/davinci_emac.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/of_platform.h>
@ -328,7 +329,6 @@ static struct regulator_init_data pandora_vmmc3 = {
static struct fixed_voltage_config pandora_vwlan = {
.supply_name = "vwlan",
.microvolts = 1800000, /* 1.8V */
.gpio = PANDORA_WIFI_NRESET_GPIO,
.startup_delay = 50000, /* 50ms */
.enable_high = 1,
.init_data = &pandora_vmmc3,
@ -342,6 +342,19 @@ static struct platform_device pandora_vwlan_device = {
},
};
static struct gpiod_lookup_table pandora_vwlan_gpiod_table = {
.dev_id = "reg-fixed-voltage.1",
.table = {
/*
* As this is a low GPIO number it should be at the first
* GPIO bank.
*/
GPIO_LOOKUP("gpio-0-31", PANDORA_WIFI_NRESET_GPIO,
NULL, GPIO_ACTIVE_HIGH),
{ },
},
};
static void pandora_wl1251_init_card(struct mmc_card *card)
{
/*
@ -403,6 +416,7 @@ static void __init pandora_wl1251_init(void)
static void __init omap3_pandora_legacy_init(void)
{
platform_device_register(&pandora_backlight);
gpiod_add_lookup_table(&pandora_vwlan_gpiod_table);
platform_device_register(&pandora_vwlan_device);
omap_hsmmc_init(pandora_mmc3);
omap_hsmmc_late_init(pandora_mmc3);

View File

@ -986,7 +986,6 @@ static struct fixed_voltage_config camera_dummy_config = {
.supply_name = "camera_vdd",
.input_supply = "vcc cam",
.microvolts = 2800000,
.gpio = -1,
.enable_high = 0,
.init_data = &camera_dummy_initdata,
};

View File

@ -21,6 +21,7 @@
#include <linux/regulator/fixed.h>
#include <linux/input.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/gpio_keys.h>
#include <linux/leds-lp3944.h>
#include <linux/platform_data/i2c-pxa.h>
@ -698,31 +699,39 @@ static struct pxa27x_keypad_platform_data e2_keypad_platform_data = {
#if defined(CONFIG_MACH_EZX_A780) || defined(CONFIG_MACH_EZX_A910)
/* camera */
static struct regulator_consumer_supply camera_dummy_supplies[] = {
static struct regulator_consumer_supply camera_regulator_supplies[] = {
REGULATOR_SUPPLY("vdd", "0-005d"),
};
static struct regulator_init_data camera_dummy_initdata = {
.consumer_supplies = camera_dummy_supplies,
.num_consumer_supplies = ARRAY_SIZE(camera_dummy_supplies),
static struct regulator_init_data camera_regulator_initdata = {
.consumer_supplies = camera_regulator_supplies,
.num_consumer_supplies = ARRAY_SIZE(camera_regulator_supplies),
.constraints = {
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
};
static struct fixed_voltage_config camera_dummy_config = {
static struct fixed_voltage_config camera_regulator_config = {
.supply_name = "camera_vdd",
.microvolts = 2800000,
.gpio = GPIO50_nCAM_EN,
.enable_high = 0,
.init_data = &camera_dummy_initdata,
.init_data = &camera_regulator_initdata,
};
static struct platform_device camera_supply_dummy_device = {
static struct platform_device camera_supply_regulator_device = {
.name = "reg-fixed-voltage",
.id = 1,
.dev = {
.platform_data = &camera_dummy_config,
.platform_data = &camera_regulator_config,
},
};
static struct gpiod_lookup_table camera_supply_gpiod_table = {
.dev_id = "reg-fixed-voltage.1",
.table = {
GPIO_LOOKUP("gpio-pxa", GPIO50_nCAM_EN,
NULL, GPIO_ACTIVE_HIGH),
{ },
},
};
#endif
@ -800,7 +809,7 @@ static struct i2c_board_info a780_i2c_board_info[] = {
static struct platform_device *a780_devices[] __initdata = {
&a780_gpio_keys,
&camera_supply_dummy_device,
&camera_supply_regulator_device,
};
static void __init a780_init(void)
@ -823,6 +832,7 @@ static void __init a780_init(void)
if (a780_camera_init() == 0)
pxa_set_camera_info(&a780_pxacamera_platform_data);
gpiod_add_lookup_table(&camera_supply_gpiod_table);
pwm_add_table(ezx_pwm_lookup, ARRAY_SIZE(ezx_pwm_lookup));
platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
platform_add_devices(ARRAY_AND_SIZE(a780_devices));
@ -1098,7 +1108,7 @@ static struct i2c_board_info __initdata a910_i2c_board_info[] = {
static struct platform_device *a910_devices[] __initdata = {
&a910_gpio_keys,
&camera_supply_dummy_device,
&camera_supply_regulator_device,
};
static void __init a910_init(void)
@ -1121,6 +1131,7 @@ static void __init a910_init(void)
if (a910_camera_init() == 0)
pxa_set_camera_info(&a910_pxacamera_platform_data);
gpiod_add_lookup_table(&camera_supply_gpiod_table);
pwm_add_table(ezx_pwm_lookup, ARRAY_SIZE(ezx_pwm_lookup));
platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
platform_add_devices(ARRAY_AND_SIZE(a910_devices));

View File

@ -18,6 +18,7 @@
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/mfd/htc-pasic3.h>
@ -696,7 +697,6 @@ static struct regulator_init_data vads7846_regulator = {
static struct fixed_voltage_config vads7846 = {
.supply_name = "vads7846",
.microvolts = 3300000, /* probably */
.gpio = -EINVAL,
.startup_delay = 0,
.init_data = &vads7846_regulator,
};

View File

@ -886,7 +886,6 @@ static struct regulator_init_data audio_va_initdata = {
static struct fixed_voltage_config audio_va_config = {
.supply_name = "audio_va",
.microvolts = 5000000,
.gpio = GPIO_AUDIO_VA_ENABLE,
.enable_high = 1,
.enabled_at_boot = 0,
.init_data = &audio_va_initdata,
@ -900,6 +899,15 @@ static struct platform_device audio_va_device = {
},
};
static struct gpiod_lookup_table audio_va_gpiod_table = {
.dev_id = "reg-fixed-voltage.0",
.table = {
GPIO_LOOKUP("gpio-pxa", GPIO_AUDIO_VA_ENABLE,
NULL, GPIO_ACTIVE_HIGH),
{ },
},
};
/* Dummy supplies for Codec's VD/VLC */
static struct regulator_consumer_supply audio_dummy_supplies[] = {
@ -918,7 +926,6 @@ static struct regulator_init_data audio_dummy_initdata = {
static struct fixed_voltage_config audio_dummy_config = {
.supply_name = "audio_vd",
.microvolts = 3300000,
.gpio = -1,
.init_data = &audio_dummy_initdata,
};
@ -1033,6 +1040,7 @@ static void __init raumfeld_audio_init(void)
else
gpio_direction_output(GPIO_MCLK_RESET, 1);
gpiod_add_lookup_table(&audio_va_gpiod_table);
platform_add_devices(ARRAY_AND_SIZE(audio_regulator_devices));
}

View File

@ -17,6 +17,7 @@
#include <linux/irq.h>
#include <linux/pm.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/serial_8250.h>
#include <linux/dm9000.h>
#include <linux/mmc/host.h>
@ -410,7 +411,6 @@ static struct regulator_init_data can_regulator_init_data = {
static struct fixed_voltage_config can_regulator_pdata = {
.supply_name = "CAN_SHDN",
.microvolts = 3300000,
.gpio = ZEUS_CAN_SHDN_GPIO,
.init_data = &can_regulator_init_data,
};
@ -422,6 +422,15 @@ static struct platform_device can_regulator_device = {
},
};
static struct gpiod_lookup_table can_regulator_gpiod_table = {
.dev_id = "reg-fixed-voltage.0",
.table = {
GPIO_LOOKUP("gpio-pxa", ZEUS_CAN_SHDN_GPIO,
NULL, GPIO_ACTIVE_HIGH),
{ },
},
};
static struct mcp251x_platform_data zeus_mcp2515_pdata = {
.oscillator_frequency = 16*1000*1000,
};
@ -538,7 +547,6 @@ static struct regulator_init_data zeus_ohci_regulator_data = {
static struct fixed_voltage_config zeus_ohci_regulator_config = {
.supply_name = "vbus2",
.microvolts = 5000000, /* 5.0V */
.gpio = ZEUS_USB2_PWREN_GPIO,
.enable_high = 1,
.startup_delay = 0,
.init_data = &zeus_ohci_regulator_data,
@ -552,6 +560,15 @@ static struct platform_device zeus_ohci_regulator_device = {
},
};
static struct gpiod_lookup_table zeus_ohci_regulator_gpiod_table = {
.dev_id = "reg-fixed-voltage.0",
.table = {
GPIO_LOOKUP("gpio-pxa", ZEUS_USB2_PWREN_GPIO,
NULL, GPIO_ACTIVE_HIGH),
{ },
},
};
static struct pxaohci_platform_data zeus_ohci_platform_data = {
.port_mode = PMM_NPS_MODE,
/* Clear Power Control Polarity Low and set Power Sense
@ -855,6 +872,8 @@ static void __init zeus_init(void)
pxa2xx_mfp_config(ARRAY_AND_SIZE(zeus_pin_config));
gpiod_add_lookup_table(&can_regulator_gpiod_table);
gpiod_add_lookup_table(&zeus_ohci_regulator_gpiod_table);
platform_add_devices(zeus_devices, ARRAY_SIZE(zeus_devices));
zeus_register_ohci();

View File

@ -352,7 +352,6 @@ static struct fixed_voltage_config wallvdd_pdata = {
.supply_name = "WALLVDD",
.microvolts = 5000000,
.init_data = &wallvdd_data,
.gpio = -EINVAL,
};
static struct platform_device wallvdd_device = {

View File

@ -222,7 +222,6 @@ static struct fixed_voltage_config smdk6410_b_pwr_5v_pdata = {
.supply_name = "B_PWR_5V",
.microvolts = 5000000,
.init_data = &smdk6410_b_pwr_5v_data,
.gpio = -EINVAL,
};
static struct platform_device smdk6410_b_pwr_5v = {

View File

@ -101,7 +101,7 @@ static int __init assabet_init_gpio(void __iomem *reg, u32 def_val)
assabet_bcr_gc = gc;
return gc->base;
return 0;
}
/*
@ -471,6 +471,14 @@ static struct fixed_voltage_config assabet_cf_vcc_pdata __initdata = {
.enable_high = 1,
};
static struct gpiod_lookup_table assabet_cf_vcc_gpio_table = {
.dev_id = "reg-fixed-voltage.0",
.table = {
GPIO_LOOKUP("assabet", 0, NULL, GPIO_ACTIVE_HIGH),
{ },
},
};
static void __init assabet_init(void)
{
/*
@ -517,9 +525,11 @@ static void __init assabet_init(void)
neponset_resources, ARRAY_SIZE(neponset_resources));
#endif
} else {
gpiod_add_lookup_table(&assabet_cf_vcc_gpio_table);
sa11x0_register_fixed_regulator(0, &assabet_cf_vcc_pdata,
assabet_cf_vcc_consumers,
ARRAY_SIZE(assabet_cf_vcc_consumers));
assabet_cf_vcc_consumers,
ARRAY_SIZE(assabet_cf_vcc_consumers),
true);
}
@ -802,7 +812,6 @@ fs_initcall(assabet_leds_init);
void __init assabet_init_irq(void)
{
unsigned int assabet_gpio_base;
u32 def_val;
sa1100_init_irq();
@ -817,9 +826,7 @@ void __init assabet_init_irq(void)
*
* This must precede any driver calls to BCR_set() or BCR_clear().
*/
assabet_gpio_base = assabet_init_gpio((void *)&ASSABET_BCR, def_val);
assabet_cf_vcc_pdata.gpio = assabet_gpio_base + 0;
assabet_init_gpio((void *)&ASSABET_BCR, def_val);
}
MACHINE_START(ASSABET, "Intel-Assabet")

View File

@ -348,7 +348,8 @@ void __init sa11x0_init_late(void)
int __init sa11x0_register_fixed_regulator(int n,
struct fixed_voltage_config *cfg,
struct regulator_consumer_supply *supplies, unsigned num_supplies)
struct regulator_consumer_supply *supplies, unsigned num_supplies,
bool uses_gpio)
{
struct regulator_init_data *id;
@ -356,7 +357,7 @@ int __init sa11x0_register_fixed_regulator(int n,
if (!cfg->init_data)
return -ENOMEM;
if (cfg->gpio < 0)
if (!uses_gpio)
id->constraints.always_on = 1;
id->constraints.name = cfg->supply_name;
id->constraints.min_uV = cfg->microvolts;

View File

@ -54,4 +54,5 @@ void sa11x0_register_pcmcia(int socket, struct gpiod_lookup_table *);
struct fixed_voltage_config;
struct regulator_consumer_supply;
int sa11x0_register_fixed_regulator(int n, struct fixed_voltage_config *cfg,
struct regulator_consumer_supply *supplies, unsigned num_supplies);
struct regulator_consumer_supply *supplies, unsigned num_supplies,
bool uses_gpio);

View File

@ -102,14 +102,14 @@ static struct fixed_voltage_config shannon_cf_vcc_pdata __initdata = {
.supply_name = "cf-power",
.microvolts = 3300000,
.enabled_at_boot = 1,
.gpio = -EINVAL,
};
static void __init shannon_init(void)
{
sa11x0_register_fixed_regulator(0, &shannon_cf_vcc_pdata,
shannon_cf_vcc_consumers,
ARRAY_SIZE(shannon_cf_vcc_consumers));
ARRAY_SIZE(shannon_cf_vcc_consumers),
false);
sa11x0_register_pcmcia(0, &shannon_pcmcia0_gpio_table);
sa11x0_register_pcmcia(1, &shannon_pcmcia1_gpio_table);
sa11x0_ppc_configure_mcp();

View File

@ -633,7 +633,6 @@ static struct regulator_init_data cn12_power_init_data = {
static struct fixed_voltage_config cn12_power_info = {
.supply_name = "CN12 SD/MMC Vdd",
.microvolts = 3300000,
.gpio = GPIO_PTB7,
.enable_high = 1,
.init_data = &cn12_power_init_data,
};
@ -646,6 +645,16 @@ static struct platform_device cn12_power = {
},
};
static struct gpiod_lookup_table cn12_power_gpiod_table = {
.dev_id = "reg-fixed-voltage.0",
.table = {
/* Offset 7 on port B */
GPIO_LOOKUP("sh7724_pfc", GPIO_PTB7,
NULL, GPIO_ACTIVE_HIGH),
{ },
},
};
#if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)
/* SDHI0 */
static struct regulator_consumer_supply sdhi0_power_consumers[] =
@ -665,7 +674,6 @@ static struct regulator_init_data sdhi0_power_init_data = {
static struct fixed_voltage_config sdhi0_power_info = {
.supply_name = "CN11 SD/MMC Vdd",
.microvolts = 3300000,
.gpio = GPIO_PTB6,
.enable_high = 1,
.init_data = &sdhi0_power_init_data,
};
@ -678,6 +686,16 @@ static struct platform_device sdhi0_power = {
},
};
static struct gpiod_lookup_table sdhi0_power_gpiod_table = {
.dev_id = "reg-fixed-voltage.1",
.table = {
/* Offset 6 on port B */
GPIO_LOOKUP("sh7724_pfc", GPIO_PTB6,
NULL, GPIO_ACTIVE_HIGH),
{ },
},
};
static struct tmio_mmc_data sdhi0_info = {
.chan_priv_tx = (void *)SHDMA_SLAVE_SDHI0_TX,
.chan_priv_rx = (void *)SHDMA_SLAVE_SDHI0_RX,
@ -1413,6 +1431,11 @@ static int __init arch_setup(void)
DMA_MEMORY_EXCLUSIVE);
platform_device_add(ecovec_ceu_devices[1]);
gpiod_add_lookup_table(&cn12_power_gpiod_table);
#if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)
gpiod_add_lookup_table(&sdhi0_power_gpiod_table);
#endif
return platform_add_devices(ecovec_devices,
ARRAY_SIZE(ecovec_devices));
}

View File

@ -10,7 +10,7 @@
* of the License.
*/
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/platform_device.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/fixed.h>
@ -43,7 +43,6 @@ static struct fixed_voltage_config bcm43xx_vmmc = {
* real voltage and signaling are still 1.8V.
*/
.microvolts = 2000000, /* 1.8V */
.gpio = -EINVAL,
.startup_delay = 250 * 1000, /* 250ms */
.enable_high = 1, /* active high */
.enabled_at_boot = 0, /* disabled at boot */
@ -58,11 +57,23 @@ static struct platform_device bcm43xx_vmmc_regulator = {
},
};
static struct gpiod_lookup_table bcm43xx_vmmc_gpio_table = {
.dev_id = "reg-fixed-voltage.0",
.table = {
GPIO_LOOKUP("0000:00:0c.0", -1, NULL, GPIO_ACTIVE_LOW),
{}
},
};
static int __init bcm43xx_regulator_register(void)
{
struct gpiod_lookup_table *table = &bcm43xx_vmmc_gpio_table;
struct gpiod_lookup *lookup = table->table;
int ret;
bcm43xx_vmmc.gpio = get_gpio_by_name(WLAN_SFI_GPIO_ENABLE_NAME);
lookup[0].chip_hwnum = get_gpio_by_name(WLAN_SFI_GPIO_ENABLE_NAME);
gpiod_add_lookup_table(table);
ret = platform_device_register(&bcm43xx_vmmc_regulator);
if (ret) {
pr_err("%s: vmmc regulator register failed\n", __func__);

View File

@ -3909,8 +3909,23 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
* the device name as label
*/
status = gpiod_request(desc, con_id ? con_id : devname);
if (status < 0)
return ERR_PTR(status);
if (status < 0) {
if (status == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) {
/*
* This happens when there are several consumers for
* the same GPIO line: we just return here without
* further initialization. It is a bit if a hack.
* This is necessary to support fixed regulators.
*
* FIXME: Make this more sane and safe.
*/
dev_info(dev, "nonexclusive access to GPIO for %s\n",
con_id ? con_id : devname);
return desc;
} else {
return ERR_PTR(status);
}
}
status = gpiod_configure_flags(desc, con_id, lookupflags, flags);
if (status < 0) {

View File

@ -2,26 +2,21 @@
//
// Copyright (C) 2018 ROHM Semiconductors
//
// ROHM BD71837MWV PMIC driver
// ROHM BD71837MWV and BD71847MWV PMIC driver
//
// Datasheet available from
// Datasheet for BD71837MWV available from
// https://www.rohm.com/datasheet/BD71837MWV/bd71837mwv-e
#include <linux/gpio_keys.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/mfd/rohm-bd718x7.h>
#include <linux/mfd/core.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
/*
* gpio_keys.h requires definiton of bool. It is brought in
* by above includes. Keep this as last until gpio_keys.h gets fixed.
*/
#include <linux/gpio_keys.h>
static const u8 supported_revisions[] = { 0xA2 /* BD71837 */ };
#include <linux/types.h>
static struct gpio_keys_button button = {
.code = KEY_POWER,
@ -35,42 +30,42 @@ static struct gpio_keys_platform_data bd718xx_powerkey_data = {
.name = "bd718xx-pwrkey",
};
static struct mfd_cell bd71837_mfd_cells[] = {
static struct mfd_cell bd718xx_mfd_cells[] = {
{
.name = "gpio-keys",
.platform_data = &bd718xx_powerkey_data,
.pdata_size = sizeof(bd718xx_powerkey_data),
},
{ .name = "bd71837-clk", },
{ .name = "bd71837-pmic", },
{ .name = "bd718xx-clk", },
{ .name = "bd718xx-pmic", },
};
static const struct regmap_irq bd71837_irqs[] = {
REGMAP_IRQ_REG(BD71837_INT_SWRST, 0, BD71837_INT_SWRST_MASK),
REGMAP_IRQ_REG(BD71837_INT_PWRBTN_S, 0, BD71837_INT_PWRBTN_S_MASK),
REGMAP_IRQ_REG(BD71837_INT_PWRBTN_L, 0, BD71837_INT_PWRBTN_L_MASK),
REGMAP_IRQ_REG(BD71837_INT_PWRBTN, 0, BD71837_INT_PWRBTN_MASK),
REGMAP_IRQ_REG(BD71837_INT_WDOG, 0, BD71837_INT_WDOG_MASK),
REGMAP_IRQ_REG(BD71837_INT_ON_REQ, 0, BD71837_INT_ON_REQ_MASK),
REGMAP_IRQ_REG(BD71837_INT_STBY_REQ, 0, BD71837_INT_STBY_REQ_MASK),
static const struct regmap_irq bd718xx_irqs[] = {
REGMAP_IRQ_REG(BD718XX_INT_SWRST, 0, BD718XX_INT_SWRST_MASK),
REGMAP_IRQ_REG(BD718XX_INT_PWRBTN_S, 0, BD718XX_INT_PWRBTN_S_MASK),
REGMAP_IRQ_REG(BD718XX_INT_PWRBTN_L, 0, BD718XX_INT_PWRBTN_L_MASK),
REGMAP_IRQ_REG(BD718XX_INT_PWRBTN, 0, BD718XX_INT_PWRBTN_MASK),
REGMAP_IRQ_REG(BD718XX_INT_WDOG, 0, BD718XX_INT_WDOG_MASK),
REGMAP_IRQ_REG(BD718XX_INT_ON_REQ, 0, BD718XX_INT_ON_REQ_MASK),
REGMAP_IRQ_REG(BD718XX_INT_STBY_REQ, 0, BD718XX_INT_STBY_REQ_MASK),
};
static struct regmap_irq_chip bd71837_irq_chip = {
.name = "bd71837-irq",
.irqs = bd71837_irqs,
.num_irqs = ARRAY_SIZE(bd71837_irqs),
static struct regmap_irq_chip bd718xx_irq_chip = {
.name = "bd718xx-irq",
.irqs = bd718xx_irqs,
.num_irqs = ARRAY_SIZE(bd718xx_irqs),
.num_regs = 1,
.irq_reg_stride = 1,
.status_base = BD71837_REG_IRQ,
.mask_base = BD71837_REG_MIRQ,
.ack_base = BD71837_REG_IRQ,
.status_base = BD718XX_REG_IRQ,
.mask_base = BD718XX_REG_MIRQ,
.ack_base = BD718XX_REG_IRQ,
.init_ack_masked = true,
.mask_invert = false,
};
static const struct regmap_range pmic_status_range = {
.range_min = BD71837_REG_IRQ,
.range_max = BD71837_REG_POW_STATE,
.range_min = BD718XX_REG_IRQ,
.range_max = BD718XX_REG_POW_STATE,
};
static const struct regmap_access_table volatile_regs = {
@ -78,67 +73,53 @@ static const struct regmap_access_table volatile_regs = {
.n_yes_ranges = 1,
};
static const struct regmap_config bd71837_regmap_config = {
static const struct regmap_config bd718xx_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.volatile_table = &volatile_regs,
.max_register = BD71837_MAX_REGISTER - 1,
.max_register = BD718XX_MAX_REGISTER - 1,
.cache_type = REGCACHE_RBTREE,
};
static int bd71837_i2c_probe(struct i2c_client *i2c,
static int bd718xx_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct bd71837 *bd71837;
int ret, i;
unsigned int val;
struct bd718xx *bd718xx;
int ret;
bd71837 = devm_kzalloc(&i2c->dev, sizeof(struct bd71837), GFP_KERNEL);
if (!bd71837)
return -ENOMEM;
bd71837->chip_irq = i2c->irq;
if (!bd71837->chip_irq) {
if (!i2c->irq) {
dev_err(&i2c->dev, "No IRQ configured\n");
return -EINVAL;
}
bd71837->dev = &i2c->dev;
dev_set_drvdata(&i2c->dev, bd71837);
bd718xx = devm_kzalloc(&i2c->dev, sizeof(struct bd718xx), GFP_KERNEL);
bd71837->regmap = devm_regmap_init_i2c(i2c, &bd71837_regmap_config);
if (IS_ERR(bd71837->regmap)) {
if (!bd718xx)
return -ENOMEM;
bd718xx->chip_irq = i2c->irq;
bd718xx->chip_type = (unsigned int)
of_device_get_match_data(&i2c->dev);
bd718xx->dev = &i2c->dev;
dev_set_drvdata(&i2c->dev, bd718xx);
bd718xx->regmap = devm_regmap_init_i2c(i2c, &bd718xx_regmap_config);
if (IS_ERR(bd718xx->regmap)) {
dev_err(&i2c->dev, "regmap initialization failed\n");
return PTR_ERR(bd71837->regmap);
return PTR_ERR(bd718xx->regmap);
}
ret = regmap_read(bd71837->regmap, BD71837_REG_REV, &val);
if (ret) {
dev_err(&i2c->dev, "Read BD71837_REG_DEVICE failed\n");
return ret;
}
for (i = 0; i < ARRAY_SIZE(supported_revisions); i++)
if (supported_revisions[i] == val)
break;
if (i == ARRAY_SIZE(supported_revisions)) {
dev_err(&i2c->dev, "Unsupported chip revision\n");
return -ENODEV;
}
ret = devm_regmap_add_irq_chip(&i2c->dev, bd71837->regmap,
bd71837->chip_irq, IRQF_ONESHOT, 0,
&bd71837_irq_chip, &bd71837->irq_data);
ret = devm_regmap_add_irq_chip(&i2c->dev, bd718xx->regmap,
bd718xx->chip_irq, IRQF_ONESHOT, 0,
&bd718xx_irq_chip, &bd718xx->irq_data);
if (ret) {
dev_err(&i2c->dev, "Failed to add irq_chip\n");
return ret;
}
/* Configure short press to 10 milliseconds */
ret = regmap_update_bits(bd71837->regmap,
BD71837_REG_PWRONCONFIG0,
ret = regmap_update_bits(bd718xx->regmap,
BD718XX_REG_PWRONCONFIG0,
BD718XX_PWRBTN_PRESS_DURATION_MASK,
BD718XX_PWRBTN_SHORT_PRESS_10MS);
if (ret) {
@ -148,8 +129,8 @@ static int bd71837_i2c_probe(struct i2c_client *i2c,
}
/* Configure long press to 10 seconds */
ret = regmap_update_bits(bd71837->regmap,
BD71837_REG_PWRONCONFIG1,
ret = regmap_update_bits(bd718xx->regmap,
BD718XX_REG_PWRONCONFIG1,
BD718XX_PWRBTN_PRESS_DURATION_MASK,
BD718XX_PWRBTN_LONG_PRESS_10S);
@ -159,7 +140,7 @@ static int bd71837_i2c_probe(struct i2c_client *i2c,
return ret;
}
ret = regmap_irq_get_virq(bd71837->irq_data, BD71837_INT_PWRBTN_S);
ret = regmap_irq_get_virq(bd718xx->irq_data, BD718XX_INT_PWRBTN_S);
if (ret < 0) {
dev_err(&i2c->dev, "Failed to get the IRQ\n");
@ -168,44 +149,51 @@ static int bd71837_i2c_probe(struct i2c_client *i2c,
button.irq = ret;
ret = devm_mfd_add_devices(bd71837->dev, PLATFORM_DEVID_AUTO,
bd71837_mfd_cells,
ARRAY_SIZE(bd71837_mfd_cells), NULL, 0,
regmap_irq_get_domain(bd71837->irq_data));
ret = devm_mfd_add_devices(bd718xx->dev, PLATFORM_DEVID_AUTO,
bd718xx_mfd_cells,
ARRAY_SIZE(bd718xx_mfd_cells), NULL, 0,
regmap_irq_get_domain(bd718xx->irq_data));
if (ret)
dev_err(&i2c->dev, "Failed to create subdevices\n");
return ret;
}
static const struct of_device_id bd71837_of_match[] = {
{ .compatible = "rohm,bd71837", },
static const struct of_device_id bd718xx_of_match[] = {
{
.compatible = "rohm,bd71837",
.data = (void *)BD718XX_TYPE_BD71837,
},
{
.compatible = "rohm,bd71847",
.data = (void *)BD718XX_TYPE_BD71847,
},
{ }
};
MODULE_DEVICE_TABLE(of, bd71837_of_match);
MODULE_DEVICE_TABLE(of, bd718xx_of_match);
static struct i2c_driver bd71837_i2c_driver = {
static struct i2c_driver bd718xx_i2c_driver = {
.driver = {
.name = "rohm-bd718x7",
.of_match_table = bd71837_of_match,
.of_match_table = bd718xx_of_match,
},
.probe = bd71837_i2c_probe,
.probe = bd718xx_i2c_probe,
};
static int __init bd71837_i2c_init(void)
static int __init bd718xx_i2c_init(void)
{
return i2c_add_driver(&bd71837_i2c_driver);
return i2c_add_driver(&bd718xx_i2c_driver);
}
/* Initialise early so consumer devices can complete system boot */
subsys_initcall(bd71837_i2c_init);
subsys_initcall(bd718xx_i2c_init);
static void __exit bd71837_i2c_exit(void)
static void __exit bd718xx_i2c_exit(void)
{
i2c_del_driver(&bd71837_i2c_driver);
i2c_del_driver(&bd718xx_i2c_driver);
}
module_exit(bd71837_i2c_exit);
module_exit(bd718xx_i2c_exit);
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
MODULE_DESCRIPTION("ROHM BD71837 Power Management IC driver");
MODULE_DESCRIPTION("ROHM BD71837/BD71847 Power Management IC driver");
MODULE_LICENSE("GPL");

View File

@ -189,7 +189,7 @@ config REGULATOR_BD718XX
and LDO regulators.
This driver can also be built as a module. If so, the module
will be called bd71837-regulator.
will be called bd718x7-regulator.
config REGULATOR_BD9571MWV
tristate "ROHM BD9571MWV Regulators"
@ -356,6 +356,13 @@ config REGULATOR_LM363X
One boost output voltage is configurable and always on.
Other LDOs are used for the display module.
config REGULATOR_LOCHNAGAR
tristate "Cirrus Logic Lochnagar regulator driver"
depends on MFD_LOCHNAGAR
help
This enables regulator support on the Cirrus Logic Lochnagar audio
development board.
config REGULATOR_LP3971
tristate "National Semiconductors LP3971 PMIC regulator driver"
depends on I2C
@ -803,6 +810,18 @@ config REGULATOR_STM32_VREFBUF
This driver can also be built as a module. If so, the module
will be called stm32-vrefbuf.
config REGULATOR_STPMIC1
tristate "STMicroelectronics STPMIC1 PMIC Regulators"
depends on MFD_STPMIC1
help
This driver supports STMicroelectronics STPMIC1 PMIC voltage
regulators and switches. The STPMIC1 regulators supply power to
an application processor as well as to external system
peripherals such as DDR, Flash memories and system devices.
To compile this driver as a module, choose M here: the
module will be called stpmic1_regulator.
config REGULATOR_TI_ABB
tristate "TI Adaptive Body Bias on-chip LDO"
depends on ARCH_OMAP

View File

@ -27,7 +27,7 @@ obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o
obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o
obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o
obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o
obj-$(CONFIG_REGULATOR_BD718XX) += bd71837-regulator.o
obj-$(CONFIG_REGULATOR_BD718XX) += bd718x7-regulator.o
obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o
obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o
@ -46,6 +46,7 @@ obj-$(CONFIG_REGULATOR_HI655X) += hi655x-regulator.o
obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
obj-$(CONFIG_REGULATOR_ISL9305) += isl9305.o
obj-$(CONFIG_REGULATOR_LM363X) += lm363x-regulator.o
obj-$(CONFIG_REGULATOR_LOCHNAGAR) += lochnagar-regulator.o
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o
obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o
@ -101,6 +102,7 @@ obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
obj-$(CONFIG_REGULATOR_SC2731) += sc2731-regulator.o
obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o
obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
obj-$(CONFIG_REGULATOR_STPMIC1) += stpmic1_regulator.o
obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o
obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o

View File

@ -260,7 +260,7 @@ static int arizona_ldo1_common_init(struct platform_device *pdev,
* so clean up would happen at the wrong time
*/
config.ena_gpiod = gpiod_get_optional(parent_dev, "wlf,ldoena",
GPIOD_OUT_LOW);
GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
if (IS_ERR(config.ena_gpiod))
return PTR_ERR(config.ena_gpiod);

View File

@ -509,10 +509,10 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
/*
* AXP803/AXP813 DCDC work frequency setting has the same
* range and step as AXP22X, but at a different register.
* Fall through to the check below.
* (See include/linux/mfd/axp20x.h)
*/
reg = AXP803_DCDC_FREQ_CTRL;
/* Fall through to the check below.*/
case AXP806_ID:
/*
* AXP806 also have DCDC work frequency setting register at a
@ -520,6 +520,7 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
*/
if (axp20x->variant == AXP806_ID)
reg = AXP806_DCDC_FREQ_CTRL;
/* Fall through */
case AXP221_ID:
case AXP223_ID:
case AXP809_ID:

View File

@ -1,645 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2018 ROHM Semiconductors
// bd71837-regulator.c ROHM BD71837MWV regulator driver
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mfd/rohm-bd718x7.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/slab.h>
struct bd71837_pmic {
struct regulator_desc descs[BD71837_REGULATOR_CNT];
struct bd71837 *mfd;
struct platform_device *pdev;
struct regulator_dev *rdev[BD71837_REGULATOR_CNT];
};
/*
* BUCK1/2/3/4
* BUCK1RAMPRATE[1:0] BUCK1 DVS ramp rate setting
* 00: 10.00mV/usec 10mV 1uS
* 01: 5.00mV/usec 10mV 2uS
* 10: 2.50mV/usec 10mV 4uS
* 11: 1.25mV/usec 10mV 8uS
*/
static int bd71837_buck1234_set_ramp_delay(struct regulator_dev *rdev,
int ramp_delay)
{
struct bd71837_pmic *pmic = rdev_get_drvdata(rdev);
struct bd71837 *mfd = pmic->mfd;
int id = rdev->desc->id;
unsigned int ramp_value = BUCK_RAMPRATE_10P00MV;
dev_dbg(&pmic->pdev->dev, "Buck[%d] Set Ramp = %d\n", id + 1,
ramp_delay);
switch (ramp_delay) {
case 1 ... 1250:
ramp_value = BUCK_RAMPRATE_1P25MV;
break;
case 1251 ... 2500:
ramp_value = BUCK_RAMPRATE_2P50MV;
break;
case 2501 ... 5000:
ramp_value = BUCK_RAMPRATE_5P00MV;
break;
case 5001 ... 10000:
ramp_value = BUCK_RAMPRATE_10P00MV;
break;
default:
ramp_value = BUCK_RAMPRATE_10P00MV;
dev_err(&pmic->pdev->dev,
"%s: ramp_delay: %d not supported, setting 10000mV//us\n",
rdev->desc->name, ramp_delay);
}
return regmap_update_bits(mfd->regmap, BD71837_REG_BUCK1_CTRL + id,
BUCK_RAMPRATE_MASK, ramp_value << 6);
}
/* Bucks 1 to 4 support DVS. PWM mode is used when voltage is changed.
* Bucks 5 to 8 and LDOs can use PFM and must be disabled when voltage
* is changed. Hence we return -EBUSY for these if voltage is changed
* when BUCK/LDO is enabled.
*/
static int bd71837_set_voltage_sel_restricted(struct regulator_dev *rdev,
unsigned int sel)
{
if (regulator_is_enabled_regmap(rdev))
return -EBUSY;
return regulator_set_voltage_sel_regmap(rdev, sel);
}
static struct regulator_ops bd71837_ldo_regulator_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.list_voltage = regulator_list_voltage_linear_range,
.set_voltage_sel = bd71837_set_voltage_sel_restricted,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
};
static struct regulator_ops bd71837_ldo_regulator_nolinear_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.list_voltage = regulator_list_voltage_table,
.set_voltage_sel = bd71837_set_voltage_sel_restricted,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
};
static struct regulator_ops bd71837_buck_regulator_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.list_voltage = regulator_list_voltage_linear_range,
.set_voltage_sel = bd71837_set_voltage_sel_restricted,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
};
static struct regulator_ops bd71837_buck_regulator_nolinear_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.list_voltage = regulator_list_voltage_table,
.set_voltage_sel = bd71837_set_voltage_sel_restricted,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
};
static struct regulator_ops bd71837_buck1234_regulator_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.list_voltage = regulator_list_voltage_linear_range,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
.set_ramp_delay = bd71837_buck1234_set_ramp_delay,
};
/*
* BUCK1/2/3/4
* 0.70 to 1.30V (10mV step)
*/
static const struct regulator_linear_range bd71837_buck1234_voltage_ranges[] = {
REGULATOR_LINEAR_RANGE(700000, 0x00, 0x3C, 10000),
REGULATOR_LINEAR_RANGE(1300000, 0x3D, 0x3F, 0),
};
/*
* BUCK5
* 0.9V to 1.35V ()
*/
static const struct regulator_linear_range bd71837_buck5_voltage_ranges[] = {
REGULATOR_LINEAR_RANGE(700000, 0x00, 0x03, 100000),
REGULATOR_LINEAR_RANGE(1050000, 0x04, 0x05, 50000),
REGULATOR_LINEAR_RANGE(1200000, 0x06, 0x07, 150000),
};
/*
* BUCK6
* 3.0V to 3.3V (step 100mV)
*/
static const struct regulator_linear_range bd71837_buck6_voltage_ranges[] = {
REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000),
};
/*
* BUCK7
* 000 = 1.605V
* 001 = 1.695V
* 010 = 1.755V
* 011 = 1.8V (Initial)
* 100 = 1.845V
* 101 = 1.905V
* 110 = 1.95V
* 111 = 1.995V
*/
static const unsigned int buck_7_volts[] = {
1605000, 1695000, 1755000, 1800000, 1845000, 1905000, 1950000, 1995000
};
/*
* BUCK8
* 0.8V to 1.40V (step 10mV)
*/
static const struct regulator_linear_range bd71837_buck8_voltage_ranges[] = {
REGULATOR_LINEAR_RANGE(800000, 0x00, 0x3C, 10000),
REGULATOR_LINEAR_RANGE(1400000, 0x3D, 0x3F, 0),
};
/*
* LDO1
* 3.0 to 3.3V (100mV step)
*/
static const struct regulator_linear_range bd71837_ldo1_voltage_ranges[] = {
REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000),
};
/*
* LDO2
* 0.8 or 0.9V
*/
static const unsigned int ldo_2_volts[] = {
900000, 800000
};
/*
* LDO3
* 1.8 to 3.3V (100mV step)
*/
static const struct regulator_linear_range bd71837_ldo3_voltage_ranges[] = {
REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
};
/*
* LDO4
* 0.9 to 1.8V (100mV step)
*/
static const struct regulator_linear_range bd71837_ldo4_voltage_ranges[] = {
REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000),
REGULATOR_LINEAR_RANGE(1800000, 0x0A, 0x0F, 0),
};
/*
* LDO5
* 1.8 to 3.3V (100mV step)
*/
static const struct regulator_linear_range bd71837_ldo5_voltage_ranges[] = {
REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
};
/*
* LDO6
* 0.9 to 1.8V (100mV step)
*/
static const struct regulator_linear_range bd71837_ldo6_voltage_ranges[] = {
REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000),
REGULATOR_LINEAR_RANGE(1800000, 0x0A, 0x0F, 0),
};
/*
* LDO7
* 1.8 to 3.3V (100mV step)
*/
static const struct regulator_linear_range bd71837_ldo7_voltage_ranges[] = {
REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
};
static const struct regulator_desc bd71837_regulators[] = {
{
.name = "buck1",
.of_match = of_match_ptr("BUCK1"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71837_BUCK1,
.ops = &bd71837_buck1234_regulator_ops,
.type = REGULATOR_VOLTAGE,
.n_voltages = BD71837_BUCK1_VOLTAGE_NUM,
.linear_ranges = bd71837_buck1234_voltage_ranges,
.n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
.vsel_reg = BD71837_REG_BUCK1_VOLT_RUN,
.vsel_mask = BUCK1_RUN_MASK,
.enable_reg = BD71837_REG_BUCK1_CTRL,
.enable_mask = BD71837_BUCK_EN,
.owner = THIS_MODULE,
},
{
.name = "buck2",
.of_match = of_match_ptr("BUCK2"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71837_BUCK2,
.ops = &bd71837_buck1234_regulator_ops,
.type = REGULATOR_VOLTAGE,
.n_voltages = BD71837_BUCK2_VOLTAGE_NUM,
.linear_ranges = bd71837_buck1234_voltage_ranges,
.n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
.vsel_reg = BD71837_REG_BUCK2_VOLT_RUN,
.vsel_mask = BUCK2_RUN_MASK,
.enable_reg = BD71837_REG_BUCK2_CTRL,
.enable_mask = BD71837_BUCK_EN,
.owner = THIS_MODULE,
},
{
.name = "buck3",
.of_match = of_match_ptr("BUCK3"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71837_BUCK3,
.ops = &bd71837_buck1234_regulator_ops,
.type = REGULATOR_VOLTAGE,
.n_voltages = BD71837_BUCK3_VOLTAGE_NUM,
.linear_ranges = bd71837_buck1234_voltage_ranges,
.n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
.vsel_reg = BD71837_REG_BUCK3_VOLT_RUN,
.vsel_mask = BUCK3_RUN_MASK,
.enable_reg = BD71837_REG_BUCK3_CTRL,
.enable_mask = BD71837_BUCK_EN,
.owner = THIS_MODULE,
},
{
.name = "buck4",
.of_match = of_match_ptr("BUCK4"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71837_BUCK4,
.ops = &bd71837_buck1234_regulator_ops,
.type = REGULATOR_VOLTAGE,
.n_voltages = BD71837_BUCK4_VOLTAGE_NUM,
.linear_ranges = bd71837_buck1234_voltage_ranges,
.n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
.vsel_reg = BD71837_REG_BUCK4_VOLT_RUN,
.vsel_mask = BUCK4_RUN_MASK,
.enable_reg = BD71837_REG_BUCK4_CTRL,
.enable_mask = BD71837_BUCK_EN,
.owner = THIS_MODULE,
},
{
.name = "buck5",
.of_match = of_match_ptr("BUCK5"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71837_BUCK5,
.ops = &bd71837_buck_regulator_ops,
.type = REGULATOR_VOLTAGE,
.n_voltages = BD71837_BUCK5_VOLTAGE_NUM,
.linear_ranges = bd71837_buck5_voltage_ranges,
.n_linear_ranges = ARRAY_SIZE(bd71837_buck5_voltage_ranges),
.vsel_reg = BD71837_REG_BUCK5_VOLT,
.vsel_mask = BUCK5_MASK,
.enable_reg = BD71837_REG_BUCK5_CTRL,
.enable_mask = BD71837_BUCK_EN,
.owner = THIS_MODULE,
},
{
.name = "buck6",
.of_match = of_match_ptr("BUCK6"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71837_BUCK6,
.ops = &bd71837_buck_regulator_ops,
.type = REGULATOR_VOLTAGE,
.n_voltages = BD71837_BUCK6_VOLTAGE_NUM,
.linear_ranges = bd71837_buck6_voltage_ranges,
.n_linear_ranges = ARRAY_SIZE(bd71837_buck6_voltage_ranges),
.vsel_reg = BD71837_REG_BUCK6_VOLT,
.vsel_mask = BUCK6_MASK,
.enable_reg = BD71837_REG_BUCK6_CTRL,
.enable_mask = BD71837_BUCK_EN,
.owner = THIS_MODULE,
},
{
.name = "buck7",
.of_match = of_match_ptr("BUCK7"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71837_BUCK7,
.ops = &bd71837_buck_regulator_nolinear_ops,
.type = REGULATOR_VOLTAGE,
.volt_table = &buck_7_volts[0],
.n_voltages = ARRAY_SIZE(buck_7_volts),
.vsel_reg = BD71837_REG_BUCK7_VOLT,
.vsel_mask = BUCK7_MASK,
.enable_reg = BD71837_REG_BUCK7_CTRL,
.enable_mask = BD71837_BUCK_EN,
.owner = THIS_MODULE,
},
{
.name = "buck8",
.of_match = of_match_ptr("BUCK8"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71837_BUCK8,
.ops = &bd71837_buck_regulator_ops,
.type = REGULATOR_VOLTAGE,
.n_voltages = BD71837_BUCK8_VOLTAGE_NUM,
.linear_ranges = bd71837_buck8_voltage_ranges,
.n_linear_ranges = ARRAY_SIZE(bd71837_buck8_voltage_ranges),
.vsel_reg = BD71837_REG_BUCK8_VOLT,
.vsel_mask = BUCK8_MASK,
.enable_reg = BD71837_REG_BUCK8_CTRL,
.enable_mask = BD71837_BUCK_EN,
.owner = THIS_MODULE,
},
{
.name = "ldo1",
.of_match = of_match_ptr("LDO1"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71837_LDO1,
.ops = &bd71837_ldo_regulator_ops,
.type = REGULATOR_VOLTAGE,
.n_voltages = BD71837_LDO1_VOLTAGE_NUM,
.linear_ranges = bd71837_ldo1_voltage_ranges,
.n_linear_ranges = ARRAY_SIZE(bd71837_ldo1_voltage_ranges),
.vsel_reg = BD71837_REG_LDO1_VOLT,
.vsel_mask = LDO1_MASK,
.enable_reg = BD71837_REG_LDO1_VOLT,
.enable_mask = BD71837_LDO_EN,
.owner = THIS_MODULE,
},
{
.name = "ldo2",
.of_match = of_match_ptr("LDO2"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71837_LDO2,
.ops = &bd71837_ldo_regulator_nolinear_ops,
.type = REGULATOR_VOLTAGE,
.volt_table = &ldo_2_volts[0],
.vsel_reg = BD71837_REG_LDO2_VOLT,
.vsel_mask = LDO2_MASK,
.n_voltages = ARRAY_SIZE(ldo_2_volts),
.n_voltages = BD71837_LDO2_VOLTAGE_NUM,
.enable_reg = BD71837_REG_LDO2_VOLT,
.enable_mask = BD71837_LDO_EN,
.owner = THIS_MODULE,
},
{
.name = "ldo3",
.of_match = of_match_ptr("LDO3"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71837_LDO3,
.ops = &bd71837_ldo_regulator_ops,
.type = REGULATOR_VOLTAGE,
.n_voltages = BD71837_LDO3_VOLTAGE_NUM,
.linear_ranges = bd71837_ldo3_voltage_ranges,
.n_linear_ranges = ARRAY_SIZE(bd71837_ldo3_voltage_ranges),
.vsel_reg = BD71837_REG_LDO3_VOLT,
.vsel_mask = LDO3_MASK,
.enable_reg = BD71837_REG_LDO3_VOLT,
.enable_mask = BD71837_LDO_EN,
.owner = THIS_MODULE,
},
{
.name = "ldo4",
.of_match = of_match_ptr("LDO4"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71837_LDO4,
.ops = &bd71837_ldo_regulator_ops,
.type = REGULATOR_VOLTAGE,
.n_voltages = BD71837_LDO4_VOLTAGE_NUM,
.linear_ranges = bd71837_ldo4_voltage_ranges,
.n_linear_ranges = ARRAY_SIZE(bd71837_ldo4_voltage_ranges),
.vsel_reg = BD71837_REG_LDO4_VOLT,
.vsel_mask = LDO4_MASK,
.enable_reg = BD71837_REG_LDO4_VOLT,
.enable_mask = BD71837_LDO_EN,
.owner = THIS_MODULE,
},
{
.name = "ldo5",
.of_match = of_match_ptr("LDO5"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71837_LDO5,
.ops = &bd71837_ldo_regulator_ops,
.type = REGULATOR_VOLTAGE,
.n_voltages = BD71837_LDO5_VOLTAGE_NUM,
.linear_ranges = bd71837_ldo5_voltage_ranges,
.n_linear_ranges = ARRAY_SIZE(bd71837_ldo5_voltage_ranges),
/* LDO5 is supplied by buck6 */
.supply_name = "buck6",
.vsel_reg = BD71837_REG_LDO5_VOLT,
.vsel_mask = LDO5_MASK,
.enable_reg = BD71837_REG_LDO5_VOLT,
.enable_mask = BD71837_LDO_EN,
.owner = THIS_MODULE,
},
{
.name = "ldo6",
.of_match = of_match_ptr("LDO6"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71837_LDO6,
.ops = &bd71837_ldo_regulator_ops,
.type = REGULATOR_VOLTAGE,
.n_voltages = BD71837_LDO6_VOLTAGE_NUM,
.linear_ranges = bd71837_ldo6_voltage_ranges,
.n_linear_ranges = ARRAY_SIZE(bd71837_ldo6_voltage_ranges),
/* LDO6 is supplied by buck7 */
.supply_name = "buck7",
.vsel_reg = BD71837_REG_LDO6_VOLT,
.vsel_mask = LDO6_MASK,
.enable_reg = BD71837_REG_LDO6_VOLT,
.enable_mask = BD71837_LDO_EN,
.owner = THIS_MODULE,
},
{
.name = "ldo7",
.of_match = of_match_ptr("LDO7"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71837_LDO7,
.ops = &bd71837_ldo_regulator_ops,
.type = REGULATOR_VOLTAGE,
.n_voltages = BD71837_LDO7_VOLTAGE_NUM,
.linear_ranges = bd71837_ldo7_voltage_ranges,
.n_linear_ranges = ARRAY_SIZE(bd71837_ldo7_voltage_ranges),
.vsel_reg = BD71837_REG_LDO7_VOLT,
.vsel_mask = LDO7_MASK,
.enable_reg = BD71837_REG_LDO7_VOLT,
.enable_mask = BD71837_LDO_EN,
.owner = THIS_MODULE,
},
};
struct reg_init {
unsigned int reg;
unsigned int mask;
};
static int bd71837_probe(struct platform_device *pdev)
{
struct bd71837_pmic *pmic;
struct regulator_config config = { 0 };
struct reg_init pmic_regulator_inits[] = {
{
.reg = BD71837_REG_BUCK1_CTRL,
.mask = BD71837_BUCK_SEL,
}, {
.reg = BD71837_REG_BUCK2_CTRL,
.mask = BD71837_BUCK_SEL,
}, {
.reg = BD71837_REG_BUCK3_CTRL,
.mask = BD71837_BUCK_SEL,
}, {
.reg = BD71837_REG_BUCK4_CTRL,
.mask = BD71837_BUCK_SEL,
}, {
.reg = BD71837_REG_BUCK5_CTRL,
.mask = BD71837_BUCK_SEL,
}, {
.reg = BD71837_REG_BUCK6_CTRL,
.mask = BD71837_BUCK_SEL,
}, {
.reg = BD71837_REG_BUCK7_CTRL,
.mask = BD71837_BUCK_SEL,
}, {
.reg = BD71837_REG_BUCK8_CTRL,
.mask = BD71837_BUCK_SEL,
}, {
.reg = BD71837_REG_LDO1_VOLT,
.mask = BD71837_LDO_SEL,
}, {
.reg = BD71837_REG_LDO2_VOLT,
.mask = BD71837_LDO_SEL,
}, {
.reg = BD71837_REG_LDO3_VOLT,
.mask = BD71837_LDO_SEL,
}, {
.reg = BD71837_REG_LDO4_VOLT,
.mask = BD71837_LDO_SEL,
}, {
.reg = BD71837_REG_LDO5_VOLT,
.mask = BD71837_LDO_SEL,
}, {
.reg = BD71837_REG_LDO6_VOLT,
.mask = BD71837_LDO_SEL,
}, {
.reg = BD71837_REG_LDO7_VOLT,
.mask = BD71837_LDO_SEL,
}
};
int i, err;
pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
if (!pmic)
return -ENOMEM;
memcpy(pmic->descs, bd71837_regulators, sizeof(pmic->descs));
pmic->pdev = pdev;
pmic->mfd = dev_get_drvdata(pdev->dev.parent);
if (!pmic->mfd) {
dev_err(&pdev->dev, "No MFD driver data\n");
err = -EINVAL;
goto err;
}
platform_set_drvdata(pdev, pmic);
/* Register LOCK release */
err = regmap_update_bits(pmic->mfd->regmap, BD71837_REG_REGLOCK,
(REGLOCK_PWRSEQ | REGLOCK_VREG), 0);
if (err) {
dev_err(&pmic->pdev->dev, "Failed to unlock PMIC (%d)\n", err);
goto err;
} else {
dev_dbg(&pmic->pdev->dev, "Unlocked lock register 0x%x\n",
BD71837_REG_REGLOCK);
}
/*
* There is a HW quirk in BD71837. The shutdown sequence timings for
* bucks/LDOs which are controlled via register interface are changed.
* At PMIC poweroff the voltage for BUCK6/7 is cut immediately at the
* beginning of shut-down sequence. As bucks 6 and 7 are parent
* supplies for LDO5 and LDO6 - this causes LDO5/6 voltage
* monitoring to errorneously detect under voltage and force PMIC to
* emergency state instead of poweroff. In order to avoid this we
* disable voltage monitoring for LDO5 and LDO6
*/
err = regmap_update_bits(pmic->mfd->regmap, BD718XX_REG_MVRFLTMASK2,
BD718XX_LDO5_VRMON80 | BD718XX_LDO6_VRMON80,
BD718XX_LDO5_VRMON80 | BD718XX_LDO6_VRMON80);
if (err) {
dev_err(&pmic->pdev->dev,
"Failed to disable voltage monitoring\n");
goto err;
}
for (i = 0; i < ARRAY_SIZE(pmic_regulator_inits); i++) {
struct regulator_desc *desc;
struct regulator_dev *rdev;
desc = &pmic->descs[i];
config.dev = pdev->dev.parent;
config.driver_data = pmic;
config.regmap = pmic->mfd->regmap;
rdev = devm_regulator_register(&pdev->dev, desc, &config);
if (IS_ERR(rdev)) {
dev_err(pmic->mfd->dev,
"failed to register %s regulator\n",
desc->name);
err = PTR_ERR(rdev);
goto err;
}
/* Regulator register gets the regulator constraints and
* applies them (set_machine_constraints). This should have
* turned the control register(s) to correct values and we
* can now switch the control from PMIC state machine to the
* register interface
*/
err = regmap_update_bits(pmic->mfd->regmap,
pmic_regulator_inits[i].reg,
pmic_regulator_inits[i].mask,
0xFFFFFFFF);
if (err) {
dev_err(&pmic->pdev->dev,
"Failed to write BUCK/LDO SEL bit for (%s)\n",
desc->name);
goto err;
}
pmic->rdev[i] = rdev;
}
err:
return err;
}
static struct platform_driver bd71837_regulator = {
.driver = {
.name = "bd71837-pmic",
},
.probe = bd71837_probe,
};
module_platform_driver(bd71837_regulator);
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
MODULE_DESCRIPTION("BD71837 voltage regulator driver");
MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load Diff

View File

@ -426,19 +426,24 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RO(name);
static ssize_t regulator_print_opmode(char *buf, int mode)
static const char *regulator_opmode_to_str(int mode)
{
switch (mode) {
case REGULATOR_MODE_FAST:
return sprintf(buf, "fast\n");
return "fast";
case REGULATOR_MODE_NORMAL:
return sprintf(buf, "normal\n");
return "normal";
case REGULATOR_MODE_IDLE:
return sprintf(buf, "idle\n");
return "idle";
case REGULATOR_MODE_STANDBY:
return sprintf(buf, "standby\n");
return "standby";
}
return sprintf(buf, "unknown\n");
return "unknown";
}
static ssize_t regulator_print_opmode(char *buf, int mode)
{
return sprintf(buf, "%s\n", regulator_opmode_to_str(mode));
}
static ssize_t regulator_opmode_show(struct device *dev,
@ -2783,6 +2788,11 @@ static int regulator_map_voltage(struct regulator_dev *rdev, int min_uV,
if (desc->ops->list_voltage == regulator_list_voltage_linear_range)
return regulator_map_voltage_linear_range(rdev, min_uV, max_uV);
if (desc->ops->list_voltage ==
regulator_list_voltage_pickable_linear_range)
return regulator_map_voltage_pickable_linear_range(rdev,
min_uV, max_uV);
return regulator_map_voltage_iterate(rdev, min_uV, max_uV);
}
@ -3470,21 +3480,23 @@ int regulator_set_current_limit(struct regulator *regulator,
}
EXPORT_SYMBOL_GPL(regulator_set_current_limit);
static int _regulator_get_current_limit_unlocked(struct regulator_dev *rdev)
{
/* sanity check */
if (!rdev->desc->ops->get_current_limit)
return -EINVAL;
return rdev->desc->ops->get_current_limit(rdev);
}
static int _regulator_get_current_limit(struct regulator_dev *rdev)
{
int ret;
regulator_lock(rdev);
/* sanity check */
if (!rdev->desc->ops->get_current_limit) {
ret = -EINVAL;
goto out;
}
ret = rdev->desc->ops->get_current_limit(rdev);
out:
ret = _regulator_get_current_limit_unlocked(rdev);
regulator_unlock(rdev);
return ret;
}
@ -3549,21 +3561,23 @@ int regulator_set_mode(struct regulator *regulator, unsigned int mode)
}
EXPORT_SYMBOL_GPL(regulator_set_mode);
static unsigned int _regulator_get_mode_unlocked(struct regulator_dev *rdev)
{
/* sanity check */
if (!rdev->desc->ops->get_mode)
return -EINVAL;
return rdev->desc->ops->get_mode(rdev);
}
static unsigned int _regulator_get_mode(struct regulator_dev *rdev)
{
int ret;
regulator_lock(rdev);
/* sanity check */
if (!rdev->desc->ops->get_mode) {
ret = -EINVAL;
goto out;
}
ret = rdev->desc->ops->get_mode(rdev);
out:
ret = _regulator_get_mode_unlocked(rdev);
regulator_unlock(rdev);
return ret;
}
@ -4455,41 +4469,33 @@ void regulator_unregister(struct regulator_dev *rdev)
EXPORT_SYMBOL_GPL(regulator_unregister);
#ifdef CONFIG_SUSPEND
static int _regulator_suspend(struct device *dev, void *data)
{
struct regulator_dev *rdev = dev_to_rdev(dev);
suspend_state_t *state = data;
int ret;
regulator_lock(rdev);
ret = suspend_set_state(rdev, *state);
regulator_unlock(rdev);
return ret;
}
/**
* regulator_suspend - prepare regulators for system wide suspend
* @state: system suspend state
* @dev: ``&struct device`` pointer that is passed to _regulator_suspend()
*
* Configure each regulator with it's suspend operating parameters for state.
*/
static int regulator_suspend(struct device *dev)
{
struct regulator_dev *rdev = dev_to_rdev(dev);
suspend_state_t state = pm_suspend_target_state;
int ret;
return class_for_each_device(&regulator_class, NULL, &state,
_regulator_suspend);
regulator_lock(rdev);
ret = suspend_set_state(rdev, state);
regulator_unlock(rdev);
return ret;
}
static int _regulator_resume(struct device *dev, void *data)
static int regulator_resume(struct device *dev)
{
int ret = 0;
suspend_state_t state = pm_suspend_target_state;
struct regulator_dev *rdev = dev_to_rdev(dev);
suspend_state_t *state = data;
struct regulator_state *rstate;
int ret = 0;
rstate = regulator_get_suspend_state(rdev, *state);
rstate = regulator_get_suspend_state(rdev, state);
if (rstate == NULL)
return 0;
@ -4504,15 +4510,6 @@ static int _regulator_resume(struct device *dev, void *data)
return ret;
}
static int regulator_resume(struct device *dev)
{
suspend_state_t state = pm_suspend_target_state;
return class_for_each_device(&regulator_class, NULL, &state,
_regulator_resume);
}
#else /* !CONFIG_SUSPEND */
#define regulator_suspend NULL
@ -4670,17 +4667,23 @@ static void regulator_summary_show_subtree(struct seq_file *s,
struct regulation_constraints *c;
struct regulator *consumer;
struct summary_data summary_data;
unsigned int opmode;
if (!rdev)
return;
seq_printf(s, "%*s%-*s %3d %4d %6d ",
regulator_lock_nested(rdev, level);
opmode = _regulator_get_mode_unlocked(rdev);
seq_printf(s, "%*s%-*s %3d %4d %6d %7s ",
level * 3 + 1, "",
30 - level * 3, rdev_get_name(rdev),
rdev->use_count, rdev->open_count, rdev->bypass_count);
rdev->use_count, rdev->open_count, rdev->bypass_count,
regulator_opmode_to_str(opmode));
seq_printf(s, "%5dmV ", _regulator_get_voltage(rdev) / 1000);
seq_printf(s, "%5dmA ", _regulator_get_current_limit(rdev) / 1000);
seq_printf(s, "%5dmA ",
_regulator_get_current_limit_unlocked(rdev) / 1000);
c = rdev->constraints;
if (c) {
@ -4709,7 +4712,8 @@ static void regulator_summary_show_subtree(struct seq_file *s,
switch (rdev->desc->type) {
case REGULATOR_VOLTAGE:
seq_printf(s, "%37dmV %5dmV",
seq_printf(s, "%37dmA %5dmV %5dmV",
consumer->uA_load / 1000,
consumer->voltage[PM_SUSPEND_ON].min_uV / 1000,
consumer->voltage[PM_SUSPEND_ON].max_uV / 1000);
break;
@ -4726,6 +4730,8 @@ static void regulator_summary_show_subtree(struct seq_file *s,
class_for_each_device(&regulator_class, NULL, &summary_data,
regulator_summary_show_children);
regulator_unlock(rdev);
}
static int regulator_summary_show_roots(struct device *dev, void *data)
@ -4741,8 +4747,8 @@ static int regulator_summary_show_roots(struct device *dev, void *data)
static int regulator_summary_show(struct seq_file *s, void *data)
{
seq_puts(s, " regulator use open bypass voltage current min max\n");
seq_puts(s, "-------------------------------------------------------------------------------\n");
seq_puts(s, " regulator use open bypass opmode voltage current min max\n");
seq_puts(s, "---------------------------------------------------------------------------------------\n");
class_for_each_device(&regulator_class, NULL, s,
regulator_summary_show_roots);

View File

@ -420,7 +420,7 @@ static int da9052_regulator_probe(struct platform_device *pdev)
config.dev = &pdev->dev;
config.driver_data = regulator;
config.regmap = da9052->regmap;
if (pdata && pdata->regulators) {
if (pdata) {
config.init_data = pdata->regulators[cell->id];
} else {
#ifdef CONFIG_OF

View File

@ -612,7 +612,7 @@ static int da9055_regulator_probe(struct platform_device *pdev)
config.driver_data = regulator;
config.regmap = da9055->regmap;
if (pdata && pdata->regulators) {
if (pdata) {
config.init_data = pdata->regulators[pdev->id];
} else {
ret = da9055_regulator_dt_init(pdev, regulator, &config,

View File

@ -294,11 +294,11 @@ static struct da9211_pdata *da9211_parse_regulators_dt(
pdata->init_data[n] = da9211_matches[i].init_data;
pdata->reg_node[n] = da9211_matches[i].of_node;
pdata->gpiod_ren[n] = devm_gpiod_get_from_of_node(dev,
da9211_matches[i].of_node,
"enable",
0,
GPIOD_OUT_HIGH,
"da9211-enable");
da9211_matches[i].of_node,
"enable",
0,
GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
"da9211-enable");
n++;
}

View File

@ -43,7 +43,6 @@ struct platform_device *regulator_register_always_on(int id, const char *name,
}
data->cfg.microvolts = uv;
data->cfg.gpio = -EINVAL;
data->cfg.enabled_at_boot = 1;
data->cfg.init_data = &data->init_data;

View File

@ -24,10 +24,9 @@
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/fixed.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/machine.h>
@ -78,15 +77,16 @@ of_get_fixed_voltage_config(struct device *dev,
if (init_data->constraints.boot_on)
config->enabled_at_boot = true;
config->gpio = of_get_named_gpio(np, "gpio", 0);
if ((config->gpio < 0) && (config->gpio != -ENOENT))
return ERR_PTR(config->gpio);
of_property_read_u32(np, "startup-delay-us", &config->startup_delay);
config->enable_high = of_property_read_bool(np, "enable-active-high");
config->gpio_is_open_drain = of_property_read_bool(np,
"gpio-open-drain");
/*
* FIXME: we pulled active low/high and open drain handling into
* gpiolib so it will be handled there. Delete this in the second
* step when we also remove the custom inversion handling for all
* legacy boardfiles.
*/
config->enable_high = 1;
config->gpio_is_open_drain = 0;
if (of_find_property(np, "vin-supply", NULL))
config->input_supply = "vin";
@ -102,6 +102,7 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
struct fixed_voltage_config *config;
struct fixed_voltage_data *drvdata;
struct regulator_config cfg = { };
enum gpiod_flags gflags;
int ret;
drvdata = devm_kzalloc(&pdev->dev, sizeof(struct fixed_voltage_data),
@ -150,25 +151,41 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
drvdata->desc.fixed_uV = config->microvolts;
if (gpio_is_valid(config->gpio)) {
cfg.ena_gpio = config->gpio;
if (pdev->dev.of_node)
cfg.ena_gpio_initialized = true;
}
cfg.ena_gpio_invert = !config->enable_high;
if (config->enabled_at_boot) {
if (config->enable_high)
cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH;
gflags = GPIOD_OUT_HIGH;
else
cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW;
gflags = GPIOD_OUT_LOW;
} else {
if (config->enable_high)
cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW;
gflags = GPIOD_OUT_LOW;
else
cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH;
gflags = GPIOD_OUT_HIGH;
}
if (config->gpio_is_open_drain)
cfg.ena_gpio_flags |= GPIOF_OPEN_DRAIN;
if (config->gpio_is_open_drain) {
if (gflags == GPIOD_OUT_HIGH)
gflags = GPIOD_OUT_HIGH_OPEN_DRAIN;
else
gflags = GPIOD_OUT_LOW_OPEN_DRAIN;
}
/*
* Some fixed regulators share the enable line between two
* regulators which makes it necessary to get a handle on the
* same descriptor for two different consumers. This will get
* the GPIO descriptor, but only the first call will initialize
* it so any flags such as inversion or open drain will only
* be set up by the first caller and assumed identical on the
* next caller.
*
* FIXME: find a better way to deal with this.
*/
gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
cfg.ena_gpiod = devm_gpiod_get_optional(&pdev->dev, NULL, gflags);
if (IS_ERR(cfg.ena_gpiod))
return PTR_ERR(cfg.ena_gpiod);
cfg.dev = &pdev->dev;
cfg.init_data = config->init_data;

View File

@ -103,6 +103,128 @@ int regulator_disable_regmap(struct regulator_dev *rdev)
}
EXPORT_SYMBOL_GPL(regulator_disable_regmap);
static int regulator_range_selector_to_index(struct regulator_dev *rdev,
unsigned int rval)
{
int i;
if (!rdev->desc->linear_range_selectors)
return -EINVAL;
rval &= rdev->desc->vsel_range_mask;
for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
if (rdev->desc->linear_range_selectors[i] == rval)
return i;
}
return -EINVAL;
}
/**
* regulator_get_voltage_sel_pickable_regmap - pickable range get_voltage_sel
*
* @rdev: regulator to operate on
*
* Regulators that use regmap for their register I/O and use pickable
* ranges can set the vsel_reg, vsel_mask, vsel_range_reg and vsel_range_mask
* fields in their descriptor and then use this as their get_voltage_vsel
* operation, saving some code.
*/
int regulator_get_voltage_sel_pickable_regmap(struct regulator_dev *rdev)
{
unsigned int r_val;
int range;
unsigned int val;
int ret, i;
unsigned int voltages_in_range = 0;
if (!rdev->desc->linear_ranges)
return -EINVAL;
ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val);
if (ret != 0)
return ret;
ret = regmap_read(rdev->regmap, rdev->desc->vsel_range_reg, &r_val);
if (ret != 0)
return ret;
val &= rdev->desc->vsel_mask;
val >>= ffs(rdev->desc->vsel_mask) - 1;
range = regulator_range_selector_to_index(rdev, r_val);
if (range < 0)
return -EINVAL;
for (i = 0; i < range; i++)
voltages_in_range += (rdev->desc->linear_ranges[i].max_sel -
rdev->desc->linear_ranges[i].min_sel) + 1;
return val + voltages_in_range;
}
EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_pickable_regmap);
/**
* regulator_set_voltage_sel_pickable_regmap - pickable range set_voltage_sel
*
* @rdev: regulator to operate on
* @sel: Selector to set
*
* Regulators that use regmap for their register I/O and use pickable
* ranges can set the vsel_reg, vsel_mask, vsel_range_reg and vsel_range_mask
* fields in their descriptor and then use this as their set_voltage_vsel
* operation, saving some code.
*/
int regulator_set_voltage_sel_pickable_regmap(struct regulator_dev *rdev,
unsigned int sel)
{
unsigned int range;
int ret, i;
unsigned int voltages_in_range = 0;
for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
voltages_in_range = (rdev->desc->linear_ranges[i].max_sel -
rdev->desc->linear_ranges[i].min_sel) + 1;
if (sel < voltages_in_range)
break;
sel -= voltages_in_range;
}
if (i == rdev->desc->n_linear_ranges)
return -EINVAL;
sel <<= ffs(rdev->desc->vsel_mask) - 1;
sel += rdev->desc->linear_ranges[i].min_sel;
range = rdev->desc->linear_range_selectors[i];
if (rdev->desc->vsel_reg == rdev->desc->vsel_range_reg) {
ret = regmap_update_bits(rdev->regmap,
rdev->desc->vsel_reg,
rdev->desc->vsel_range_mask |
rdev->desc->vsel_mask, sel | range);
} else {
ret = regmap_update_bits(rdev->regmap,
rdev->desc->vsel_range_reg,
rdev->desc->vsel_range_mask, range);
if (ret)
return ret;
ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
rdev->desc->vsel_mask, sel);
}
if (ret)
return ret;
if (rdev->desc->apply_bit)
ret = regmap_update_bits(rdev->regmap, rdev->desc->apply_reg,
rdev->desc->apply_bit,
rdev->desc->apply_bit);
return ret;
}
EXPORT_SYMBOL_GPL(regulator_set_voltage_sel_pickable_regmap);
/**
* regulator_get_voltage_sel_regmap - standard get_voltage_sel for regmap users
*
@ -321,20 +443,91 @@ int regulator_map_voltage_linear_range(struct regulator_dev *rdev,
ret += range->min_sel;
break;
/*
* Map back into a voltage to verify we're still in bounds.
* If we are not, then continue checking rest of the ranges.
*/
voltage = rdev->desc->ops->list_voltage(rdev, ret);
if (voltage >= min_uV && voltage <= max_uV)
break;
}
if (i == rdev->desc->n_linear_ranges)
return -EINVAL;
/* Map back into a voltage to verify we're still in bounds */
voltage = rdev->desc->ops->list_voltage(rdev, ret);
if (voltage < min_uV || voltage > max_uV)
return ret;
}
EXPORT_SYMBOL_GPL(regulator_map_voltage_linear_range);
/**
* regulator_map_voltage_pickable_linear_range - map_voltage, pickable ranges
*
* @rdev: Regulator to operate on
* @min_uV: Lower bound for voltage
* @max_uV: Upper bound for voltage
*
* Drivers providing pickable linear_ranges in their descriptor can use
* this as their map_voltage() callback.
*/
int regulator_map_voltage_pickable_linear_range(struct regulator_dev *rdev,
int min_uV, int max_uV)
{
const struct regulator_linear_range *range;
int ret = -EINVAL;
int voltage, i;
unsigned int selector = 0;
if (!rdev->desc->n_linear_ranges) {
BUG_ON(!rdev->desc->n_linear_ranges);
return -EINVAL;
}
for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
int linear_max_uV;
range = &rdev->desc->linear_ranges[i];
linear_max_uV = range->min_uV +
(range->max_sel - range->min_sel) * range->uV_step;
if (!(min_uV <= linear_max_uV && max_uV >= range->min_uV)) {
selector += (range->max_sel - range->min_sel + 1);
continue;
}
if (min_uV <= range->min_uV)
min_uV = range->min_uV;
/* range->uV_step == 0 means fixed voltage range */
if (range->uV_step == 0) {
ret = 0;
} else {
ret = DIV_ROUND_UP(min_uV - range->min_uV,
range->uV_step);
if (ret < 0)
return ret;
}
ret += selector;
voltage = rdev->desc->ops->list_voltage(rdev, ret);
/*
* Map back into a voltage to verify we're still in bounds.
* We may have overlapping voltage ranges. Hence we don't
* exit but retry until we have checked all ranges.
*/
if (voltage < min_uV || voltage > max_uV)
selector += (range->max_sel - range->min_sel + 1);
else
break;
}
if (i == rdev->desc->n_linear_ranges)
return -EINVAL;
return ret;
}
EXPORT_SYMBOL_GPL(regulator_map_voltage_linear_range);
EXPORT_SYMBOL_GPL(regulator_map_voltage_pickable_linear_range);
/**
* regulator_list_voltage_linear - List voltages with simple calculation
@ -360,6 +553,46 @@ int regulator_list_voltage_linear(struct regulator_dev *rdev,
}
EXPORT_SYMBOL_GPL(regulator_list_voltage_linear);
/**
* regulator_list_voltage_pickable_linear_range - pickable range list voltages
*
* @rdev: Regulator device
* @selector: Selector to convert into a voltage
*
* list_voltage() operation, intended to be used by drivers utilizing pickable
* ranges helpers.
*/
int regulator_list_voltage_pickable_linear_range(struct regulator_dev *rdev,
unsigned int selector)
{
const struct regulator_linear_range *range;
int i;
unsigned int all_sels = 0;
if (!rdev->desc->n_linear_ranges) {
BUG_ON(!rdev->desc->n_linear_ranges);
return -EINVAL;
}
for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
unsigned int sels_in_range;
range = &rdev->desc->linear_ranges[i];
sels_in_range = range->max_sel - range->min_sel;
if (all_sels + sels_in_range >= selector) {
selector -= all_sels;
return range->min_uV + (range->uV_step * selector);
}
all_sels += (sels_in_range + 1);
}
return -EINVAL;
}
EXPORT_SYMBOL_GPL(regulator_list_voltage_pickable_linear_range);
/**
* regulator_list_voltage_linear_range - List voltages for linear ranges
*

View File

@ -84,6 +84,7 @@ static const struct regulator_desc isl9305_regulators[] = {
.enable_mask = ISL9305_DCD1_EN,
.supply_name = "VINDCD1",
.ops = &isl9305_ops,
.owner = THIS_MODULE,
},
[ISL9305_DCD2] = {
.name = "DCD2",
@ -98,6 +99,7 @@ static const struct regulator_desc isl9305_regulators[] = {
.enable_mask = ISL9305_DCD2_EN,
.supply_name = "VINDCD2",
.ops = &isl9305_ops,
.owner = THIS_MODULE,
},
[ISL9305_LDO1] = {
.name = "LDO1",
@ -112,6 +114,7 @@ static const struct regulator_desc isl9305_regulators[] = {
.enable_mask = ISL9305_LDO1_EN,
.supply_name = "VINLDO1",
.ops = &isl9305_ops,
.owner = THIS_MODULE,
},
[ISL9305_LDO2] = {
.name = "LDO2",
@ -126,6 +129,7 @@ static const struct regulator_desc isl9305_regulators[] = {
.enable_mask = ISL9305_LDO2_EN,
.supply_name = "VINLDO2",
.ops = &isl9305_ops,
.owner = THIS_MODULE,
},
};

View File

@ -227,9 +227,11 @@ static struct gpio_desc *lm363x_regulator_of_get_enable_gpio(struct device *dev,
*/
switch (id) {
case LM3632_LDO_POS:
return devm_gpiod_get_index_optional(dev, "enable", 0, GPIOD_OUT_LOW);
return devm_gpiod_get_index_optional(dev, "enable", 0,
GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
case LM3632_LDO_NEG:
return devm_gpiod_get_index_optional(dev, "enable", 1, GPIOD_OUT_LOW);
return devm_gpiod_get_index_optional(dev, "enable", 1,
GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
default:
return NULL;
}

View File

@ -0,0 +1,254 @@
// SPDX-License-Identifier: GPL-2.0
//
// Lochnagar regulator driver
//
// Copyright (c) 2017-2018 Cirrus Logic, Inc. and
// Cirrus Logic International Semiconductor Ltd.
//
// Author: Charles Keepax <ckeepax@opensource.cirrus.com>
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/mfd/lochnagar.h>
static const struct regulator_ops lochnagar_micvdd_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.list_voltage = regulator_list_voltage_linear_range,
.map_voltage = regulator_map_voltage_linear_range,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
};
static const struct regulator_linear_range lochnagar_micvdd_ranges[] = {
REGULATOR_LINEAR_RANGE(1000000, 0, 0xC, 50000),
REGULATOR_LINEAR_RANGE(1700000, 0xD, 0x1F, 100000),
};
static int lochnagar_micbias_enable(struct regulator_dev *rdev)
{
struct lochnagar *lochnagar = rdev_get_drvdata(rdev);
int ret;
mutex_lock(&lochnagar->analogue_config_lock);
ret = regulator_enable_regmap(rdev);
if (ret < 0)
goto err;
ret = lochnagar_update_config(lochnagar);
err:
mutex_unlock(&lochnagar->analogue_config_lock);
return ret;
}
static int lochnagar_micbias_disable(struct regulator_dev *rdev)
{
struct lochnagar *lochnagar = rdev_get_drvdata(rdev);
int ret;
mutex_lock(&lochnagar->analogue_config_lock);
ret = regulator_disable_regmap(rdev);
if (ret < 0)
goto err;
ret = lochnagar_update_config(lochnagar);
err:
mutex_unlock(&lochnagar->analogue_config_lock);
return ret;
}
static const struct regulator_ops lochnagar_micbias_ops = {
.enable = lochnagar_micbias_enable,
.disable = lochnagar_micbias_disable,
.is_enabled = regulator_is_enabled_regmap,
};
static const struct regulator_ops lochnagar_vddcore_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.list_voltage = regulator_list_voltage_linear_range,
.map_voltage = regulator_map_voltage_linear_range,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
};
static const struct regulator_linear_range lochnagar_vddcore_ranges[] = {
REGULATOR_LINEAR_RANGE(600000, 0x8, 0x41, 12500),
};
enum lochnagar_regulators {
LOCHNAGAR_MICVDD,
LOCHNAGAR_MIC1VDD,
LOCHNAGAR_MIC2VDD,
LOCHNAGAR_VDDCORE,
};
static int lochnagar_micbias_of_parse(struct device_node *np,
const struct regulator_desc *desc,
struct regulator_config *config)
{
struct lochnagar *lochnagar = config->driver_data;
int shift = (desc->id - LOCHNAGAR_MIC1VDD) *
LOCHNAGAR2_P2_MICBIAS_SRC_SHIFT;
int mask = LOCHNAGAR2_P1_MICBIAS_SRC_MASK << shift;
unsigned int val;
int ret;
ret = of_property_read_u32(np, "cirrus,micbias-input", &val);
if (ret >= 0) {
mutex_lock(&lochnagar->analogue_config_lock);
ret = regmap_update_bits(lochnagar->regmap,
LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
mask, val << shift);
mutex_unlock(&lochnagar->analogue_config_lock);
if (ret < 0) {
dev_err(lochnagar->dev,
"Failed to update micbias source: %d\n", ret);
return ret;
}
}
return 0;
}
static const struct regulator_desc lochnagar_regulators[] = {
[LOCHNAGAR_MICVDD] = {
.name = "MICVDD",
.supply_name = "SYSVDD",
.type = REGULATOR_VOLTAGE,
.n_voltages = 32,
.ops = &lochnagar_micvdd_ops,
.id = LOCHNAGAR_MICVDD,
.of_match = of_match_ptr("MICVDD"),
.enable_reg = LOCHNAGAR2_MICVDD_CTRL1,
.enable_mask = LOCHNAGAR2_MICVDD_REG_ENA_MASK,
.vsel_reg = LOCHNAGAR2_MICVDD_CTRL2,
.vsel_mask = LOCHNAGAR2_MICVDD_VSEL_MASK,
.linear_ranges = lochnagar_micvdd_ranges,
.n_linear_ranges = ARRAY_SIZE(lochnagar_micvdd_ranges),
.enable_time = 3000,
.ramp_delay = 1000,
.owner = THIS_MODULE,
},
[LOCHNAGAR_MIC1VDD] = {
.name = "MIC1VDD",
.supply_name = "MICBIAS1",
.type = REGULATOR_VOLTAGE,
.ops = &lochnagar_micbias_ops,
.id = LOCHNAGAR_MIC1VDD,
.of_match = of_match_ptr("MIC1VDD"),
.of_parse_cb = lochnagar_micbias_of_parse,
.enable_reg = LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
.enable_mask = LOCHNAGAR2_P1_INPUT_BIAS_ENA_MASK,
.owner = THIS_MODULE,
},
[LOCHNAGAR_MIC2VDD] = {
.name = "MIC2VDD",
.supply_name = "MICBIAS2",
.type = REGULATOR_VOLTAGE,
.ops = &lochnagar_micbias_ops,
.id = LOCHNAGAR_MIC2VDD,
.of_match = of_match_ptr("MIC2VDD"),
.of_parse_cb = lochnagar_micbias_of_parse,
.enable_reg = LOCHNAGAR2_ANALOGUE_PATH_CTRL2,
.enable_mask = LOCHNAGAR2_P2_INPUT_BIAS_ENA_MASK,
.owner = THIS_MODULE,
},
[LOCHNAGAR_VDDCORE] = {
.name = "VDDCORE",
.supply_name = "SYSVDD",
.type = REGULATOR_VOLTAGE,
.n_voltages = 57,
.ops = &lochnagar_vddcore_ops,
.id = LOCHNAGAR_VDDCORE,
.of_match = of_match_ptr("VDDCORE"),
.enable_reg = LOCHNAGAR2_VDDCORE_CDC_CTRL1,
.enable_mask = LOCHNAGAR2_VDDCORE_CDC_REG_ENA_MASK,
.vsel_reg = LOCHNAGAR2_VDDCORE_CDC_CTRL2,
.vsel_mask = LOCHNAGAR2_VDDCORE_CDC_VSEL_MASK,
.linear_ranges = lochnagar_vddcore_ranges,
.n_linear_ranges = ARRAY_SIZE(lochnagar_vddcore_ranges),
.enable_time = 3000,
.ramp_delay = 1000,
.owner = THIS_MODULE,
},
};
static int lochnagar_regulator_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct lochnagar *lochnagar = dev_get_drvdata(dev->parent);
struct regulator_config config = { };
struct regulator_dev *rdev;
int ret, i;
config.dev = lochnagar->dev;
config.regmap = lochnagar->regmap;
config.driver_data = lochnagar;
for (i = 0; i < ARRAY_SIZE(lochnagar_regulators); i++) {
const struct regulator_desc *desc = &lochnagar_regulators[i];
rdev = devm_regulator_register(dev, desc, &config);
if (IS_ERR(rdev)) {
ret = PTR_ERR(rdev);
dev_err(dev, "Failed to register %s regulator: %d\n",
desc->name, ret);
return ret;
}
}
return 0;
}
static struct platform_driver lochnagar_regulator_driver = {
.driver = {
.name = "lochnagar-regulator",
},
.probe = lochnagar_regulator_probe,
};
module_platform_driver(lochnagar_regulator_driver);
MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
MODULE_DESCRIPTION("Regulator driver for Cirrus Logic Lochnagar Board");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:lochnagar-regulator");

View File

@ -503,9 +503,10 @@ static int lp8788_config_ldo_enable_mode(struct platform_device *pdev,
/* FIXME: check default mode for GPIO here: high or low? */
ldo->ena_gpiod = devm_gpiod_get_index_optional(&pdev->dev,
"enable",
enable_id,
GPIOD_OUT_HIGH);
"enable",
enable_id,
GPIOD_OUT_HIGH |
GPIOD_FLAGS_BIT_NONEXCLUSIVE);
if (IS_ERR(ldo->ena_gpiod))
return PTR_ERR(ldo->ena_gpiod);

View File

@ -230,6 +230,7 @@ static int max8952_pmic_probe(struct i2c_client *client,
gflags = GPIOD_OUT_HIGH;
else
gflags = GPIOD_OUT_LOW;
gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
gpiod = devm_gpiod_get_optional(&client->dev,
"max8952,en",
gflags);

View File

@ -758,6 +758,7 @@ static int max8973_probe(struct i2c_client *client,
gflags = GPIOD_OUT_HIGH;
else
gflags = GPIOD_OUT_LOW;
gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
gpiod = devm_gpiod_get_optional(&client->dev,
"maxim,enable",
gflags);

View File

@ -929,8 +929,8 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,
break;
if (i == ARRAY_SIZE(regulators)) {
dev_warn(&pdev->dev, "don't know how to configure regulator %s\n",
reg_np->name);
dev_warn(&pdev->dev, "don't know how to configure regulator %pOFn\n",
reg_np);
continue;
}

View File

@ -203,7 +203,7 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
if (!found)
dev_warn(&pdev->dev,
"Unknown regulator: %s\n", child->name);
"Unknown regulator: %pOFn\n", child);
}
of_node_put(parent);

View File

@ -95,8 +95,8 @@ static void of_get_regulation_constraints(struct device_node *np,
if (!ret)
constraints->settling_time_up = pval;
if (constraints->settling_time_up && constraints->settling_time) {
pr_warn("%s: ambiguous configuration for settling time, ignoring 'regulator-settling-time-up-us'\n",
np->name);
pr_warn("%pOFn: ambiguous configuration for settling time, ignoring 'regulator-settling-time-up-us'\n",
np);
constraints->settling_time_up = 0;
}
@ -105,8 +105,8 @@ static void of_get_regulation_constraints(struct device_node *np,
if (!ret)
constraints->settling_time_down = pval;
if (constraints->settling_time_down && constraints->settling_time) {
pr_warn("%s: ambiguous configuration for settling time, ignoring 'regulator-settling-time-down-us'\n",
np->name);
pr_warn("%pOFn: ambiguous configuration for settling time, ignoring 'regulator-settling-time-down-us'\n",
np);
constraints->settling_time_down = 0;
}
@ -127,12 +127,12 @@ static void of_get_regulation_constraints(struct device_node *np,
if (desc && desc->of_map_mode) {
mode = desc->of_map_mode(pval);
if (mode == REGULATOR_MODE_INVALID)
pr_err("%s: invalid mode %u\n", np->name, pval);
pr_err("%pOFn: invalid mode %u\n", np, pval);
else
constraints->initial_mode = mode;
} else {
pr_warn("%s: mapping for mode %d not defined\n",
np->name, pval);
pr_warn("%pOFn: mapping for mode %d not defined\n",
np, pval);
}
}
@ -144,14 +144,14 @@ static void of_get_regulation_constraints(struct device_node *np,
ret = of_property_read_u32_index(np,
"regulator-allowed-modes", i, &pval);
if (ret) {
pr_err("%s: couldn't read allowed modes index %d, ret=%d\n",
np->name, i, ret);
pr_err("%pOFn: couldn't read allowed modes index %d, ret=%d\n",
np, i, ret);
break;
}
mode = desc->of_map_mode(pval);
if (mode == REGULATOR_MODE_INVALID)
pr_err("%s: invalid regulator-allowed-modes element %u\n",
np->name, pval);
pr_err("%pOFn: invalid regulator-allowed-modes element %u\n",
np, pval);
else
constraints->valid_modes_mask |= mode;
}
@ -159,7 +159,7 @@ static void of_get_regulation_constraints(struct device_node *np,
constraints->valid_ops_mask
|= REGULATOR_CHANGE_MODE;
} else {
pr_warn("%s: mode mapping not defined\n", np->name);
pr_warn("%pOFn: mode mapping not defined\n", np);
}
}
@ -197,13 +197,13 @@ static void of_get_regulation_constraints(struct device_node *np,
if (desc && desc->of_map_mode) {
mode = desc->of_map_mode(pval);
if (mode == REGULATOR_MODE_INVALID)
pr_err("%s: invalid mode %u\n",
np->name, pval);
pr_err("%pOFn: invalid mode %u\n",
np, pval);
else
suspend_state->mode = mode;
} else {
pr_warn("%s: mapping for mode %d not defined\n",
np->name, pval);
pr_warn("%pOFn: mapping for mode %d not defined\n",
np, pval);
}
}
@ -349,8 +349,8 @@ int of_regulator_match(struct device *dev, struct device_node *node,
match->desc);
if (!match->init_data) {
dev_err(dev,
"failed to parse DT for regulator %s\n",
child->name);
"failed to parse DT for regulator %pOFn\n",
child);
of_node_put(child);
return -EINVAL;
}
@ -399,16 +399,16 @@ struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
init_data = of_get_regulator_init_data(dev, child, desc);
if (!init_data) {
dev_err(dev,
"failed to parse DT for regulator %s\n",
child->name);
"failed to parse DT for regulator %pOFn\n",
child);
break;
}
if (desc->of_parse_cb) {
if (desc->of_parse_cb(child, desc, config)) {
dev_err(dev,
"driver callback failed to parse DT for regulator %s\n",
child->name);
"driver callback failed to parse DT for regulator %pOFn\n",
child);
init_data = NULL;
break;
}

View File

@ -414,7 +414,7 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev,
break;
if (!rpmh_data->name) {
dev_err(dev, "Unknown regulator %s\n", node->name);
dev_err(dev, "Unknown regulator %pOFn\n", node);
return -EINVAL;
}
@ -423,8 +423,8 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev,
vreg->addr = cmd_db_read_addr(rpmh_resource_name);
if (!vreg->addr) {
dev_err(dev, "%s: could not find RPMh address for resource %s\n",
node->name, rpmh_resource_name);
dev_err(dev, "%pOFn: could not find RPMh address for resource %s\n",
node, rpmh_resource_name);
return -ENODEV;
}
@ -469,13 +469,13 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev,
rdev = devm_regulator_register(dev, &vreg->rdesc, &reg_config);
if (IS_ERR(rdev)) {
ret = PTR_ERR(rdev);
dev_err(dev, "%s: devm_regulator_register() failed, ret=%d\n",
node->name, ret);
dev_err(dev, "%pOFn: devm_regulator_register() failed, ret=%d\n",
node, ret);
return ret;
}
dev_dbg(dev, "%s regulator registered for RPMh resource %s @ 0x%05X\n",
node->name, rpmh_resource_name, vreg->addr);
dev_dbg(dev, "%pOFn regulator registered for RPMh resource %s @ 0x%05X\n",
node, rpmh_resource_name, vreg->addr);
return 0;
}
@ -504,6 +504,7 @@ static unsigned int rpmh_regulator_pmic4_ldo_of_map_mode(unsigned int rpmh_mode)
break;
default:
mode = REGULATOR_MODE_INVALID;
break;
}
return mode;
@ -537,6 +538,7 @@ rpmh_regulator_pmic4_smps_of_map_mode(unsigned int rpmh_mode)
break;
default:
mode = REGULATOR_MODE_INVALID;
break;
}
return mode;
@ -566,6 +568,7 @@ static unsigned int rpmh_regulator_pmic4_bob_of_map_mode(unsigned int rpmh_mode)
break;
default:
mode = REGULATOR_MODE_INVALID;
break;
}
return mode;

View File

@ -420,6 +420,60 @@ static const struct regulator_desc pmi8998_bob = {
.ops = &rpm_bob_ops,
};
static const struct regulator_desc pms405_hfsmps3 = {
.linear_ranges = (struct regulator_linear_range[]) {
REGULATOR_LINEAR_RANGE(320000, 0, 215, 8000),
},
.n_linear_ranges = 1,
.n_voltages = 216,
.ops = &rpm_smps_ldo_ops,
};
static const struct regulator_desc pms405_nldo300 = {
.linear_ranges = (struct regulator_linear_range[]) {
REGULATOR_LINEAR_RANGE(312000, 0, 127, 8000),
},
.n_linear_ranges = 1,
.n_voltages = 128,
.ops = &rpm_smps_ldo_ops,
};
static const struct regulator_desc pms405_nldo1200 = {
.linear_ranges = (struct regulator_linear_range[]) {
REGULATOR_LINEAR_RANGE(312000, 0, 127, 8000),
},
.n_linear_ranges = 1,
.n_voltages = 128,
.ops = &rpm_smps_ldo_ops,
};
static const struct regulator_desc pms405_pldo50 = {
.linear_ranges = (struct regulator_linear_range[]) {
REGULATOR_LINEAR_RANGE(1664000, 0, 128, 16000),
},
.n_linear_ranges = 1,
.n_voltages = 129,
.ops = &rpm_smps_ldo_ops,
};
static const struct regulator_desc pms405_pldo150 = {
.linear_ranges = (struct regulator_linear_range[]) {
REGULATOR_LINEAR_RANGE(1664000, 0, 128, 16000),
},
.n_linear_ranges = 1,
.n_voltages = 129,
.ops = &rpm_smps_ldo_ops,
};
static const struct regulator_desc pms405_pldo600 = {
.linear_ranges = (struct regulator_linear_range[]) {
REGULATOR_LINEAR_RANGE(1256000, 0, 98, 8000),
},
.n_linear_ranges = 1,
.n_voltages = 99,
.ops = &rpm_smps_ldo_ops,
};
struct rpm_regulator_data {
const char *name;
u32 type;
@ -661,6 +715,28 @@ static const struct rpm_regulator_data rpm_pmi8998_regulators[] = {
{}
};
static const struct rpm_regulator_data rpm_pms405_regulators[] = {
{ "s1", QCOM_SMD_RPM_SMPA, 1, &pms405_hfsmps3, "vdd_s1" },
{ "s2", QCOM_SMD_RPM_SMPA, 2, &pms405_hfsmps3, "vdd_s2" },
{ "s3", QCOM_SMD_RPM_SMPA, 3, &pms405_hfsmps3, "vdd_s3" },
{ "s4", QCOM_SMD_RPM_SMPA, 4, &pms405_hfsmps3, "vdd_s4" },
{ "s5", QCOM_SMD_RPM_SMPA, 5, &pms405_hfsmps3, "vdd_s5" },
{ "l1", QCOM_SMD_RPM_LDOA, 1, &pms405_nldo1200, "vdd_l1_l2" },
{ "l2", QCOM_SMD_RPM_LDOA, 2, &pms405_nldo1200, "vdd_l1_l2" },
{ "l3", QCOM_SMD_RPM_LDOA, 3, &pms405_nldo1200, "vdd_l3_l8" },
{ "l4", QCOM_SMD_RPM_LDOA, 4, &pms405_nldo300, "vdd_l4" },
{ "l5", QCOM_SMD_RPM_LDOA, 5, &pms405_pldo600, "vdd_l5_l6" },
{ "l6", QCOM_SMD_RPM_LDOA, 6, &pms405_pldo600, "vdd_l5_l6" },
{ "l7", QCOM_SMD_RPM_LDOA, 7, &pms405_pldo150, "vdd_l7" },
{ "l8", QCOM_SMD_RPM_LDOA, 8, &pms405_nldo1200, "vdd_l3_l8" },
{ "l9", QCOM_SMD_RPM_LDOA, 9, &pms405_nldo1200, "vdd_l9" },
{ "l10", QCOM_SMD_RPM_LDOA, 10, &pms405_pldo50, "vdd_l10_l11_l12_l13" },
{ "l11", QCOM_SMD_RPM_LDOA, 11, &pms405_pldo150, "vdd_l10_l11_l12_l13" },
{ "l12", QCOM_SMD_RPM_LDOA, 12, &pms405_pldo150, "vdd_l10_l11_l12_l13" },
{ "l13", QCOM_SMD_RPM_LDOA, 13, &pms405_pldo150, "vdd_l10_l11_l12_l13" },
{}
};
static const struct of_device_id rpm_of_match[] = {
{ .compatible = "qcom,rpm-pm8841-regulators", .data = &rpm_pm8841_regulators },
{ .compatible = "qcom,rpm-pm8916-regulators", .data = &rpm_pm8916_regulators },
@ -669,6 +745,7 @@ static const struct of_device_id rpm_of_match[] = {
{ .compatible = "qcom,rpm-pm8998-regulators", .data = &rpm_pm8998_regulators },
{ .compatible = "qcom,rpm-pma8084-regulators", .data = &rpm_pma8084_regulators },
{ .compatible = "qcom,rpm-pmi8998-regulators", .data = &rpm_pmi8998_regulators },
{ .compatible = "qcom,rpm-pms405-regulators", .data = &rpm_pms405_regulators },
{}
};
MODULE_DEVICE_TABLE(of, rpm_of_match);

View File

@ -447,15 +447,15 @@ static void s5m8767_regulator_config_ext_control(struct s5m8767_info *s5m8767,
}
if (mode != S5M8767_ENCTRL_USE_GPIO) {
dev_warn(s5m8767->dev,
"ext-control for %s: mismatched op_mode (%x), ignoring\n",
rdata->reg_node->name, mode);
"ext-control for %pOFn: mismatched op_mode (%x), ignoring\n",
rdata->reg_node, mode);
return;
}
if (!rdata->ext_control_gpiod) {
dev_warn(s5m8767->dev,
"ext-control for %s: GPIO not valid, ignoring\n",
rdata->reg_node->name);
"ext-control for %pOFn: GPIO not valid, ignoring\n",
rdata->reg_node);
return;
}
@ -566,17 +566,18 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
if (i == ARRAY_SIZE(regulators)) {
dev_warn(iodev->dev,
"don't know how to configure regulator %s\n",
reg_np->name);
"don't know how to configure regulator %pOFn\n",
reg_np);
continue;
}
rdata->ext_control_gpiod = devm_gpiod_get_from_of_node(&pdev->dev,
reg_np,
"s5m8767,pmic-ext-control-gpios",
0,
GPIOD_OUT_HIGH,
"s5m8767");
rdata->ext_control_gpiod = devm_gpiod_get_from_of_node(
&pdev->dev,
reg_np,
"s5m8767,pmic-ext-control-gpios",
0,
GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE,
"s5m8767");
if (IS_ERR(rdata->ext_control_gpiod))
return PTR_ERR(rdata->ext_control_gpiod);

View File

@ -0,0 +1,674 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) STMicroelectronics 2018
// Author: Pascal Paillet <p.paillet@st.com> for STMicroelectronics.
#include <linux/interrupt.h>
#include <linux/mfd/stpmic1.h>
#include <linux/module.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
/**
* stpmic1 regulator description
* @desc: regulator framework description
* @mask_reset_reg: mask reset register address
* @mask_reset_mask: mask rank and mask reset register mask
* @icc_reg: icc register address
* @icc_mask: icc register mask
*/
struct stpmic1_regulator_cfg {
struct regulator_desc desc;
u8 mask_reset_reg;
u8 mask_reset_mask;
u8 icc_reg;
u8 icc_mask;
};
/**
* stpmic1 regulator data: this structure is used as driver data
* @regul_id: regulator id
* @reg_node: DT node of regulator (unused on non-DT platforms)
* @cfg: stpmic specific regulator description
* @mask_reset: mask_reset bit value
* @irq_curlim: current limit interrupt number
* @regmap: point to parent regmap structure
*/
struct stpmic1_regulator {
unsigned int regul_id;
struct device_node *reg_node;
struct stpmic1_regulator_cfg *cfg;
u8 mask_reset;
int irq_curlim;
struct regmap *regmap;
};
static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode);
static unsigned int stpmic1_get_mode(struct regulator_dev *rdev);
static int stpmic1_set_icc(struct regulator_dev *rdev);
static int stpmic1_regulator_parse_dt(void *driver_data);
static unsigned int stpmic1_map_mode(unsigned int mode);
enum {
STPMIC1_BUCK1 = 0,
STPMIC1_BUCK2 = 1,
STPMIC1_BUCK3 = 2,
STPMIC1_BUCK4 = 3,
STPMIC1_LDO1 = 4,
STPMIC1_LDO2 = 5,
STPMIC1_LDO3 = 6,
STPMIC1_LDO4 = 7,
STPMIC1_LDO5 = 8,
STPMIC1_LDO6 = 9,
STPMIC1_VREF_DDR = 10,
STPMIC1_BOOST = 11,
STPMIC1_VBUS_OTG = 12,
STPMIC1_SW_OUT = 13,
};
/* Enable time worst case is 5000mV/(2250uV/uS) */
#define PMIC_ENABLE_TIME_US 2200
#define STPMIC1_BUCK_MODE_NORMAL 0
#define STPMIC1_BUCK_MODE_LP BUCK_HPLP_ENABLE_MASK
struct regulator_linear_range buck1_ranges[] = {
REGULATOR_LINEAR_RANGE(600000, 0, 30, 25000),
REGULATOR_LINEAR_RANGE(1350000, 31, 63, 0),
};
struct regulator_linear_range buck2_ranges[] = {
REGULATOR_LINEAR_RANGE(1000000, 0, 17, 0),
REGULATOR_LINEAR_RANGE(1050000, 18, 19, 0),
REGULATOR_LINEAR_RANGE(1100000, 20, 21, 0),
REGULATOR_LINEAR_RANGE(1150000, 22, 23, 0),
REGULATOR_LINEAR_RANGE(1200000, 24, 25, 0),
REGULATOR_LINEAR_RANGE(1250000, 26, 27, 0),
REGULATOR_LINEAR_RANGE(1300000, 28, 29, 0),
REGULATOR_LINEAR_RANGE(1350000, 30, 31, 0),
REGULATOR_LINEAR_RANGE(1400000, 32, 33, 0),
REGULATOR_LINEAR_RANGE(1450000, 34, 35, 0),
REGULATOR_LINEAR_RANGE(1500000, 36, 63, 0),
};
struct regulator_linear_range buck3_ranges[] = {
REGULATOR_LINEAR_RANGE(1000000, 0, 19, 0),
REGULATOR_LINEAR_RANGE(1100000, 20, 23, 0),
REGULATOR_LINEAR_RANGE(1200000, 24, 27, 0),
REGULATOR_LINEAR_RANGE(1300000, 28, 31, 0),
REGULATOR_LINEAR_RANGE(1400000, 32, 35, 0),
REGULATOR_LINEAR_RANGE(1500000, 36, 55, 100000),
REGULATOR_LINEAR_RANGE(3400000, 56, 63, 0),
};
struct regulator_linear_range buck4_ranges[] = {
REGULATOR_LINEAR_RANGE(600000, 0, 27, 25000),
REGULATOR_LINEAR_RANGE(1300000, 28, 29, 0),
REGULATOR_LINEAR_RANGE(1350000, 30, 31, 0),
REGULATOR_LINEAR_RANGE(1400000, 32, 33, 0),
REGULATOR_LINEAR_RANGE(1450000, 34, 35, 0),
REGULATOR_LINEAR_RANGE(1500000, 36, 60, 100000),
REGULATOR_LINEAR_RANGE(3900000, 61, 63, 0),
};
struct regulator_linear_range ldo1_ranges[] = {
REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0),
REGULATOR_LINEAR_RANGE(1700000, 8, 24, 100000),
REGULATOR_LINEAR_RANGE(3300000, 25, 31, 0),
};
struct regulator_linear_range ldo2_ranges[] = {
REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0),
REGULATOR_LINEAR_RANGE(1700000, 8, 24, 100000),
REGULATOR_LINEAR_RANGE(3300000, 25, 30, 0),
};
struct regulator_linear_range ldo3_ranges[] = {
REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0),
REGULATOR_LINEAR_RANGE(1700000, 8, 24, 100000),
REGULATOR_LINEAR_RANGE(3300000, 25, 30, 0),
/* with index 31 LDO3 is in DDR mode */
REGULATOR_LINEAR_RANGE(500000, 31, 31, 0),
};
struct regulator_linear_range ldo5_ranges[] = {
REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0),
REGULATOR_LINEAR_RANGE(1700000, 8, 30, 100000),
REGULATOR_LINEAR_RANGE(3900000, 31, 31, 0),
};
struct regulator_linear_range ldo6_ranges[] = {
REGULATOR_LINEAR_RANGE(900000, 0, 24, 100000),
REGULATOR_LINEAR_RANGE(3300000, 25, 31, 0),
};
static struct regulator_ops stpmic1_ldo_ops = {
.list_voltage = regulator_list_voltage_linear_range,
.map_voltage = regulator_map_voltage_linear_range,
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.set_pull_down = regulator_set_pull_down_regmap,
.set_over_current_protection = stpmic1_set_icc,
};
static struct regulator_ops stpmic1_ldo3_ops = {
.list_voltage = regulator_list_voltage_linear_range,
.map_voltage = regulator_map_voltage_iterate,
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.set_pull_down = regulator_set_pull_down_regmap,
.get_bypass = regulator_get_bypass_regmap,
.set_bypass = regulator_set_bypass_regmap,
.set_over_current_protection = stpmic1_set_icc,
};
static struct regulator_ops stpmic1_ldo4_fixed_regul_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.set_pull_down = regulator_set_pull_down_regmap,
.set_over_current_protection = stpmic1_set_icc,
};
static struct regulator_ops stpmic1_buck_ops = {
.list_voltage = regulator_list_voltage_linear_range,
.map_voltage = regulator_map_voltage_linear_range,
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.set_pull_down = regulator_set_pull_down_regmap,
.set_mode = stpmic1_set_mode,
.get_mode = stpmic1_get_mode,
.set_over_current_protection = stpmic1_set_icc,
};
static struct regulator_ops stpmic1_vref_ddr_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.set_pull_down = regulator_set_pull_down_regmap,
};
static struct regulator_ops stpmic1_switch_regul_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.set_over_current_protection = stpmic1_set_icc,
};
#define REG_LDO(ids, base) { \
.name = #ids, \
.id = STPMIC1_##ids, \
.n_voltages = 32, \
.ops = &stpmic1_ldo_ops, \
.linear_ranges = base ## _ranges, \
.n_linear_ranges = ARRAY_SIZE(base ## _ranges), \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
.vsel_reg = ids##_ACTIVE_CR, \
.vsel_mask = LDO_VOLTAGE_MASK, \
.enable_reg = ids##_ACTIVE_CR, \
.enable_mask = LDO_ENABLE_MASK, \
.enable_val = 1, \
.disable_val = 0, \
.enable_time = PMIC_ENABLE_TIME_US, \
.pull_down_reg = ids##_PULL_DOWN_REG, \
.pull_down_mask = ids##_PULL_DOWN_MASK, \
.supply_name = #base, \
}
#define REG_LDO3(ids, base) { \
.name = #ids, \
.id = STPMIC1_##ids, \
.n_voltages = 32, \
.ops = &stpmic1_ldo3_ops, \
.linear_ranges = ldo3_ranges, \
.n_linear_ranges = ARRAY_SIZE(ldo3_ranges), \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
.vsel_reg = LDO3_ACTIVE_CR, \
.vsel_mask = LDO_VOLTAGE_MASK, \
.enable_reg = LDO3_ACTIVE_CR, \
.enable_mask = LDO_ENABLE_MASK, \
.enable_val = 1, \
.disable_val = 0, \
.enable_time = PMIC_ENABLE_TIME_US, \
.bypass_reg = LDO3_ACTIVE_CR, \
.bypass_mask = LDO_BYPASS_MASK, \
.bypass_val_on = LDO_BYPASS_MASK, \
.bypass_val_off = 0, \
.pull_down_reg = ids##_PULL_DOWN_REG, \
.pull_down_mask = ids##_PULL_DOWN_MASK, \
.supply_name = #base, \
}
#define REG_LDO4(ids, base) { \
.name = #ids, \
.id = STPMIC1_##ids, \
.n_voltages = 1, \
.ops = &stpmic1_ldo4_fixed_regul_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
.min_uV = 3300000, \
.fixed_uV = 3300000, \
.enable_reg = LDO4_ACTIVE_CR, \
.enable_mask = LDO_ENABLE_MASK, \
.enable_val = 1, \
.disable_val = 0, \
.enable_time = PMIC_ENABLE_TIME_US, \
.pull_down_reg = ids##_PULL_DOWN_REG, \
.pull_down_mask = ids##_PULL_DOWN_MASK, \
.supply_name = #base, \
}
#define REG_BUCK(ids, base) { \
.name = #ids, \
.id = STPMIC1_##ids, \
.ops = &stpmic1_buck_ops, \
.n_voltages = 64, \
.linear_ranges = base ## _ranges, \
.n_linear_ranges = ARRAY_SIZE(base ## _ranges), \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
.vsel_reg = ids##_ACTIVE_CR, \
.vsel_mask = BUCK_VOLTAGE_MASK, \
.enable_reg = ids##_ACTIVE_CR, \
.enable_mask = BUCK_ENABLE_MASK, \
.enable_val = 1, \
.disable_val = 0, \
.enable_time = PMIC_ENABLE_TIME_US, \
.of_map_mode = stpmic1_map_mode, \
.pull_down_reg = ids##_PULL_DOWN_REG, \
.pull_down_mask = ids##_PULL_DOWN_MASK, \
.supply_name = #base, \
}
#define REG_VREF_DDR(ids, base) { \
.name = #ids, \
.id = STPMIC1_##ids, \
.n_voltages = 1, \
.ops = &stpmic1_vref_ddr_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
.min_uV = 500000, \
.fixed_uV = 500000, \
.enable_reg = VREF_DDR_ACTIVE_CR, \
.enable_mask = BUCK_ENABLE_MASK, \
.enable_val = 1, \
.disable_val = 0, \
.enable_time = PMIC_ENABLE_TIME_US, \
.pull_down_reg = ids##_PULL_DOWN_REG, \
.pull_down_mask = ids##_PULL_DOWN_MASK, \
.supply_name = #base, \
}
#define REG_SWITCH(ids, base, reg, mask, val) { \
.name = #ids, \
.id = STPMIC1_##ids, \
.n_voltages = 1, \
.ops = &stpmic1_switch_regul_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
.min_uV = 0, \
.fixed_uV = 5000000, \
.enable_reg = (reg), \
.enable_mask = (mask), \
.enable_val = (val), \
.disable_val = 0, \
.enable_time = PMIC_ENABLE_TIME_US, \
.supply_name = #base, \
}
struct stpmic1_regulator_cfg stpmic1_regulator_cfgs[] = {
[STPMIC1_BUCK1] = {
.desc = REG_BUCK(BUCK1, buck1),
.icc_reg = BUCKS_ICCTO_CR,
.icc_mask = BIT(0),
.mask_reset_reg = BUCKS_MASK_RESET_CR,
.mask_reset_mask = BIT(0),
},
[STPMIC1_BUCK2] = {
.desc = REG_BUCK(BUCK2, buck2),
.icc_reg = BUCKS_ICCTO_CR,
.icc_mask = BIT(1),
.mask_reset_reg = BUCKS_MASK_RESET_CR,
.mask_reset_mask = BIT(1),
},
[STPMIC1_BUCK3] = {
.desc = REG_BUCK(BUCK3, buck3),
.icc_reg = BUCKS_ICCTO_CR,
.icc_mask = BIT(2),
.mask_reset_reg = BUCKS_MASK_RESET_CR,
.mask_reset_mask = BIT(2),
},
[STPMIC1_BUCK4] = {
.desc = REG_BUCK(BUCK4, buck4),
.icc_reg = BUCKS_ICCTO_CR,
.icc_mask = BIT(3),
.mask_reset_reg = BUCKS_MASK_RESET_CR,
.mask_reset_mask = BIT(3),
},
[STPMIC1_LDO1] = {
.desc = REG_LDO(LDO1, ldo1),
.icc_reg = LDOS_ICCTO_CR,
.icc_mask = BIT(0),
.mask_reset_reg = LDOS_MASK_RESET_CR,
.mask_reset_mask = BIT(0),
},
[STPMIC1_LDO2] = {
.desc = REG_LDO(LDO2, ldo2),
.icc_reg = LDOS_ICCTO_CR,
.icc_mask = BIT(1),
.mask_reset_reg = LDOS_MASK_RESET_CR,
.mask_reset_mask = BIT(1),
},
[STPMIC1_LDO3] = {
.desc = REG_LDO3(LDO3, ldo3),
.icc_reg = LDOS_ICCTO_CR,
.icc_mask = BIT(2),
.mask_reset_reg = LDOS_MASK_RESET_CR,
.mask_reset_mask = BIT(2),
},
[STPMIC1_LDO4] = {
.desc = REG_LDO4(LDO4, ldo4),
.icc_reg = LDOS_ICCTO_CR,
.icc_mask = BIT(3),
.mask_reset_reg = LDOS_MASK_RESET_CR,
.mask_reset_mask = BIT(3),
},
[STPMIC1_LDO5] = {
.desc = REG_LDO(LDO5, ldo5),
.icc_reg = LDOS_ICCTO_CR,
.icc_mask = BIT(4),
.mask_reset_reg = LDOS_MASK_RESET_CR,
.mask_reset_mask = BIT(4),
},
[STPMIC1_LDO6] = {
.desc = REG_LDO(LDO6, ldo6),
.icc_reg = LDOS_ICCTO_CR,
.icc_mask = BIT(5),
.mask_reset_reg = LDOS_MASK_RESET_CR,
.mask_reset_mask = BIT(5),
},
[STPMIC1_VREF_DDR] = {
.desc = REG_VREF_DDR(VREF_DDR, vref_ddr),
.mask_reset_reg = LDOS_MASK_RESET_CR,
.mask_reset_mask = BIT(6),
},
[STPMIC1_BOOST] = {
.desc = REG_SWITCH(BOOST, boost, BST_SW_CR,
BOOST_ENABLED,
BOOST_ENABLED),
.icc_reg = BUCKS_ICCTO_CR,
.icc_mask = BIT(6),
},
[STPMIC1_VBUS_OTG] = {
.desc = REG_SWITCH(VBUS_OTG, pwr_sw1, BST_SW_CR,
USBSW_OTG_SWITCH_ENABLED,
USBSW_OTG_SWITCH_ENABLED),
.icc_reg = BUCKS_ICCTO_CR,
.icc_mask = BIT(4),
},
[STPMIC1_SW_OUT] = {
.desc = REG_SWITCH(SW_OUT, pwr_sw2, BST_SW_CR,
SWIN_SWOUT_ENABLED,
SWIN_SWOUT_ENABLED),
.icc_reg = BUCKS_ICCTO_CR,
.icc_mask = BIT(5),
},
};
static unsigned int stpmic1_map_mode(unsigned int mode)
{
switch (mode) {
case STPMIC1_BUCK_MODE_NORMAL:
return REGULATOR_MODE_NORMAL;
case STPMIC1_BUCK_MODE_LP:
return REGULATOR_MODE_STANDBY;
default:
return REGULATOR_MODE_INVALID;
}
}
static unsigned int stpmic1_get_mode(struct regulator_dev *rdev)
{
int value;
regmap_read(rdev->regmap, rdev->desc->enable_reg, &value);
if (value & STPMIC1_BUCK_MODE_LP)
return REGULATOR_MODE_STANDBY;
return REGULATOR_MODE_NORMAL;
}
static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode)
{
int value;
switch (mode) {
case REGULATOR_MODE_NORMAL:
value = STPMIC1_BUCK_MODE_NORMAL;
break;
case REGULATOR_MODE_STANDBY:
value = STPMIC1_BUCK_MODE_LP;
break;
default:
return -EINVAL;
}
return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
STPMIC1_BUCK_MODE_LP, value);
}
static int stpmic1_set_icc(struct regulator_dev *rdev)
{
struct stpmic1_regulator *regul = rdev_get_drvdata(rdev);
/* enable switch off in case of over current */
return regmap_update_bits(regul->regmap, regul->cfg->icc_reg,
regul->cfg->icc_mask, regul->cfg->icc_mask);
}
static irqreturn_t stpmic1_curlim_irq_handler(int irq, void *data)
{
struct regulator_dev *rdev = (struct regulator_dev *)data;
mutex_lock(&rdev->mutex);
/* Send an overcurrent notification */
regulator_notifier_call_chain(rdev,
REGULATOR_EVENT_OVER_CURRENT,
NULL);
mutex_unlock(&rdev->mutex);
return IRQ_HANDLED;
}
static int stpmic1_regulator_init(struct platform_device *pdev,
struct regulator_dev *rdev)
{
struct stpmic1_regulator *regul = rdev_get_drvdata(rdev);
int ret = 0;
/* set mask reset */
if (regul->mask_reset && regul->cfg->mask_reset_reg != 0) {
ret = regmap_update_bits(regul->regmap,
regul->cfg->mask_reset_reg,
regul->cfg->mask_reset_mask,
regul->cfg->mask_reset_mask);
if (ret) {
dev_err(&pdev->dev, "set mask reset failed\n");
return ret;
}
}
/* setup an irq handler for over-current detection */
if (regul->irq_curlim > 0) {
ret = devm_request_threaded_irq(&pdev->dev,
regul->irq_curlim, NULL,
stpmic1_curlim_irq_handler,
IRQF_ONESHOT | IRQF_SHARED,
pdev->name, rdev);
if (ret) {
dev_err(&pdev->dev, "Request IRQ failed\n");
return ret;
}
}
return 0;
}
#define MATCH(_name, _id) \
[STPMIC1_##_id] = { \
.name = #_name, \
.desc = &stpmic1_regulator_cfgs[STPMIC1_##_id].desc, \
}
static struct of_regulator_match stpmic1_regulators_matches[] = {
MATCH(buck1, BUCK1),
MATCH(buck2, BUCK2),
MATCH(buck3, BUCK3),
MATCH(buck4, BUCK4),
MATCH(ldo1, LDO1),
MATCH(ldo2, LDO2),
MATCH(ldo3, LDO3),
MATCH(ldo4, LDO4),
MATCH(ldo5, LDO5),
MATCH(ldo6, LDO6),
MATCH(vref_ddr, VREF_DDR),
MATCH(boost, BOOST),
MATCH(pwr_sw1, VBUS_OTG),
MATCH(pwr_sw2, SW_OUT),
};
static int stpmic1_regulator_parse_dt(void *driver_data)
{
struct stpmic1_regulator *regul =
(struct stpmic1_regulator *)driver_data;
if (!regul)
return -EINVAL;
if (of_get_property(regul->reg_node, "st,mask-reset", NULL))
regul->mask_reset = 1;
regul->irq_curlim = of_irq_get(regul->reg_node, 0);
return 0;
}
static struct
regulator_dev *stpmic1_regulator_register(struct platform_device *pdev, int id,
struct regulator_init_data *init_data,
struct stpmic1_regulator *regul)
{
struct stpmic1 *pmic_dev = dev_get_drvdata(pdev->dev.parent);
struct regulator_dev *rdev;
struct regulator_config config = {};
config.dev = &pdev->dev;
config.init_data = init_data;
config.of_node = stpmic1_regulators_matches[id].of_node;
config.regmap = pmic_dev->regmap;
config.driver_data = regul;
regul->regul_id = id;
regul->reg_node = config.of_node;
regul->cfg = &stpmic1_regulator_cfgs[id];
regul->regmap = pmic_dev->regmap;
rdev = devm_regulator_register(&pdev->dev, &regul->cfg->desc, &config);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "failed to register %s regulator\n",
regul->cfg->desc.name);
}
return rdev;
}
static int stpmic1_regulator_probe(struct platform_device *pdev)
{
struct regulator_dev *rdev;
struct stpmic1_regulator *regul;
struct regulator_init_data *init_data;
struct device_node *np;
int i, ret;
np = pdev->dev.of_node;
ret = of_regulator_match(&pdev->dev, np,
stpmic1_regulators_matches,
ARRAY_SIZE(stpmic1_regulators_matches));
if (ret < 0) {
dev_err(&pdev->dev,
"Error in PMIC regulator device tree node");
return ret;
}
regul = devm_kzalloc(&pdev->dev, ARRAY_SIZE(stpmic1_regulator_cfgs) *
sizeof(struct stpmic1_regulator),
GFP_KERNEL);
if (!regul)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(stpmic1_regulator_cfgs); i++) {
/* Parse DT & find regulators to register */
init_data = stpmic1_regulators_matches[i].init_data;
if (init_data)
init_data->regulator_init = &stpmic1_regulator_parse_dt;
rdev = stpmic1_regulator_register(pdev, i, init_data, regul);
if (IS_ERR(rdev))
return PTR_ERR(rdev);
ret = stpmic1_regulator_init(pdev, rdev);
if (ret) {
dev_err(&pdev->dev,
"failed to initialize regulator %d\n", ret);
return ret;
}
regul++;
}
dev_dbg(&pdev->dev, "stpmic1_regulator driver probed\n");
return 0;
}
static const struct of_device_id of_pmic_regulator_match[] = {
{ .compatible = "st,stpmic1-regulators" },
{ },
};
MODULE_DEVICE_TABLE(of, of_pmic_regulator_match);
static struct platform_driver stpmic1_regulator_driver = {
.driver = {
.name = "stpmic1-regulator",
.of_match_table = of_match_ptr(of_pmic_regulator_match),
},
.probe = stpmic1_regulator_probe,
};
module_platform_driver(stpmic1_regulator_driver);
MODULE_DESCRIPTION("STPMIC1 PMIC voltage regulator driver");
MODULE_AUTHOR("Pascal Paillet <p.paillet@st.com>");
MODULE_LICENSE("GPL v2");

View File

@ -374,6 +374,7 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data(
gflags = GPIOD_OUT_HIGH;
else
gflags = GPIOD_OUT_LOW;
gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
rpdata->gpiod = devm_gpiod_get_from_of_node(&pdev->dev,
tps65090_matches[idx].of_node,

View File

@ -30,6 +30,7 @@ struct gpio_descs {
#define GPIOD_FLAGS_BIT_DIR_OUT BIT(1)
#define GPIOD_FLAGS_BIT_DIR_VAL BIT(2)
#define GPIOD_FLAGS_BIT_OPEN_DRAIN BIT(3)
#define GPIOD_FLAGS_BIT_NONEXCLUSIVE BIT(4)
/**
* Optional flags that can be passed to one of gpiod_* to configure direction

View File

@ -1,112 +1,127 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Copyright (C) 2018 ROHM Semiconductors */
#ifndef __LINUX_MFD_BD71837_H__
#define __LINUX_MFD_BD71837_H__
#ifndef __LINUX_MFD_BD718XX_H__
#define __LINUX_MFD_BD718XX_H__
#include <linux/regmap.h>
enum {
BD71837_BUCK1 = 0,
BD71837_BUCK2,
BD71837_BUCK3,
BD71837_BUCK4,
BD71837_BUCK5,
BD71837_BUCK6,
BD71837_BUCK7,
BD71837_BUCK8,
BD71837_LDO1,
BD71837_LDO2,
BD71837_LDO3,
BD71837_LDO4,
BD71837_LDO5,
BD71837_LDO6,
BD71837_LDO7,
BD71837_REGULATOR_CNT,
BD718XX_TYPE_BD71837 = 0,
BD718XX_TYPE_BD71847,
BD718XX_TYPE_AMOUNT
};
#define BD71837_BUCK1_VOLTAGE_NUM 0x40
#define BD71837_BUCK2_VOLTAGE_NUM 0x40
#define BD71837_BUCK3_VOLTAGE_NUM 0x40
#define BD71837_BUCK4_VOLTAGE_NUM 0x40
enum {
BD718XX_BUCK1 = 0,
BD718XX_BUCK2,
BD718XX_BUCK3,
BD718XX_BUCK4,
BD718XX_BUCK5,
BD718XX_BUCK6,
BD718XX_BUCK7,
BD718XX_BUCK8,
BD718XX_LDO1,
BD718XX_LDO2,
BD718XX_LDO3,
BD718XX_LDO4,
BD718XX_LDO5,
BD718XX_LDO6,
BD718XX_LDO7,
BD718XX_REGULATOR_AMOUNT,
};
#define BD71837_BUCK5_VOLTAGE_NUM 0x08
/* Common voltage configurations */
#define BD718XX_DVS_BUCK_VOLTAGE_NUM 0x3D
#define BD718XX_4TH_NODVS_BUCK_VOLTAGE_NUM 0x3D
#define BD718XX_LDO1_VOLTAGE_NUM 0x08
#define BD718XX_LDO2_VOLTAGE_NUM 0x02
#define BD718XX_LDO3_VOLTAGE_NUM 0x10
#define BD718XX_LDO4_VOLTAGE_NUM 0x0A
#define BD718XX_LDO6_VOLTAGE_NUM 0x0A
/* BD71837 specific voltage configurations */
#define BD71837_BUCK5_VOLTAGE_NUM 0x10
#define BD71837_BUCK6_VOLTAGE_NUM 0x04
#define BD71837_BUCK7_VOLTAGE_NUM 0x08
#define BD71837_BUCK8_VOLTAGE_NUM 0x40
#define BD71837_LDO1_VOLTAGE_NUM 0x04
#define BD71837_LDO2_VOLTAGE_NUM 0x02
#define BD71837_LDO3_VOLTAGE_NUM 0x10
#define BD71837_LDO4_VOLTAGE_NUM 0x10
#define BD71837_LDO5_VOLTAGE_NUM 0x10
#define BD71837_LDO6_VOLTAGE_NUM 0x10
#define BD71837_LDO7_VOLTAGE_NUM 0x10
/* BD71847 specific voltage configurations */
#define BD71847_BUCK3_VOLTAGE_NUM 0x18
#define BD71847_BUCK4_VOLTAGE_NUM 0x08
#define BD71847_LDO5_VOLTAGE_NUM 0x20
/* Registers specific to BD71837 */
enum {
BD71837_REG_REV = 0x00,
BD71837_REG_SWRESET = 0x01,
BD71837_REG_I2C_DEV = 0x02,
BD71837_REG_PWRCTRL0 = 0x03,
BD71837_REG_PWRCTRL1 = 0x04,
BD71837_REG_BUCK1_CTRL = 0x05,
BD71837_REG_BUCK2_CTRL = 0x06,
BD71837_REG_BUCK3_CTRL = 0x07,
BD71837_REG_BUCK4_CTRL = 0x08,
BD71837_REG_BUCK5_CTRL = 0x09,
BD71837_REG_BUCK6_CTRL = 0x0A,
BD71837_REG_BUCK7_CTRL = 0x0B,
BD71837_REG_BUCK8_CTRL = 0x0C,
BD71837_REG_BUCK1_VOLT_RUN = 0x0D,
BD71837_REG_BUCK1_VOLT_IDLE = 0x0E,
BD71837_REG_BUCK1_VOLT_SUSP = 0x0F,
BD71837_REG_BUCK2_VOLT_RUN = 0x10,
BD71837_REG_BUCK2_VOLT_IDLE = 0x11,
BD71837_REG_BUCK3_VOLT_RUN = 0x12,
BD71837_REG_BUCK4_VOLT_RUN = 0x13,
BD71837_REG_BUCK5_VOLT = 0x14,
BD71837_REG_BUCK6_VOLT = 0x15,
BD71837_REG_BUCK7_VOLT = 0x16,
BD71837_REG_BUCK8_VOLT = 0x17,
BD71837_REG_LDO1_VOLT = 0x18,
BD71837_REG_LDO2_VOLT = 0x19,
BD71837_REG_LDO3_VOLT = 0x1A,
BD71837_REG_LDO4_VOLT = 0x1B,
BD71837_REG_LDO5_VOLT = 0x1C,
BD71837_REG_LDO6_VOLT = 0x1D,
BD71837_REG_LDO7_VOLT = 0x1E,
BD71837_REG_TRANS_COND0 = 0x1F,
BD71837_REG_TRANS_COND1 = 0x20,
BD71837_REG_VRFAULTEN = 0x21,
BD718XX_REG_MVRFLTMASK0 = 0x22,
BD718XX_REG_MVRFLTMASK1 = 0x23,
BD718XX_REG_MVRFLTMASK2 = 0x24,
BD71837_REG_RCVCFG = 0x25,
BD71837_REG_RCVNUM = 0x26,
BD71837_REG_PWRONCONFIG0 = 0x27,
BD71837_REG_PWRONCONFIG1 = 0x28,
BD71837_REG_RESETSRC = 0x29,
BD71837_REG_MIRQ = 0x2A,
BD71837_REG_IRQ = 0x2B,
BD71837_REG_IN_MON = 0x2C,
BD71837_REG_POW_STATE = 0x2D,
BD71837_REG_OUT32K = 0x2E,
BD71837_REG_REGLOCK = 0x2F,
BD71837_REG_OTPVER = 0xFF,
BD71837_MAX_REGISTER = 0x100,
BD71837_REG_BUCK3_CTRL = 0x07,
BD71837_REG_BUCK4_CTRL = 0x08,
BD71837_REG_BUCK3_VOLT_RUN = 0x12,
BD71837_REG_BUCK4_VOLT_RUN = 0x13,
BD71837_REG_LDO7_VOLT = 0x1E,
};
/* Registers common for BD71837 and BD71847 */
enum {
BD718XX_REG_REV = 0x00,
BD718XX_REG_SWRESET = 0x01,
BD718XX_REG_I2C_DEV = 0x02,
BD718XX_REG_PWRCTRL0 = 0x03,
BD718XX_REG_PWRCTRL1 = 0x04,
BD718XX_REG_BUCK1_CTRL = 0x05,
BD718XX_REG_BUCK2_CTRL = 0x06,
BD718XX_REG_1ST_NODVS_BUCK_CTRL = 0x09,
BD718XX_REG_2ND_NODVS_BUCK_CTRL = 0x0A,
BD718XX_REG_3RD_NODVS_BUCK_CTRL = 0x0B,
BD718XX_REG_4TH_NODVS_BUCK_CTRL = 0x0C,
BD718XX_REG_BUCK1_VOLT_RUN = 0x0D,
BD718XX_REG_BUCK1_VOLT_IDLE = 0x0E,
BD718XX_REG_BUCK1_VOLT_SUSP = 0x0F,
BD718XX_REG_BUCK2_VOLT_RUN = 0x10,
BD718XX_REG_BUCK2_VOLT_IDLE = 0x11,
BD718XX_REG_1ST_NODVS_BUCK_VOLT = 0x14,
BD718XX_REG_2ND_NODVS_BUCK_VOLT = 0x15,
BD718XX_REG_3RD_NODVS_BUCK_VOLT = 0x16,
BD718XX_REG_4TH_NODVS_BUCK_VOLT = 0x17,
BD718XX_REG_LDO1_VOLT = 0x18,
BD718XX_REG_LDO2_VOLT = 0x19,
BD718XX_REG_LDO3_VOLT = 0x1A,
BD718XX_REG_LDO4_VOLT = 0x1B,
BD718XX_REG_LDO5_VOLT = 0x1C,
BD718XX_REG_LDO6_VOLT = 0x1D,
BD718XX_REG_TRANS_COND0 = 0x1F,
BD718XX_REG_TRANS_COND1 = 0x20,
BD718XX_REG_VRFAULTEN = 0x21,
BD718XX_REG_MVRFLTMASK0 = 0x22,
BD718XX_REG_MVRFLTMASK1 = 0x23,
BD718XX_REG_MVRFLTMASK2 = 0x24,
BD718XX_REG_RCVCFG = 0x25,
BD718XX_REG_RCVNUM = 0x26,
BD718XX_REG_PWRONCONFIG0 = 0x27,
BD718XX_REG_PWRONCONFIG1 = 0x28,
BD718XX_REG_RESETSRC = 0x29,
BD718XX_REG_MIRQ = 0x2A,
BD718XX_REG_IRQ = 0x2B,
BD718XX_REG_IN_MON = 0x2C,
BD718XX_REG_POW_STATE = 0x2D,
BD718XX_REG_OUT32K = 0x2E,
BD718XX_REG_REGLOCK = 0x2F,
BD718XX_REG_OTPVER = 0xFF,
BD718XX_MAX_REGISTER = 0x100,
};
#define REGLOCK_PWRSEQ 0x1
#define REGLOCK_VREG 0x10
/* Generic BUCK control masks */
#define BD71837_BUCK_SEL 0x02
#define BD71837_BUCK_EN 0x01
#define BD71837_BUCK_RUN_ON 0x04
#define BD718XX_BUCK_SEL 0x02
#define BD718XX_BUCK_EN 0x01
#define BD718XX_BUCK_RUN_ON 0x04
/* Generic LDO masks */
#define BD71837_LDO_SEL 0x80
#define BD71837_LDO_EN 0x40
#define BD718XX_LDO_SEL 0x80
#define BD718XX_LDO_EN 0x40
/* BD71837 BUCK ramp rate CTRL reg bits */
#define BUCK_RAMPRATE_MASK 0xC0
@ -115,49 +130,35 @@ enum {
#define BUCK_RAMPRATE_2P50MV 0x2
#define BUCK_RAMPRATE_1P25MV 0x3
/* BD71837_REG_BUCK1_VOLT_RUN bits */
#define BUCK1_RUN_MASK 0x3F
#define BUCK1_RUN_DEFAULT 0x14
#define DVS_BUCK_RUN_MASK 0x3F
#define DVS_BUCK_SUSP_MASK 0x3F
#define DVS_BUCK_IDLE_MASK 0x3F
/* BD71837_REG_BUCK1_VOLT_SUSP bits */
#define BUCK1_SUSP_MASK 0x3F
#define BUCK1_SUSP_DEFAULT 0x14
#define BD718XX_1ST_NODVS_BUCK_MASK 0x07
#define BD718XX_3RD_NODVS_BUCK_MASK 0x07
#define BD718XX_4TH_NODVS_BUCK_MASK 0x3F
/* BD71837_REG_BUCK1_VOLT_IDLE bits */
#define BUCK1_IDLE_MASK 0x3F
#define BUCK1_IDLE_DEFAULT 0x14
#define BD71847_BUCK3_MASK 0x07
#define BD71847_BUCK3_RANGE_MASK 0xC0
#define BD71847_BUCK4_MASK 0x03
#define BD71847_BUCK4_RANGE_MASK 0x40
/* BD71837_REG_BUCK2_VOLT_RUN bits */
#define BUCK2_RUN_MASK 0x3F
#define BUCK2_RUN_DEFAULT 0x1E
#define BD71837_BUCK5_MASK 0x07
#define BD71837_BUCK5_RANGE_MASK 0x80
#define BD71837_BUCK6_MASK 0x03
/* BD71837_REG_BUCK2_VOLT_IDLE bits */
#define BUCK2_IDLE_MASK 0x3F
#define BUCK2_IDLE_DEFAULT 0x14
#define BD718XX_LDO1_MASK 0x03
#define BD718XX_LDO1_RANGE_MASK 0x20
#define BD718XX_LDO2_MASK 0x20
#define BD718XX_LDO3_MASK 0x0F
#define BD718XX_LDO4_MASK 0x0F
#define BD718XX_LDO6_MASK 0x0F
/* BD71837_REG_BUCK3_VOLT_RUN bits */
#define BUCK3_RUN_MASK 0x3F
#define BUCK3_RUN_DEFAULT 0x1E
#define BD71837_LDO5_MASK 0x0F
#define BD71847_LDO5_MASK 0x0F
#define BD71847_LDO5_RANGE_MASK 0x20
/* BD71837_REG_BUCK4_VOLT_RUN bits */
#define BUCK4_RUN_MASK 0x3F
#define BUCK4_RUN_DEFAULT 0x1E
/* BD71837_REG_BUCK5_VOLT bits */
#define BUCK5_MASK 0x07
#define BUCK5_DEFAULT 0x02
/* BD71837_REG_BUCK6_VOLT bits */
#define BUCK6_MASK 0x03
#define BUCK6_DEFAULT 0x03
/* BD71837_REG_BUCK7_VOLT bits */
#define BUCK7_MASK 0x07
#define BUCK7_DEFAULT 0x03
/* BD71837_REG_BUCK8_VOLT bits */
#define BUCK8_MASK 0x3F
#define BUCK8_DEFAULT 0x1E
#define BD71837_LDO7_MASK 0x0F
/* BD718XX Voltage monitoring masks */
#define BD718XX_BUCK1_VRMON80 0x1
@ -186,7 +187,7 @@ enum {
#define BD71837_BUCK4_VRMON130 0x80
#define BD71837_LDO7_VRMON80 0x40
/* BD71837_REG_IRQ bits */
/* BD718XX_REG_IRQ bits */
#define IRQ_SWRST 0x40
#define IRQ_PWRON_S 0x20
#define IRQ_PWRON_L 0x10
@ -195,52 +196,31 @@ enum {
#define IRQ_ON_REQ 0x02
#define IRQ_STBY_REQ 0x01
/* BD71837_REG_OUT32K bits */
#define BD71837_OUT32K_EN 0x01
/* BD718XX_REG_OUT32K bits */
#define BD718XX_OUT32K_EN 0x01
/* BD71837 gated clock rate */
#define BD71837_CLK_RATE 32768
/* BD7183XX gated clock rate */
#define BD718XX_CLK_RATE 32768
/* ROHM BD71837 irqs */
/* ROHM BD718XX irqs */
enum {
BD71837_INT_STBY_REQ,
BD71837_INT_ON_REQ,
BD71837_INT_WDOG,
BD71837_INT_PWRBTN,
BD71837_INT_PWRBTN_L,
BD71837_INT_PWRBTN_S,
BD71837_INT_SWRST
BD718XX_INT_STBY_REQ,
BD718XX_INT_ON_REQ,
BD718XX_INT_WDOG,
BD718XX_INT_PWRBTN,
BD718XX_INT_PWRBTN_L,
BD718XX_INT_PWRBTN_S,
BD718XX_INT_SWRST
};
/* ROHM BD71837 interrupt masks */
#define BD71837_INT_SWRST_MASK 0x40
#define BD71837_INT_PWRBTN_S_MASK 0x20
#define BD71837_INT_PWRBTN_L_MASK 0x10
#define BD71837_INT_PWRBTN_MASK 0x8
#define BD71837_INT_WDOG_MASK 0x4
#define BD71837_INT_ON_REQ_MASK 0x2
#define BD71837_INT_STBY_REQ_MASK 0x1
/* BD71837_REG_LDO1_VOLT bits */
#define LDO1_MASK 0x03
/* BD71837_REG_LDO1_VOLT bits */
#define LDO2_MASK 0x20
/* BD71837_REG_LDO3_VOLT bits */
#define LDO3_MASK 0x0F
/* BD71837_REG_LDO4_VOLT bits */
#define LDO4_MASK 0x0F
/* BD71837_REG_LDO5_VOLT bits */
#define LDO5_MASK 0x0F
/* BD71837_REG_LDO6_VOLT bits */
#define LDO6_MASK 0x0F
/* BD71837_REG_LDO7_VOLT bits */
#define LDO7_MASK 0x0F
/* ROHM BD718XX interrupt masks */
#define BD718XX_INT_SWRST_MASK 0x40
#define BD718XX_INT_PWRBTN_S_MASK 0x20
#define BD718XX_INT_PWRBTN_L_MASK 0x10
#define BD718XX_INT_PWRBTN_MASK 0x8
#define BD718XX_INT_WDOG_MASK 0x4
#define BD718XX_INT_ON_REQ_MASK 0x2
#define BD718XX_INT_STBY_REQ_MASK 0x1
/* Register write induced reset settings */
@ -250,13 +230,13 @@ enum {
* write 1 to it we will trigger the action. So always write 0 to it when
* changning SWRESET action - no matter what we read from it.
*/
#define BD71837_SWRESET_TYPE_MASK 7
#define BD71837_SWRESET_TYPE_DISABLED 0
#define BD71837_SWRESET_TYPE_COLD 4
#define BD71837_SWRESET_TYPE_WARM 6
#define BD718XX_SWRESET_TYPE_MASK 7
#define BD718XX_SWRESET_TYPE_DISABLED 0
#define BD718XX_SWRESET_TYPE_COLD 4
#define BD718XX_SWRESET_TYPE_WARM 6
#define BD71837_SWRESET_RESET_MASK 1
#define BD71837_SWRESET_RESET 1
#define BD718XX_SWRESET_RESET_MASK 1
#define BD718XX_SWRESET_RESET 1
/* Poweroff state transition conditions */
@ -341,10 +321,10 @@ enum {
BD718XX_PWRBTN_LONG_PRESS_15S
};
struct bd71837_pmic;
struct bd71837_clk;
struct bd718xx_clk;
struct bd71837 {
struct bd718xx {
unsigned int chip_type;
struct device *dev;
struct regmap *regmap;
unsigned long int id;
@ -352,8 +332,7 @@ struct bd71837 {
int chip_irq;
struct regmap_irq_chip_data *irq_data;
struct bd71837_pmic *pmic;
struct bd71837_clk *clk;
struct bd718xx_clk *clk;
};
#endif /* __LINUX_MFD_BD71837_H__ */
#endif /* __LINUX_MFD_BD718XX_H__ */

View File

@ -271,9 +271,16 @@ enum regulator_type {
* @ramp_delay: Time to settle down after voltage change (unit: uV/us)
* @min_dropout_uV: The minimum dropout voltage this regulator can handle
* @linear_ranges: A constant table of possible voltage ranges.
* @n_linear_ranges: Number of entries in the @linear_ranges table.
* @linear_range_selectors: A constant table of voltage range selectors.
* If pickable ranges are used each range must
* have corresponding selector here.
* @n_linear_ranges: Number of entries in the @linear_ranges (and in
* linear_range_selectors if used) table(s).
* @volt_table: Voltage mapping table (if table based mapping)
*
* @vsel_range_reg: Register for range selector when using pickable ranges
* and regulator_regmap_X_voltage_X_pickable functions.
* @vsel_range_mask: Mask for register bitfield used for range selector
* @vsel_reg: Register for selector when using regulator_regmap_X_voltage_
* @vsel_mask: Mask for register bitfield used for selector
* @csel_reg: Register for TPS65218 LS3 current regulator
@ -338,10 +345,14 @@ struct regulator_desc {
int min_dropout_uV;
const struct regulator_linear_range *linear_ranges;
const unsigned int *linear_range_selectors;
int n_linear_ranges;
const unsigned int *volt_table;
unsigned int vsel_range_reg;
unsigned int vsel_range_mask;
unsigned int vsel_reg;
unsigned int vsel_mask;
unsigned int csel_reg;
@ -498,18 +509,25 @@ int regulator_mode_to_status(unsigned int);
int regulator_list_voltage_linear(struct regulator_dev *rdev,
unsigned int selector);
int regulator_list_voltage_pickable_linear_range(struct regulator_dev *rdev,
unsigned int selector);
int regulator_list_voltage_linear_range(struct regulator_dev *rdev,
unsigned int selector);
int regulator_list_voltage_table(struct regulator_dev *rdev,
unsigned int selector);
int regulator_map_voltage_linear(struct regulator_dev *rdev,
int min_uV, int max_uV);
int regulator_map_voltage_pickable_linear_range(struct regulator_dev *rdev,
int min_uV, int max_uV);
int regulator_map_voltage_linear_range(struct regulator_dev *rdev,
int min_uV, int max_uV);
int regulator_map_voltage_iterate(struct regulator_dev *rdev,
int min_uV, int max_uV);
int regulator_map_voltage_ascend(struct regulator_dev *rdev,
int min_uV, int max_uV);
int regulator_get_voltage_sel_pickable_regmap(struct regulator_dev *rdev);
int regulator_set_voltage_sel_pickable_regmap(struct regulator_dev *rdev,
unsigned int sel);
int regulator_get_voltage_sel_regmap(struct regulator_dev *rdev);
int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel);
int regulator_is_enabled_regmap(struct regulator_dev *rdev);

View File

@ -24,8 +24,6 @@ struct regulator_init_data;
* @supply_name: Name of the regulator supply
* @input_supply: Name of the input regulator supply
* @microvolts: Output voltage of regulator
* @gpio: GPIO to use for enable control
* set to -EINVAL if not used
* @startup_delay: Start-up time in microseconds
* @gpio_is_open_drain: Gpio pin is open drain or normal type.
* If it is open drain type then HIGH will be set
@ -49,7 +47,6 @@ struct fixed_voltage_config {
const char *supply_name;
const char *input_supply;
int microvolts;
int gpio;
unsigned startup_delay;
unsigned gpio_is_open_drain:1;
unsigned enable_high:1;