Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
f03e2a72
Commit
f03e2a72
authored
Feb 12, 2021
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'regulator/for-5.12' into regulator-next
parents
8571bdc2
27866e3e
Changes
36
Hide whitespace changes
Inline
Side-by-side
Showing
36 changed files
with
2648 additions
and
1471 deletions
+2648
-1471
Documentation/devicetree/bindings/regulator/max8997-regulator.txt
...ation/devicetree/bindings/regulator/max8997-regulator.txt
+1
-0
Documentation/devicetree/bindings/regulator/mcp16502-regulator.txt
...tion/devicetree/bindings/regulator/mcp16502-regulator.txt
+2
-1
Documentation/devicetree/bindings/regulator/mt6315-regulator.yaml
...ation/devicetree/bindings/regulator/mt6315-regulator.yaml
+69
-0
Documentation/devicetree/bindings/regulator/nxp,pca9450-regulator.yaml
.../devicetree/bindings/regulator/nxp,pca9450-regulator.yaml
+5
-0
Documentation/devicetree/bindings/regulator/nxp,pf8x00-regulator.yaml
...n/devicetree/bindings/regulator/nxp,pf8x00-regulator.yaml
+5
-12
Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.txt
...ion/devicetree/bindings/regulator/qcom,rpmh-regulator.txt
+2
-0
Documentation/devicetree/bindings/regulator/qcom-labibb-regulator.yaml
.../devicetree/bindings/regulator/qcom-labibb-regulator.yaml
+22
-8
Documentation/devicetree/bindings/regulator/richtek,rt4831-regulator.yaml
...vicetree/bindings/regulator/richtek,rt4831-regulator.yaml
+35
-0
MAINTAINERS
MAINTAINERS
+2
-2
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts
+8
-1
drivers/mfd/ab8500-core.c
drivers/mfd/ab8500-core.c
+0
-1
drivers/regulator/Kconfig
drivers/regulator/Kconfig
+42
-9
drivers/regulator/Makefile
drivers/regulator/Makefile
+4
-1
drivers/regulator/ab3100.c
drivers/regulator/ab3100.c
+0
-724
drivers/regulator/ab8500-ext.c
drivers/regulator/ab8500-ext.c
+10
-412
drivers/regulator/ab8500.c
drivers/regulator/ab8500.c
+115
-1
drivers/regulator/atc260x-regulator.c
drivers/regulator/atc260x-regulator.c
+539
-0
drivers/regulator/axp20x-regulator.c
drivers/regulator/axp20x-regulator.c
+3
-4
drivers/regulator/bd70528-regulator.c
drivers/regulator/bd70528-regulator.c
+3
-8
drivers/regulator/bd71828-regulator.c
drivers/regulator/bd71828-regulator.c
+4
-9
drivers/regulator/bd718x7-regulator.c
drivers/regulator/bd718x7-regulator.c
+9
-11
drivers/regulator/core.c
drivers/regulator/core.c
+11
-7
drivers/regulator/mcp16502.c
drivers/regulator/mcp16502.c
+1
-1
drivers/regulator/mt6315-regulator.c
drivers/regulator/mt6315-regulator.c
+299
-0
drivers/regulator/mtk-dvfsrc-regulator.c
drivers/regulator/mtk-dvfsrc-regulator.c
+215
-0
drivers/regulator/pca9450-regulator.c
drivers/regulator/pca9450-regulator.c
+22
-0
drivers/regulator/pf8x00-regulator.c
drivers/regulator/pf8x00-regulator.c
+197
-79
drivers/regulator/qcom-labibb-regulator.c
drivers/regulator/qcom-labibb-regulator.c
+725
-3
drivers/regulator/qcom-rpmh-regulator.c
drivers/regulator/qcom-rpmh-regulator.c
+34
-0
drivers/regulator/rt4831-regulator.c
drivers/regulator/rt4831-regulator.c
+198
-0
drivers/regulator/s5m8767.c
drivers/regulator/s5m8767.c
+11
-4
include/linux/mfd/abx500/ab8500.h
include/linux/mfd/abx500/ab8500.h
+0
-3
include/linux/regulator/ab8500.h
include/linux/regulator/ab8500.h
+0
-166
include/linux/regulator/mt6315-regulator.h
include/linux/regulator/mt6315-regulator.h
+44
-0
include/linux/regulator/pca9450.h
include/linux/regulator/pca9450.h
+7
-0
lib/linear_ranges.c
lib/linear_ranges.c
+4
-4
No files found.
Documentation/devicetree/bindings/regulator/max8997-regulator.txt
View file @
f03e2a72
...
...
@@ -35,6 +35,7 @@ Optional properties:
- interrupts: Interrupt specifiers for two interrupt sources.
- First interrupt specifier is for 'irq1' interrupt.
- Second interrupt specifier is for 'alert' interrupt.
- charger-supply: regulator node for charging current.
- max8997,pmic-buck1-uses-gpio-dvs: 'buck1' can be controlled by gpio dvs.
- max8997,pmic-buck2-uses-gpio-dvs: 'buck2' can be controlled by gpio dvs.
- max8997,pmic-buck5-uses-gpio-dvs: 'buck5' can be controlled by gpio dvs.
...
...
Documentation/devicetree/bindings/regulator/mcp16502-regulator.txt
View file @
f03e2a72
...
...
@@ -4,7 +4,8 @@ Required properties:
- compatible: "microchip,mcp16502"
- reg: I2C slave address
- lpm-gpios: GPIO for LPM pin. Note that this GPIO *must* remain high during
suspend-to-ram, keeping the PMIC into HIBERNATE mode.
suspend-to-ram, keeping the PMIC into HIBERNATE mode; this
property is optional;
- regulators: A node that houses a sub-node for each regulator within
the device. Each sub-node is identified using the node's
name. The content of each sub-node is defined by the
...
...
Documentation/devicetree/bindings/regulator/mt6315-regulator.yaml
0 → 100644
View file @
f03e2a72
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML
1.2
---
$id
:
http://devicetree.org/schemas/regulator/mt6315-regulator.yaml#
$schema
:
http://devicetree.org/meta-schemas/core.yaml#
title
:
Mediatek MT6315 Regulator
maintainers
:
-
Hsin-Hsiung Wang <hsin-hsiung.wang@mediatek.com>
description
:
|
The MT6315 is a power management IC (PMIC) configurable with SPMI.
that contains 4 BUCKs output which can combine with each other
by different efuse settings.
properties
:
compatible
:
const
:
mediatek,mt6315-regulator
reg
:
maxItems
:
1
regulators
:
type
:
object
description
:
List of regulators and its properties
patternProperties
:
"
^vbuck[1-4]$"
:
type
:
object
$ref
:
"
regulator.yaml#"
properties
:
regulator-name
:
pattern
:
"
^vbuck[1-4]$"
additionalProperties
:
false
required
:
-
compatible
-
reg
-
regulators
additionalProperties
:
false
examples
:
-
|
pmic@6 {
compatible = "mediatek,mt6315-regulator";
reg = <0x6 0>;
regulators {
vbuck1 {
regulator-compatible = "vbuck1";
regulator-min-microvolt = <300000>;
regulator-max-microvolt = <1193750>;
regulator-enable-ramp-delay = <256>;
regulator-allowed-modes = <0 1 2 4>;
};
vbuck3 {
regulator-compatible = "vbuck3";
regulator-min-microvolt = <300000>;
regulator-max-microvolt = <1193750>;
regulator-enable-ramp-delay = <256>;
regulator-allowed-modes = <0 1 2 4>;
};
};
};
Documentation/devicetree/bindings/regulator/nxp,pca9450-regulator.yaml
View file @
f03e2a72
...
...
@@ -87,6 +87,11 @@ properties:
additionalProperties
:
false
sd-vsel-gpios
:
description
:
GPIO that is used to switch LDO5 between being configured by
LDO5CTRL_L or LDO5CTRL_H register. Use this if the SD_VSEL signal is
connected to a host GPIO.
required
:
-
compatible
-
reg
...
...
Documentation/devicetree/bindings/regulator/nxp,pf8x00-regulator.yaml
View file @
f03e2a72
...
...
@@ -62,8 +62,11 @@ properties:
$ref
:
"
/schemas/types.yaml#/definitions/uint32"
minimum
:
2100
maximum
:
4500
deprecated
:
true
description
:
BUCK regulators current limit in mA.
This property is deprecated, please use
"regulator-max-microamp" instead.
Listed current limits in mA are,
2100 (default)
...
...
@@ -73,21 +76,11 @@ properties:
nxp,phase-shift
:
$ref
:
"
/schemas/types.yaml#/definitions/uint32"
minimum
:
45
maximum
:
0
default
:
0
enum
:
[
0
,
45
,
90
,
135
,
180
,
225
,
270
,
315
]
description
:
BUCK regulators phase shift control in degrees.
Listed phase shift control values in degrees are,
45
90
135
180
225
270
315
0 (default)
unevaluatedProperties
:
false
"
^vsnvs$"
:
...
...
Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.txt
View file @
f03e2a72
...
...
@@ -50,6 +50,8 @@ First Level Nodes - PMIC
"qcom,pm8350-rpmh-regulators"
"qcom,pm8350c-rpmh-regulators"
"qcom,pm8998-rpmh-regulators"
"qcom,pmc8180-rpmh-regulators"
"qcom,pmc8180c-rpmh-regulators"
"qcom,pmi8998-rpmh-regulators"
"qcom,pm6150-rpmh-regulators"
"qcom,pm6150l-rpmh-regulators"
...
...
Documentation/devicetree/bindings/regulator/qcom-labibb-regulator.yaml
View file @
f03e2a72
...
...
@@ -22,11 +22,17 @@ properties:
type
:
object
properties
:
qcom,soft-start-us
:
$ref
:
/schemas/types.yaml#/definitions/uint32
description
:
Regulator soft start time in microseconds.
enum
:
[
200
,
400
,
600
,
800
]
default
:
200
interrupts
:
maxItems
:
1
minItems
:
1
maxItems
:
2
description
:
Short-circuit
interrupt
for lab.
Short-circuit
and over-current interrupts
for lab.
required
:
-
interrupts
...
...
@@ -35,11 +41,17 @@ properties:
type
:
object
properties
:
qcom,discharge-resistor-kohms
:
$ref
:
/schemas/types.yaml#/definitions/uint32
description
:
Discharge resistor value in KiloOhms.
enum
:
[
300
,
64
,
32
,
16
]
default
:
300
interrupts
:
maxItems
:
1
minItems
:
1
maxItems
:
2
description
:
Short-circuit
interrupt for la
b.
Short-circuit
and over-current interrupts for ib
b.
required
:
-
interrupts
...
...
@@ -57,13 +69,15 @@ examples:
compatible = "qcom,pmi8998-lab-ibb";
lab {
interrupts = <0x3 0x0 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "sc-err";
interrupts = <0x3 0xde 0x1 IRQ_TYPE_EDGE_RISING>,
<0x3 0xde 0x0 IRQ_TYPE_LEVEL_LOW>;
interrupt-names = "sc-err", "ocp";
};
ibb {
interrupts = <0x3 0x2 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "sc-err";
interrupts = <0x3 0xdc 0x2 IRQ_TYPE_EDGE_RISING>,
<0x3 0xdc 0x0 IRQ_TYPE_LEVEL_LOW>;
interrupt-names = "sc-err", "ocp";
};
};
...
...
Documentation/devicetree/bindings/regulator/richtek,rt4831-regulator.yaml
0 → 100644
View file @
f03e2a72
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML
1.2
---
$id
:
http://devicetree.org/schemas/regulator/richtek,rt4831-regulator.yaml#
$schema
:
http://devicetree.org/meta-schemas/core.yaml#
title
:
Richtek RT4831 Display Bias Voltage Regulator
maintainers
:
-
ChiYuan Huang <cy_huang@richtek.com>
description
:
|
RT4831 is a multifunctional device that can provide power to the LCD display
and LCD backlight.
For Display Bias Voltage DSVP and DSVN, the output range is about 4V to 6.5V.
It is sufficient to meet the current LCD power requirement.
DSVLCM is a boost regulator in IC internal as DSVP and DSVN input power.
Its voltage should be configured above 0.15V to 0.2V gap larger than the
voltage needed for DSVP and DSVN. Too much voltage gap could improve the
voltage drop from the heavy loading scenario. But it also make the power
efficiency worse. It's a trade-off.
Datasheet is available at
https://www.richtek.com/assets/product_file/RT4831A/DS4831A-05.pdf
patternProperties
:
"
^DSV(LCM|P|N)$"
:
type
:
object
$ref
:
regulator.yaml#
description
:
Properties for single Display Bias Voltage regulator.
additionalProperties
:
false
MAINTAINERS
View file @
f03e2a72
...
...
@@ -11684,9 +11684,9 @@ F: drivers/video/fbdev/atmel_lcdfb.c
F: include/video/atmel_lcdc.h
MICROCHIP MCP16502 PMIC DRIVER
M:
Andrei Stefanescu <andrei.stefanescu
@microchip.com>
M:
Claudiu Beznea <claudiu.beznea
@microchip.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S:
Maintain
ed
S:
Support
ed
F: Documentation/devicetree/bindings/regulator/mcp16502-regulator.txt
F: drivers/regulator/mcp16502.c
...
...
arch/arm64/boot/dts/qcom/qrb5165-rb5.dts
View file @
f03e2a72
...
...
@@ -122,7 +122,7 @@ vreg_s4a_1p8: vreg-s4a-1p8 {
&
apps_rsc
{
pm8009
-
rpmh
-
regulators
{
compatible
=
"qcom,pm8009-rpmh-regulators"
;
compatible
=
"qcom,pm8009-
1-
rpmh-regulators"
;
qcom
,
pmic
-
id
=
"f"
;
vdd
-
s1
-
supply
=
<&
vph_pwr
>;
...
...
@@ -131,6 +131,13 @@ pm8009-rpmh-regulators {
vdd
-
l5
-
l6
-
supply
=
<&
vreg_bob
>;
vdd
-
l7
-
supply
=
<&
vreg_s4a_1p8
>;
vreg_s2f_0p95
:
smps2
{
regulator
-
name
=
"vreg_s2f_0p95"
;
regulator
-
min
-
microvolt
=
<
900000
>;
regulator
-
max
-
microvolt
=
<
952000
>;
regulator
-
initial
-
mode
=
<
RPMH_REGULATOR_MODE_AUTO
>;
};
vreg_l1f_1p1
:
ldo1
{
regulator
-
name
=
"vreg_l1f_1p1"
;
regulator
-
min
-
microvolt
=
<
1104000
>;
...
...
drivers/mfd/ab8500-core.c
View file @
f03e2a72
...
...
@@ -21,7 +21,6 @@
#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/abx500/ab8500-bm.h>
#include <linux/mfd/dbx500-prcmu.h>
#include <linux/regulator/ab8500.h>
#include <linux/of.h>
#include <linux/of_device.h>
...
...
drivers/regulator/Kconfig
View file @
f03e2a72
...
...
@@ -122,15 +122,6 @@ config REGULATOR_AAT2870
If you have a AnalogicTech AAT2870 say Y to enable the
regulator driver.
config REGULATOR_AB3100
tristate "ST-Ericsson AB3100 Regulator functions"
depends on AB3100_CORE
default y if AB3100_CORE
help
These regulators correspond to functionality in the
AB3100 analog baseband dealing with power regulators
for the system.
config REGULATOR_AB8500
bool "ST-Ericsson AB8500 Power Regulators"
depends on AB8500_CORE
...
...
@@ -179,6 +170,14 @@ config REGULATOR_AS3722
AS3722 PMIC. This will enable support for all the software
controllable DCDC/LDO regulators.
config REGULATOR_ATC260X
tristate "Actions Semi ATC260x PMIC Regulators"
depends on MFD_ATC260X
help
This driver provides support for the voltage regulators on the
ATC260x PMICs. This will enable support for all the software
controllable DCDC/LDO regulators.
config REGULATOR_AXP20X
tristate "X-POWERS AXP20X PMIC Regulators"
depends on MFD_AXP20X
...
...
@@ -732,6 +731,16 @@ config REGULATOR_MT6311
This driver supports the control of different power rails of device
through regulator interface.
config REGULATOR_MT6315
tristate "MediaTek MT6315 PMIC"
depends on SPMI
select REGMAP_SPMI
help
Say y here to select this option to enable the power regulator of
MediaTek MT6315 PMIC.
This driver supports the control of different power rails of device
through regulator interface.
config REGULATOR_MT6323
tristate "MediaTek MT6323 PMIC"
depends on MFD_MT6397
...
...
@@ -777,6 +786,16 @@ config REGULATOR_MT6397
This driver supports the control of different power rails of device
through regulator interface.
config REGULATOR_MTK_DVFSRC
tristate "MediaTek DVFSRC regulator driver"
depends on MTK_DVFSRC
help
Say y here to control regulator by DVFSRC (dynamic voltage
and frequency scaling resource collector).
This driver supports to control regulators via the DVFSRC
of Mediatek. It allows for voting on regulator state
between multiple users.
config REGULATOR_PALMAS
tristate "TI Palmas PMIC Regulators"
depends on MFD_PALMAS
...
...
@@ -828,6 +847,10 @@ config REGULATOR_PF8X00
Say y here to support the regulators found on the NXP
PF8100/PF8121A/PF8200 PMIC.
Say M here if you want to support for the regulators found
on the NXP PF8100/PF8121A/PF8200 PMIC. The module will be named
"pf8x00-regulator".
config REGULATOR_PFUZE100
tristate "Freescale PFUZE100/200/3000/3001 regulator driver"
depends on I2C && OF
...
...
@@ -969,6 +992,16 @@ config REGULATOR_RT4801
This adds support for voltage regulators in Richtek RT4801 Display Bias IC.
The device supports two regulators (DSVP/DSVN).
config REGULATOR_RT4831
tristate "Richtek RT4831 DSV Regulators"
depends on MFD_RT4831
help
This adds support for voltage regulators in Richtek RT4831.
There are three regulators (VLCM/DSVP/DSVN).
VLCM is a virtual voltage input for DSVP/DSVN inside IC.
And DSVP/DSVN is the real Vout range from 4V to 6.5V.
It's common used to provide the power for the display panel.
config REGULATOR_RT5033
tristate "Richtek RT5033 Regulators"
depends on MFD_RT5033
...
...
drivers/regulator/Makefile
View file @
f03e2a72
...
...
@@ -16,7 +16,6 @@ obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
obj-$(CONFIG_REGULATOR_CROS_EC)
+=
cros-ec-regulator.o
obj-$(CONFIG_REGULATOR_CPCAP)
+=
cpcap-regulator.o
obj-$(CONFIG_REGULATOR_AAT2870)
+=
aat2870-regulator.o
obj-$(CONFIG_REGULATOR_AB3100)
+=
ab3100.o
obj-$(CONFIG_REGULATOR_AB8500)
+=
ab8500-ext.o ab8500.o
obj-$(CONFIG_REGULATOR_ACT8865)
+=
act8865-regulator.o
obj-$(CONFIG_REGULATOR_ACT8945A)
+=
act8945a-regulator.o
...
...
@@ -27,6 +26,7 @@ obj-$(CONFIG_REGULATOR_ARIZONA_MICSUPP) += arizona-micsupp.o
obj-$(CONFIG_REGULATOR_ARM_SCMI)
+=
scmi-regulator.o
obj-$(CONFIG_REGULATOR_AS3711)
+=
as3711-regulator.o
obj-$(CONFIG_REGULATOR_AS3722)
+=
as3722-regulator.o
obj-$(CONFIG_REGULATOR_ATC260X)
+=
atc260x-regulator.o
obj-$(CONFIG_REGULATOR_AXP20X)
+=
axp20x-regulator.o
obj-$(CONFIG_REGULATOR_BCM590XX)
+=
bcm590xx-regulator.o
obj-$(CONFIG_REGULATOR_BD70528)
+=
bd70528-regulator.o
...
...
@@ -89,11 +89,13 @@ obj-$(CONFIG_REGULATOR_MP8859) += mp8859.o
obj-$(CONFIG_REGULATOR_MP886X)
+=
mp886x.o
obj-$(CONFIG_REGULATOR_MPQ7920)
+=
mpq7920.o
obj-$(CONFIG_REGULATOR_MT6311)
+=
mt6311-regulator.o
obj-$(CONFIG_REGULATOR_MT6315)
+=
mt6315-regulator.o
obj-$(CONFIG_REGULATOR_MT6323)
+=
mt6323-regulator.o
obj-$(CONFIG_REGULATOR_MT6358)
+=
mt6358-regulator.o
obj-$(CONFIG_REGULATOR_MT6360)
+=
mt6360-regulator.o
obj-$(CONFIG_REGULATOR_MT6380)
+=
mt6380-regulator.o
obj-$(CONFIG_REGULATOR_MT6397)
+=
mt6397-regulator.o
obj-$(CONFIG_REGULATOR_MTK_DVFSRC)
+=
mtk-dvfsrc-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_LABIBB)
+=
qcom-labibb-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_RPM)
+=
qcom_rpm-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_RPMH)
+=
qcom-rpmh-regulator.o
...
...
@@ -118,6 +120,7 @@ obj-$(CONFIG_REGULATOR_RK808) += rk808-regulator.o
obj-$(CONFIG_REGULATOR_RN5T618)
+=
rn5t618-regulator.o
obj-$(CONFIG_REGULATOR_ROHM)
+=
rohm-regulator.o
obj-$(CONFIG_REGULATOR_RT4801)
+=
rt4801-regulator.o
obj-$(CONFIG_REGULATOR_RT4831)
+=
rt4831-regulator.o
obj-$(CONFIG_REGULATOR_RT5033)
+=
rt5033-regulator.o
obj-$(CONFIG_REGULATOR_RTMV20)
+=
rtmv20-regulator.o
obj-$(CONFIG_REGULATOR_S2MPA01)
+=
s2mpa01.o
...
...
drivers/regulator/ab3100.c
deleted
100644 → 0
View file @
8571bdc2
// SPDX-License-Identifier: GPL-2.0-only
/*
* drivers/regulator/ab3100.c
*
* Copyright (C) 2008-2009 ST-Ericsson AB
* Low-level control of the AB3100 IC Low Dropout (LDO)
* regulators, external regulator and buck converter
* Author: Mattias Wallin <mattias.wallin@stericsson.com>
* Author: Linus Walleij <linus.walleij@stericsson.com>
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/mfd/ab3100.h>
#include <linux/mfd/abx500.h>
#include <linux/of.h>
#include <linux/regulator/of_regulator.h>
/* LDO registers and some handy masking definitions for AB3100 */
#define AB3100_LDO_A 0x40
#define AB3100_LDO_C 0x41
#define AB3100_LDO_D 0x42
#define AB3100_LDO_E 0x43
#define AB3100_LDO_E_SLEEP 0x44
#define AB3100_LDO_F 0x45
#define AB3100_LDO_G 0x46
#define AB3100_LDO_H 0x47
#define AB3100_LDO_H_SLEEP_MODE 0
#define AB3100_LDO_H_SLEEP_EN 2
#define AB3100_LDO_ON 4
#define AB3100_LDO_H_VSEL_AC 5
#define AB3100_LDO_K 0x48
#define AB3100_LDO_EXT 0x49
#define AB3100_BUCK 0x4A
#define AB3100_BUCK_SLEEP 0x4B
#define AB3100_REG_ON_MASK 0x10
/**
* struct ab3100_regulator
* A struct passed around the individual regulator functions
* @platform_device: platform device holding this regulator
* @dev: handle to the device
* @plfdata: AB3100 platform data passed in at probe time
* @regreg: regulator register number in the AB3100
*/
struct
ab3100_regulator
{
struct
device
*
dev
;
struct
ab3100_platform_data
*
plfdata
;
u8
regreg
;
};
/* The order in which registers are initialized */
static
const
u8
ab3100_reg_init_order
[
AB3100_NUM_REGULATORS
+
2
]
=
{
AB3100_LDO_A
,
AB3100_LDO_C
,
AB3100_LDO_E
,
AB3100_LDO_E_SLEEP
,
AB3100_LDO_F
,
AB3100_LDO_G
,
AB3100_LDO_H
,
AB3100_LDO_K
,
AB3100_LDO_EXT
,
AB3100_BUCK
,
AB3100_BUCK_SLEEP
,
AB3100_LDO_D
,
};
/* Preset (hardware defined) voltages for these regulators */
#define LDO_A_VOLTAGE 2750000
#define LDO_C_VOLTAGE 2650000
#define LDO_D_VOLTAGE 2650000
static
const
unsigned
int
ldo_e_buck_typ_voltages
[]
=
{
1800000
,
1400000
,
1300000
,
1200000
,
1100000
,
1050000
,
900000
,
};
static
const
unsigned
int
ldo_f_typ_voltages
[]
=
{
1800000
,
1400000
,
1300000
,
1200000
,
1100000
,
1050000
,
2500000
,
2650000
,
};
static
const
unsigned
int
ldo_g_typ_voltages
[]
=
{
2850000
,
2750000
,
1800000
,
1500000
,
};
static
const
unsigned
int
ldo_h_typ_voltages
[]
=
{
2750000
,
1800000
,
1500000
,
1200000
,
};
static
const
unsigned
int
ldo_k_typ_voltages
[]
=
{
2750000
,
1800000
,
};
/* The regulator devices */
static
struct
ab3100_regulator
ab3100_regulators
[
AB3100_NUM_REGULATORS
]
=
{
{
.
regreg
=
AB3100_LDO_A
,
},
{
.
regreg
=
AB3100_LDO_C
,
},
{
.
regreg
=
AB3100_LDO_D
,
},
{
.
regreg
=
AB3100_LDO_E
,
},
{
.
regreg
=
AB3100_LDO_F
,
},
{
.
regreg
=
AB3100_LDO_G
,
},
{
.
regreg
=
AB3100_LDO_H
,
},
{
.
regreg
=
AB3100_LDO_K
,
},
{
.
regreg
=
AB3100_LDO_EXT
,
/* No voltages for the external regulator */
},
{
.
regreg
=
AB3100_BUCK
,
},
};
/*
* General functions for enable, disable and is_enabled used for
* LDO: A,C,E,F,G,H,K,EXT and BUCK
*/
static
int
ab3100_enable_regulator
(
struct
regulator_dev
*
reg
)
{
struct
ab3100_regulator
*
abreg
=
rdev_get_drvdata
(
reg
);
int
err
;
u8
regval
;
err
=
abx500_get_register_interruptible
(
abreg
->
dev
,
0
,
abreg
->
regreg
,
&
regval
);
if
(
err
)
{
dev_warn
(
&
reg
->
dev
,
"failed to get regid %d value
\n
"
,
abreg
->
regreg
);
return
err
;
}
/* The regulator is already on, no reason to go further */
if
(
regval
&
AB3100_REG_ON_MASK
)
return
0
;
regval
|=
AB3100_REG_ON_MASK
;
err
=
abx500_set_register_interruptible
(
abreg
->
dev
,
0
,
abreg
->
regreg
,
regval
);
if
(
err
)
{
dev_warn
(
&
reg
->
dev
,
"failed to set regid %d value
\n
"
,
abreg
->
regreg
);
return
err
;
}
return
0
;
}
static
int
ab3100_disable_regulator
(
struct
regulator_dev
*
reg
)
{
struct
ab3100_regulator
*
abreg
=
rdev_get_drvdata
(
reg
);
int
err
;
u8
regval
;
/*
* LDO D is a special regulator. When it is disabled, the entire
* system is shut down. So this is handled specially.
*/
pr_info
(
"Called ab3100_disable_regulator
\n
"
);
if
(
abreg
->
regreg
==
AB3100_LDO_D
)
{
dev_info
(
&
reg
->
dev
,
"disabling LDO D - shut down system
\n
"
);
/* Setting LDO D to 0x00 cuts the power to the SoC */
return
abx500_set_register_interruptible
(
abreg
->
dev
,
0
,
AB3100_LDO_D
,
0x00U
);
}
/*
* All other regulators are handled here
*/
err
=
abx500_get_register_interruptible
(
abreg
->
dev
,
0
,
abreg
->
regreg
,
&
regval
);
if
(
err
)
{
dev_err
(
&
reg
->
dev
,
"unable to get register 0x%x
\n
"
,
abreg
->
regreg
);
return
err
;
}
regval
&=
~
AB3100_REG_ON_MASK
;
return
abx500_set_register_interruptible
(
abreg
->
dev
,
0
,
abreg
->
regreg
,
regval
);
}
static
int
ab3100_is_enabled_regulator
(
struct
regulator_dev
*
reg
)
{
struct
ab3100_regulator
*
abreg
=
rdev_get_drvdata
(
reg
);
u8
regval
;
int
err
;
err
=
abx500_get_register_interruptible
(
abreg
->
dev
,
0
,
abreg
->
regreg
,
&
regval
);
if
(
err
)
{
dev_err
(
&
reg
->
dev
,
"unable to get register 0x%x
\n
"
,
abreg
->
regreg
);
return
err
;
}
return
regval
&
AB3100_REG_ON_MASK
;
}
static
int
ab3100_get_voltage_regulator
(
struct
regulator_dev
*
reg
)
{
struct
ab3100_regulator
*
abreg
=
rdev_get_drvdata
(
reg
);
u8
regval
;
int
err
;
/*
* For variable types, read out setting and index into
* supplied voltage list.
*/
err
=
abx500_get_register_interruptible
(
abreg
->
dev
,
0
,
abreg
->
regreg
,
&
regval
);
if
(
err
)
{
dev_warn
(
&
reg
->
dev
,
"failed to get regulator value in register %02x
\n
"
,
abreg
->
regreg
);
return
err
;
}
/* The 3 highest bits index voltages */
regval
&=
0xE0
;
regval
>>=
5
;
if
(
regval
>=
reg
->
desc
->
n_voltages
)
{
dev_err
(
&
reg
->
dev
,
"regulator register %02x contains an illegal voltage setting
\n
"
,
abreg
->
regreg
);
return
-
EINVAL
;
}
return
reg
->
desc
->
volt_table
[
regval
];
}
static
int
ab3100_set_voltage_regulator_sel
(
struct
regulator_dev
*
reg
,
unsigned
selector
)
{
struct
ab3100_regulator
*
abreg
=
rdev_get_drvdata
(
reg
);
u8
regval
;
int
err
;
err
=
abx500_get_register_interruptible
(
abreg
->
dev
,
0
,
abreg
->
regreg
,
&
regval
);
if
(
err
)
{
dev_warn
(
&
reg
->
dev
,
"failed to get regulator register %02x
\n
"
,
abreg
->
regreg
);
return
err
;
}
/* The highest three bits control the variable regulators */
regval
&=
~
0xE0
;
regval
|=
(
selector
<<
5
);
err
=
abx500_set_register_interruptible
(
abreg
->
dev
,
0
,
abreg
->
regreg
,
regval
);
if
(
err
)
dev_warn
(
&
reg
->
dev
,
"failed to set regulator register %02x
\n
"
,
abreg
->
regreg
);
return
err
;
}
static
int
ab3100_set_suspend_voltage_regulator
(
struct
regulator_dev
*
reg
,
int
uV
)
{
struct
ab3100_regulator
*
abreg
=
rdev_get_drvdata
(
reg
);
u8
regval
;
int
err
;
int
bestindex
;
u8
targetreg
;
if
(
abreg
->
regreg
==
AB3100_LDO_E
)
targetreg
=
AB3100_LDO_E_SLEEP
;
else
if
(
abreg
->
regreg
==
AB3100_BUCK
)
targetreg
=
AB3100_BUCK_SLEEP
;
else
return
-
EINVAL
;
/* LDO E and BUCK have special suspend voltages you can set */
bestindex
=
regulator_map_voltage_iterate
(
reg
,
uV
,
uV
);
err
=
abx500_get_register_interruptible
(
abreg
->
dev
,
0
,
targetreg
,
&
regval
);
if
(
err
)
{
dev_warn
(
&
reg
->
dev
,
"failed to get regulator register %02x
\n
"
,
targetreg
);
return
err
;
}
/* The highest three bits control the variable regulators */
regval
&=
~
0xE0
;
regval
|=
(
bestindex
<<
5
);
err
=
abx500_set_register_interruptible
(
abreg
->
dev
,
0
,
targetreg
,
regval
);
if
(
err
)
dev_warn
(
&
reg
->
dev
,
"failed to set regulator register %02x
\n
"
,
abreg
->
regreg
);
return
err
;
}
/*
* The external regulator can just define a fixed voltage.
*/
static
int
ab3100_get_voltage_regulator_external
(
struct
regulator_dev
*
reg
)
{
struct
ab3100_regulator
*
abreg
=
rdev_get_drvdata
(
reg
);
if
(
abreg
->
plfdata
)
return
abreg
->
plfdata
->
external_voltage
;
else
/* TODO: encode external voltage into device tree */
return
0
;
}
static
const
struct
regulator_ops
regulator_ops_fixed
=
{
.
enable
=
ab3100_enable_regulator
,
.
disable
=
ab3100_disable_regulator
,
.
is_enabled
=
ab3100_is_enabled_regulator
,
};
static
const
struct
regulator_ops
regulator_ops_variable
=
{
.
enable
=
ab3100_enable_regulator
,
.
disable
=
ab3100_disable_regulator
,
.
is_enabled
=
ab3100_is_enabled_regulator
,
.
get_voltage
=
ab3100_get_voltage_regulator
,
.
set_voltage_sel
=
ab3100_set_voltage_regulator_sel
,
.
list_voltage
=
regulator_list_voltage_table
,
};
static
const
struct
regulator_ops
regulator_ops_variable_sleepable
=
{
.
enable
=
ab3100_enable_regulator
,
.
disable
=
ab3100_disable_regulator
,
.
is_enabled
=
ab3100_is_enabled_regulator
,
.
get_voltage
=
ab3100_get_voltage_regulator
,
.
set_voltage_sel
=
ab3100_set_voltage_regulator_sel
,
.
set_suspend_voltage
=
ab3100_set_suspend_voltage_regulator
,
.
list_voltage
=
regulator_list_voltage_table
,
};
/*
* LDO EXT is an external regulator so it is really
* not possible to set any voltage locally here, AB3100
* is an on/off switch plain an simple. The external
* voltage is defined in the board set-up if any.
*/
static
const
struct
regulator_ops
regulator_ops_external
=
{
.
enable
=
ab3100_enable_regulator
,
.
disable
=
ab3100_disable_regulator
,
.
is_enabled
=
ab3100_is_enabled_regulator
,
.
get_voltage
=
ab3100_get_voltage_regulator_external
,
};
static
const
struct
regulator_desc
ab3100_regulator_desc
[
AB3100_NUM_REGULATORS
]
=
{
{
.
name
=
"LDO_A"
,
.
id
=
AB3100_LDO_A
,
.
ops
=
&
regulator_ops_fixed
,
.
n_voltages
=
1
,
.
type
=
REGULATOR_VOLTAGE
,
.
owner
=
THIS_MODULE
,
.
fixed_uV
=
LDO_A_VOLTAGE
,
.
enable_time
=
200
,
},
{
.
name
=
"LDO_C"
,
.
id
=
AB3100_LDO_C
,
.
ops
=
&
regulator_ops_fixed
,
.
n_voltages
=
1
,
.
type
=
REGULATOR_VOLTAGE
,
.
owner
=
THIS_MODULE
,
.
fixed_uV
=
LDO_C_VOLTAGE
,
.
enable_time
=
200
,
},
{
.
name
=
"LDO_D"
,
.
id
=
AB3100_LDO_D
,
.
ops
=
&
regulator_ops_fixed
,
.
n_voltages
=
1
,
.
type
=
REGULATOR_VOLTAGE
,
.
owner
=
THIS_MODULE
,
.
fixed_uV
=
LDO_D_VOLTAGE
,
.
enable_time
=
200
,
},
{
.
name
=
"LDO_E"
,
.
id
=
AB3100_LDO_E
,
.
ops
=
&
regulator_ops_variable_sleepable
,
.
n_voltages
=
ARRAY_SIZE
(
ldo_e_buck_typ_voltages
),
.
volt_table
=
ldo_e_buck_typ_voltages
,
.
type
=
REGULATOR_VOLTAGE
,
.
owner
=
THIS_MODULE
,
.
enable_time
=
200
,
},
{
.
name
=
"LDO_F"
,
.
id
=
AB3100_LDO_F
,
.
ops
=
&
regulator_ops_variable
,
.
n_voltages
=
ARRAY_SIZE
(
ldo_f_typ_voltages
),
.
volt_table
=
ldo_f_typ_voltages
,
.
type
=
REGULATOR_VOLTAGE
,
.
owner
=
THIS_MODULE
,
.
enable_time
=
600
,
},
{
.
name
=
"LDO_G"
,
.
id
=
AB3100_LDO_G
,
.
ops
=
&
regulator_ops_variable
,
.
n_voltages
=
ARRAY_SIZE
(
ldo_g_typ_voltages
),
.
volt_table
=
ldo_g_typ_voltages
,
.
type
=
REGULATOR_VOLTAGE
,
.
owner
=
THIS_MODULE
,
.
enable_time
=
400
,
},
{
.
name
=
"LDO_H"
,
.
id
=
AB3100_LDO_H
,
.
ops
=
&
regulator_ops_variable
,
.
n_voltages
=
ARRAY_SIZE
(
ldo_h_typ_voltages
),
.
volt_table
=
ldo_h_typ_voltages
,
.
type
=
REGULATOR_VOLTAGE
,
.
owner
=
THIS_MODULE
,
.
enable_time
=
200
,
},
{
.
name
=
"LDO_K"
,
.
id
=
AB3100_LDO_K
,
.
ops
=
&
regulator_ops_variable
,
.
n_voltages
=
ARRAY_SIZE
(
ldo_k_typ_voltages
),
.
volt_table
=
ldo_k_typ_voltages
,
.
type
=
REGULATOR_VOLTAGE
,
.
owner
=
THIS_MODULE
,
.
enable_time
=
200
,
},
{
.
name
=
"LDO_EXT"
,
.
id
=
AB3100_LDO_EXT
,
.
ops
=
&
regulator_ops_external
,
.
type
=
REGULATOR_VOLTAGE
,
.
owner
=
THIS_MODULE
,
},
{
.
name
=
"BUCK"
,
.
id
=
AB3100_BUCK
,
.
ops
=
&
regulator_ops_variable_sleepable
,
.
n_voltages
=
ARRAY_SIZE
(
ldo_e_buck_typ_voltages
),
.
volt_table
=
ldo_e_buck_typ_voltages
,
.
type
=
REGULATOR_VOLTAGE
,
.
owner
=
THIS_MODULE
,
.
enable_time
=
1000
,
},
};
static
int
ab3100_regulator_register
(
struct
platform_device
*
pdev
,
struct
ab3100_platform_data
*
plfdata
,
struct
regulator_init_data
*
init_data
,
struct
device_node
*
np
,
unsigned
long
id
)
{
const
struct
regulator_desc
*
desc
;
struct
ab3100_regulator
*
reg
;
struct
regulator_dev
*
rdev
;
struct
regulator_config
config
=
{
};
int
err
,
i
;
for
(
i
=
0
;
i
<
AB3100_NUM_REGULATORS
;
i
++
)
{
desc
=
&
ab3100_regulator_desc
[
i
];
if
(
desc
->
id
==
id
)
break
;
}
if
(
desc
->
id
!=
id
)
return
-
ENODEV
;
/* Same index used for this array */
reg
=
&
ab3100_regulators
[
i
];
/*
* Initialize per-regulator struct.
* Inherit platform data, this comes down from the
* i2c boarddata, from the machine. So if you want to
* see what it looks like for a certain machine, go
* into the machine I2C setup.
*/
reg
->
dev
=
&
pdev
->
dev
;
if
(
plfdata
)
{
reg
->
plfdata
=
plfdata
;
config
.
init_data
=
&
plfdata
->
reg_constraints
[
i
];
}
else
if
(
np
)
{
config
.
of_node
=
np
;
config
.
init_data
=
init_data
;
}
config
.
dev
=
&
pdev
->
dev
;
config
.
driver_data
=
reg
;
rdev
=
devm_regulator_register
(
&
pdev
->
dev
,
desc
,
&
config
);
if
(
IS_ERR
(
rdev
))
{
err
=
PTR_ERR
(
rdev
);
dev_err
(
&
pdev
->
dev
,
"%s: failed to register regulator %s err %d
\n
"
,
__func__
,
desc
->
name
,
err
);
return
err
;
}
return
0
;
}
static
struct
of_regulator_match
ab3100_regulator_matches
[]
=
{
{
.
name
=
"ab3100_ldo_a"
,
.
driver_data
=
(
void
*
)
AB3100_LDO_A
,
},
{
.
name
=
"ab3100_ldo_c"
,
.
driver_data
=
(
void
*
)
AB3100_LDO_C
,
},
{
.
name
=
"ab3100_ldo_d"
,
.
driver_data
=
(
void
*
)
AB3100_LDO_D
,
},
{
.
name
=
"ab3100_ldo_e"
,
.
driver_data
=
(
void
*
)
AB3100_LDO_E
,
},
{
.
name
=
"ab3100_ldo_f"
,
.
driver_data
=
(
void
*
)
AB3100_LDO_F
},
{
.
name
=
"ab3100_ldo_g"
,
.
driver_data
=
(
void
*
)
AB3100_LDO_G
},
{
.
name
=
"ab3100_ldo_h"
,
.
driver_data
=
(
void
*
)
AB3100_LDO_H
},
{
.
name
=
"ab3100_ldo_k"
,
.
driver_data
=
(
void
*
)
AB3100_LDO_K
},
{
.
name
=
"ab3100_ext"
,
.
driver_data
=
(
void
*
)
AB3100_LDO_EXT
},
{
.
name
=
"ab3100_buck"
,
.
driver_data
=
(
void
*
)
AB3100_BUCK
},
};
/*
* Initial settings of ab3100 registers.
* Common for below LDO regulator settings are that
* bit 7-5 controls voltage. Bit 4 turns regulator ON(1) or OFF(0).
* Bit 3-2 controls sleep enable and bit 1-0 controls sleep mode.
*/
/* LDO_A 0x16: 2.75V, ON, SLEEP_A, SLEEP OFF GND */
#define LDO_A_SETTING 0x16
/* LDO_C 0x10: 2.65V, ON, SLEEP_A or B, SLEEP full power */
#define LDO_C_SETTING 0x10
/* LDO_D 0x10: 2.65V, ON, sleep mode not used */
#define LDO_D_SETTING 0x10
/* LDO_E 0x10: 1.8V, ON, SLEEP_A or B, SLEEP full power */
#define LDO_E_SETTING 0x10
/* LDO_E SLEEP 0x00: 1.8V, not used, SLEEP_A or B, not used */
#define LDO_E_SLEEP_SETTING 0x00
/* LDO_F 0xD0: 2.5V, ON, SLEEP_A or B, SLEEP full power */
#define LDO_F_SETTING 0xD0
/* LDO_G 0x00: 2.85V, OFF, SLEEP_A or B, SLEEP full power */
#define LDO_G_SETTING 0x00
/* LDO_H 0x18: 2.75V, ON, SLEEP_B, SLEEP full power */
#define LDO_H_SETTING 0x18
/* LDO_K 0x00: 2.75V, OFF, SLEEP_A or B, SLEEP full power */
#define LDO_K_SETTING 0x00
/* LDO_EXT 0x00: Voltage not set, OFF, not used, not used */
#define LDO_EXT_SETTING 0x00
/* BUCK 0x7D: 1.2V, ON, SLEEP_A and B, SLEEP low power */
#define BUCK_SETTING 0x7D
/* BUCK SLEEP 0xAC: 1.05V, Not used, SLEEP_A and B, Not used */
#define BUCK_SLEEP_SETTING 0xAC
static
const
u8
ab3100_reg_initvals
[]
=
{
LDO_A_SETTING
,
LDO_C_SETTING
,
LDO_E_SETTING
,
LDO_E_SLEEP_SETTING
,
LDO_F_SETTING
,
LDO_G_SETTING
,
LDO_H_SETTING
,
LDO_K_SETTING
,
LDO_EXT_SETTING
,
BUCK_SETTING
,
BUCK_SLEEP_SETTING
,
LDO_D_SETTING
,
};
static
int
ab3100_regulator_of_probe
(
struct
platform_device
*
pdev
,
struct
device_node
*
np
)
{
int
err
,
i
;
/*
* Set up the regulator registers, as was previously done with
* platform data.
*/
/* Set up regulators */
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
ab3100_reg_init_order
);
i
++
)
{
err
=
abx500_set_register_interruptible
(
&
pdev
->
dev
,
0
,
ab3100_reg_init_order
[
i
],
ab3100_reg_initvals
[
i
]);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"regulator initialization failed with error %d
\n
"
,
err
);
return
err
;
}
}
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
ab3100_regulator_matches
);
i
++
)
{
err
=
ab3100_regulator_register
(
pdev
,
NULL
,
ab3100_regulator_matches
[
i
].
init_data
,
ab3100_regulator_matches
[
i
].
of_node
,
(
unsigned
long
)
ab3100_regulator_matches
[
i
].
driver_data
);
if
(
err
)
return
err
;
}
return
0
;
}
static
int
ab3100_regulators_probe
(
struct
platform_device
*
pdev
)
{
struct
ab3100_platform_data
*
plfdata
=
dev_get_platdata
(
&
pdev
->
dev
);
struct
device_node
*
np
=
pdev
->
dev
.
of_node
;
int
err
=
0
;
u8
data
;
int
i
;
/* Check chip state */
err
=
abx500_get_register_interruptible
(
&
pdev
->
dev
,
0
,
AB3100_LDO_D
,
&
data
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"could not read initial status of LDO_D
\n
"
);
return
err
;
}
if
(
data
&
0x10
)
dev_notice
(
&
pdev
->
dev
,
"chip is already in active mode (Warm start)
\n
"
);
else
dev_notice
(
&
pdev
->
dev
,
"chip is in inactive mode (Cold start)
\n
"
);
if
(
np
)
{
err
=
of_regulator_match
(
&
pdev
->
dev
,
np
,
ab3100_regulator_matches
,
ARRAY_SIZE
(
ab3100_regulator_matches
));
if
(
err
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"Error parsing regulator init data: %d
\n
"
,
err
);
return
err
;
}
return
ab3100_regulator_of_probe
(
pdev
,
np
);
}
/* Set up regulators */
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
ab3100_reg_init_order
);
i
++
)
{
err
=
abx500_set_register_interruptible
(
&
pdev
->
dev
,
0
,
ab3100_reg_init_order
[
i
],
plfdata
->
reg_initvals
[
i
]);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"regulator initialization failed with error %d
\n
"
,
err
);
return
err
;
}
}
/* Register the regulators */
for
(
i
=
0
;
i
<
AB3100_NUM_REGULATORS
;
i
++
)
{
const
struct
regulator_desc
*
desc
=
&
ab3100_regulator_desc
[
i
];
err
=
ab3100_regulator_register
(
pdev
,
plfdata
,
NULL
,
NULL
,
desc
->
id
);
if
(
err
)
return
err
;
}
return
0
;
}
static
struct
platform_driver
ab3100_regulators_driver
=
{
.
driver
=
{
.
name
=
"ab3100-regulators"
,
},
.
probe
=
ab3100_regulators_probe
,
};
static
__init
int
ab3100_regulators_init
(
void
)
{
return
platform_driver_register
(
&
ab3100_regulators_driver
);
}
static
__exit
void
ab3100_regulators_exit
(
void
)
{
platform_driver_unregister
(
&
ab3100_regulators_driver
);
}
subsys_initcall
(
ab3100_regulators_init
);
module_exit
(
ab3100_regulators_exit
);
MODULE_AUTHOR
(
"Mattias Wallin <mattias.wallin@stericsson.com>"
);
MODULE_DESCRIPTION
(
"AB3100 Regulator driver"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_ALIAS
(
"platform:ab3100-regulators"
);
drivers/regulator/ab8500-ext.c
View file @
f03e2a72
...
...
@@ -22,403 +22,17 @@
#include <linux/regulator/of_regulator.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/regulator/ab8500.h>
static
struct
regulator_consumer_supply
ab8500_vaux1_consumers
[]
=
{
/* Main display, u8500 R3 uib */
REGULATOR_SUPPLY
(
"vddi"
,
"mcde_disp_sony_acx424akp.0"
),
/* Main display, u8500 uib and ST uib */
REGULATOR_SUPPLY
(
"vdd1"
,
"samsung_s6d16d0.0"
),
/* Secondary display, ST uib */
REGULATOR_SUPPLY
(
"vdd1"
,
"samsung_s6d16d0.1"
),
/* SFH7741 proximity sensor */
REGULATOR_SUPPLY
(
"vcc"
,
"gpio-keys.0"
),
/* BH1780GLS ambient light sensor */
REGULATOR_SUPPLY
(
"vcc"
,
"2-0029"
),
/* lsm303dlh accelerometer */
REGULATOR_SUPPLY
(
"vdd"
,
"2-0018"
),
/* lsm303dlhc accelerometer */
REGULATOR_SUPPLY
(
"vdd"
,
"2-0019"
),
/* lsm303dlh magnetometer */
REGULATOR_SUPPLY
(
"vdd"
,
"2-001e"
),
/* Rohm BU21013 Touchscreen devices */
REGULATOR_SUPPLY
(
"avdd"
,
"3-005c"
),
REGULATOR_SUPPLY
(
"avdd"
,
"3-005d"
),
/* Synaptics RMI4 Touchscreen device */
REGULATOR_SUPPLY
(
"vdd"
,
"3-004b"
),
/* L3G4200D Gyroscope device */
REGULATOR_SUPPLY
(
"vdd"
,
"2-0068"
),
/* Ambient light sensor device */
REGULATOR_SUPPLY
(
"vdd"
,
"3-0029"
),
/* Pressure sensor device */
REGULATOR_SUPPLY
(
"vdd"
,
"2-005c"
),
/* Cypress TrueTouch Touchscreen device */
REGULATOR_SUPPLY
(
"vcpin"
,
"spi8.0"
),
/* Camera device */
REGULATOR_SUPPLY
(
"vaux12v5"
,
"mmio_camera"
),
};
static
struct
regulator_consumer_supply
ab8500_vaux2_consumers
[]
=
{
/* On-board eMMC power */
REGULATOR_SUPPLY
(
"vmmc"
,
"sdi4"
),
/* AB8500 audio codec */
REGULATOR_SUPPLY
(
"vcc-N2158"
,
"ab8500-codec.0"
),
/* AB8500 accessory detect 1 */
REGULATOR_SUPPLY
(
"vcc-N2158"
,
"ab8500-acc-det.0"
),
/* AB8500 Tv-out device */
REGULATOR_SUPPLY
(
"vcc-N2158"
,
"mcde_tv_ab8500.4"
),
/* AV8100 HDMI device */
REGULATOR_SUPPLY
(
"vcc-N2158"
,
"av8100_hdmi.3"
),
};
static
struct
regulator_consumer_supply
ab8500_vaux3_consumers
[]
=
{
REGULATOR_SUPPLY
(
"v-SD-STM"
,
"stm"
),
/* External MMC slot power */
REGULATOR_SUPPLY
(
"vmmc"
,
"sdi0"
),
};
static
struct
regulator_consumer_supply
ab8500_vtvout_consumers
[]
=
{
/* TV-out DENC supply */
REGULATOR_SUPPLY
(
"vtvout"
,
"ab8500-denc.0"
),
/* Internal general-purpose ADC */
REGULATOR_SUPPLY
(
"vddadc"
,
"ab8500-gpadc.0"
),
/* ADC for charger */
REGULATOR_SUPPLY
(
"vddadc"
,
"ab8500-charger.0"
),
/* AB8500 Tv-out device */
REGULATOR_SUPPLY
(
"vtvout"
,
"mcde_tv_ab8500.4"
),
};
static
struct
regulator_consumer_supply
ab8500_vaud_consumers
[]
=
{
/* AB8500 audio-codec main supply */
REGULATOR_SUPPLY
(
"vaud"
,
"ab8500-codec.0"
),
};
static
struct
regulator_consumer_supply
ab8500_vamic1_consumers
[]
=
{
/* AB8500 audio-codec Mic1 supply */
REGULATOR_SUPPLY
(
"vamic1"
,
"ab8500-codec.0"
),
};
static
struct
regulator_consumer_supply
ab8500_vamic2_consumers
[]
=
{
/* AB8500 audio-codec Mic2 supply */
REGULATOR_SUPPLY
(
"vamic2"
,
"ab8500-codec.0"
),
};
static
struct
regulator_consumer_supply
ab8500_vdmic_consumers
[]
=
{
/* AB8500 audio-codec DMic supply */
REGULATOR_SUPPLY
(
"vdmic"
,
"ab8500-codec.0"
),
};
static
struct
regulator_consumer_supply
ab8500_vintcore_consumers
[]
=
{
/* SoC core supply, no device */
REGULATOR_SUPPLY
(
"v-intcore"
,
NULL
),
/* USB Transceiver */
REGULATOR_SUPPLY
(
"vddulpivio18"
,
"ab8500-usb.0"
),
/* Handled by abx500 clk driver */
REGULATOR_SUPPLY
(
"v-intcore"
,
"abx500-clk.0"
),
};
static
struct
regulator_consumer_supply
ab8500_vana_consumers
[]
=
{
/* DB8500 DSI */
REGULATOR_SUPPLY
(
"vdddsi1v2"
,
"mcde"
),
REGULATOR_SUPPLY
(
"vdddsi1v2"
,
"b2r2_core"
),
REGULATOR_SUPPLY
(
"vdddsi1v2"
,
"b2r2_1_core"
),
REGULATOR_SUPPLY
(
"vdddsi1v2"
,
"dsilink.0"
),
REGULATOR_SUPPLY
(
"vdddsi1v2"
,
"dsilink.1"
),
REGULATOR_SUPPLY
(
"vdddsi1v2"
,
"dsilink.2"
),
/* DB8500 CSI */
REGULATOR_SUPPLY
(
"vddcsi1v2"
,
"mmio_camera"
),
};
/* ab8500 regulator register initialization */
static
struct
ab8500_regulator_reg_init
ab8500_reg_init
[]
=
{
/*
* VanaRequestCtrl = HP/LP depending on VxRequest
* VextSupply1RequestCtrl = HP/LP depending on VxRequest
*/
INIT_REGULATOR_REGISTER
(
AB8500_REGUREQUESTCTRL2
,
0xf0
,
0x00
),
/*
* VextSupply2RequestCtrl = HP/LP depending on VxRequest
* VextSupply3RequestCtrl = HP/LP depending on VxRequest
* Vaux1RequestCtrl = HP/LP depending on VxRequest
* Vaux2RequestCtrl = HP/LP depending on VxRequest
*/
INIT_REGULATOR_REGISTER
(
AB8500_REGUREQUESTCTRL3
,
0xff
,
0x00
),
/*
* Vaux3RequestCtrl = HP/LP depending on VxRequest
* SwHPReq = Control through SWValid disabled
*/
INIT_REGULATOR_REGISTER
(
AB8500_REGUREQUESTCTRL4
,
0x07
,
0x00
),
/*
* VanaSysClkReq1HPValid = disabled
* Vaux1SysClkReq1HPValid = disabled
* Vaux2SysClkReq1HPValid = disabled
* Vaux3SysClkReq1HPValid = disabled
*/
INIT_REGULATOR_REGISTER
(
AB8500_REGUSYSCLKREQ1HPVALID1
,
0xe8
,
0x00
),
/*
* VextSupply1SysClkReq1HPValid = disabled
* VextSupply2SysClkReq1HPValid = disabled
* VextSupply3SysClkReq1HPValid = SysClkReq1 controlled
*/
INIT_REGULATOR_REGISTER
(
AB8500_REGUSYSCLKREQ1HPVALID2
,
0x70
,
0x40
),
/*
* VanaHwHPReq1Valid = disabled
* Vaux1HwHPreq1Valid = disabled
* Vaux2HwHPReq1Valid = disabled
* Vaux3HwHPReqValid = disabled
*/
INIT_REGULATOR_REGISTER
(
AB8500_REGUHWHPREQ1VALID1
,
0xe8
,
0x00
),
/*
* VextSupply1HwHPReq1Valid = disabled
* VextSupply2HwHPReq1Valid = disabled
* VextSupply3HwHPReq1Valid = disabled
*/
INIT_REGULATOR_REGISTER
(
AB8500_REGUHWHPREQ1VALID2
,
0x07
,
0x00
),
/*
* VanaHwHPReq2Valid = disabled
* Vaux1HwHPReq2Valid = disabled
* Vaux2HwHPReq2Valid = disabled
* Vaux3HwHPReq2Valid = disabled
*/
INIT_REGULATOR_REGISTER
(
AB8500_REGUHWHPREQ2VALID1
,
0xe8
,
0x00
),
/*
* VextSupply1HwHPReq2Valid = disabled
* VextSupply2HwHPReq2Valid = disabled
* VextSupply3HwHPReq2Valid = HWReq2 controlled
*/
INIT_REGULATOR_REGISTER
(
AB8500_REGUHWHPREQ2VALID2
,
0x07
,
0x04
),
/*
* VanaSwHPReqValid = disabled
* Vaux1SwHPReqValid = disabled
*/
INIT_REGULATOR_REGISTER
(
AB8500_REGUSWHPREQVALID1
,
0xa0
,
0x00
),
/*
* Vaux2SwHPReqValid = disabled
* Vaux3SwHPReqValid = disabled
* VextSupply1SwHPReqValid = disabled
* VextSupply2SwHPReqValid = disabled
* VextSupply3SwHPReqValid = disabled
*/
INIT_REGULATOR_REGISTER
(
AB8500_REGUSWHPREQVALID2
,
0x1f
,
0x00
),
/*
* SysClkReq2Valid1 = SysClkReq2 controlled
* SysClkReq3Valid1 = disabled
* SysClkReq4Valid1 = SysClkReq4 controlled
* SysClkReq5Valid1 = disabled
* SysClkReq6Valid1 = SysClkReq6 controlled
* SysClkReq7Valid1 = disabled
* SysClkReq8Valid1 = disabled
*/
INIT_REGULATOR_REGISTER
(
AB8500_REGUSYSCLKREQVALID1
,
0xfe
,
0x2a
),
/*
* SysClkReq2Valid2 = disabled
* SysClkReq3Valid2 = disabled
* SysClkReq4Valid2 = disabled
* SysClkReq5Valid2 = disabled
* SysClkReq6Valid2 = SysClkReq6 controlled
* SysClkReq7Valid2 = disabled
* SysClkReq8Valid2 = disabled
*/
INIT_REGULATOR_REGISTER
(
AB8500_REGUSYSCLKREQVALID2
,
0xfe
,
0x20
),
/*
* VTVoutEna = disabled
* Vintcore12Ena = disabled
* Vintcore12Sel = 1.25 V
* Vintcore12LP = inactive (HP)
* VTVoutLP = inactive (HP)
*/
INIT_REGULATOR_REGISTER
(
AB8500_REGUMISC1
,
0xfe
,
0x10
),
/*
* VaudioEna = disabled
* VdmicEna = disabled
* Vamic1Ena = disabled
* Vamic2Ena = disabled
*/
INIT_REGULATOR_REGISTER
(
AB8500_VAUDIOSUPPLY
,
0x1e
,
0x00
),
/*
* Vamic1_dzout = high-Z when Vamic1 is disabled
* Vamic2_dzout = high-Z when Vamic2 is disabled
*/
INIT_REGULATOR_REGISTER
(
AB8500_REGUCTRL1VAMIC
,
0x03
,
0x00
),
/*
* VPll = Hw controlled (NOTE! PRCMU bits)
* VanaRegu = force off
*/
INIT_REGULATOR_REGISTER
(
AB8500_VPLLVANAREGU
,
0x0f
,
0x02
),
/*
* VrefDDREna = disabled
* VrefDDRSleepMode = inactive (no pulldown)
*/
INIT_REGULATOR_REGISTER
(
AB8500_VREFDDR
,
0x03
,
0x00
),
/*
* VextSupply1Regu = force LP
* VextSupply2Regu = force OFF
* VextSupply3Regu = force HP (-> STBB2=LP and TPS=LP)
* ExtSupply2Bypass = ExtSupply12LPn ball is 0 when Ena is 0
* ExtSupply3Bypass = ExtSupply3LPn ball is 0 when Ena is 0
*/
INIT_REGULATOR_REGISTER
(
AB8500_EXTSUPPLYREGU
,
0xff
,
0x13
),
/*
* Vaux1Regu = force HP
* Vaux2Regu = force off
*/
INIT_REGULATOR_REGISTER
(
AB8500_VAUX12REGU
,
0x0f
,
0x01
),
/*
* Vaux3Regu = force off
*/
INIT_REGULATOR_REGISTER
(
AB8500_VRF1VAUX3REGU
,
0x03
,
0x00
),
/*
* Vaux1Sel = 2.8 V
*/
INIT_REGULATOR_REGISTER
(
AB8500_VAUX1SEL
,
0x0f
,
0x0C
),
/*
* Vaux2Sel = 2.9 V
*/
INIT_REGULATOR_REGISTER
(
AB8500_VAUX2SEL
,
0x0f
,
0x0d
),
/*
* Vaux3Sel = 2.91 V
*/
INIT_REGULATOR_REGISTER
(
AB8500_VRF1VAUX3SEL
,
0x07
,
0x07
),
/*
* VextSupply12LP = disabled (no LP)
*/
INIT_REGULATOR_REGISTER
(
AB8500_REGUCTRL2SPARE
,
0x01
,
0x00
),
/*
* Vaux1Disch = short discharge time
* Vaux2Disch = short discharge time
* Vaux3Disch = short discharge time
* Vintcore12Disch = short discharge time
* VTVoutDisch = short discharge time
* VaudioDisch = short discharge time
*/
INIT_REGULATOR_REGISTER
(
AB8500_REGUCTRLDISCH
,
0xfc
,
0x00
),
/*
* VanaDisch = short discharge time
* VdmicPullDownEna = pulldown disabled when Vdmic is disabled
* VdmicDisch = short discharge time
*/
INIT_REGULATOR_REGISTER
(
AB8500_REGUCTRLDISCH2
,
0x16
,
0x00
),
/* AB8500 external regulators */
enum
ab8500_ext_regulator_id
{
AB8500_EXT_SUPPLY1
,
AB8500_EXT_SUPPLY2
,
AB8500_EXT_SUPPLY3
,
AB8500_NUM_EXT_REGULATORS
,
};
/* AB8500 regulators */
static
struct
regulator_init_data
ab8500_regulators
[
AB8500_NUM_REGULATORS
]
=
{
/* supplies to the display/camera */
[
AB8500_LDO_AUX1
]
=
{
.
supply_regulator
=
"ab8500-ext-supply3"
,
.
constraints
=
{
.
name
=
"V-DISPLAY"
,
.
min_uV
=
2800000
,
.
max_uV
=
3300000
,
.
valid_ops_mask
=
REGULATOR_CHANGE_VOLTAGE
|
REGULATOR_CHANGE_STATUS
,
.
boot_on
=
1
,
/* display is on at boot */
},
.
num_consumer_supplies
=
ARRAY_SIZE
(
ab8500_vaux1_consumers
),
.
consumer_supplies
=
ab8500_vaux1_consumers
,
},
/* supplies to the on-board eMMC */
[
AB8500_LDO_AUX2
]
=
{
.
supply_regulator
=
"ab8500-ext-supply3"
,
.
constraints
=
{
.
name
=
"V-eMMC1"
,
.
min_uV
=
1100000
,
.
max_uV
=
3300000
,
.
valid_ops_mask
=
REGULATOR_CHANGE_VOLTAGE
|
REGULATOR_CHANGE_STATUS
|
REGULATOR_CHANGE_MODE
,
.
valid_modes_mask
=
REGULATOR_MODE_NORMAL
|
REGULATOR_MODE_IDLE
,
},
.
num_consumer_supplies
=
ARRAY_SIZE
(
ab8500_vaux2_consumers
),
.
consumer_supplies
=
ab8500_vaux2_consumers
,
},
/* supply for VAUX3, supplies to SDcard slots */
[
AB8500_LDO_AUX3
]
=
{
.
supply_regulator
=
"ab8500-ext-supply3"
,
.
constraints
=
{
.
name
=
"V-MMC-SD"
,
.
min_uV
=
1100000
,
.
max_uV
=
3300000
,
.
valid_ops_mask
=
REGULATOR_CHANGE_VOLTAGE
|
REGULATOR_CHANGE_STATUS
|
REGULATOR_CHANGE_MODE
,
.
valid_modes_mask
=
REGULATOR_MODE_NORMAL
|
REGULATOR_MODE_IDLE
,
},
.
num_consumer_supplies
=
ARRAY_SIZE
(
ab8500_vaux3_consumers
),
.
consumer_supplies
=
ab8500_vaux3_consumers
,
},
/* supply for tvout, gpadc, TVOUT LDO */
[
AB8500_LDO_TVOUT
]
=
{
.
constraints
=
{
.
name
=
"V-TVOUT"
,
.
valid_ops_mask
=
REGULATOR_CHANGE_STATUS
,
},
.
num_consumer_supplies
=
ARRAY_SIZE
(
ab8500_vtvout_consumers
),
.
consumer_supplies
=
ab8500_vtvout_consumers
,
},
/* supply for ab8500-vaudio, VAUDIO LDO */
[
AB8500_LDO_AUDIO
]
=
{
.
constraints
=
{
.
name
=
"V-AUD"
,
.
valid_ops_mask
=
REGULATOR_CHANGE_STATUS
,
},
.
num_consumer_supplies
=
ARRAY_SIZE
(
ab8500_vaud_consumers
),
.
consumer_supplies
=
ab8500_vaud_consumers
,
},
/* supply for v-anamic1 VAMic1-LDO */
[
AB8500_LDO_ANAMIC1
]
=
{
.
constraints
=
{
.
name
=
"V-AMIC1"
,
.
valid_ops_mask
=
REGULATOR_CHANGE_STATUS
,
},
.
num_consumer_supplies
=
ARRAY_SIZE
(
ab8500_vamic1_consumers
),
.
consumer_supplies
=
ab8500_vamic1_consumers
,
},
/* supply for v-amic2, VAMIC2 LDO, reuse constants for AMIC1 */
[
AB8500_LDO_ANAMIC2
]
=
{
.
constraints
=
{
.
name
=
"V-AMIC2"
,
.
valid_ops_mask
=
REGULATOR_CHANGE_STATUS
,
},
.
num_consumer_supplies
=
ARRAY_SIZE
(
ab8500_vamic2_consumers
),
.
consumer_supplies
=
ab8500_vamic2_consumers
,
},
/* supply for v-dmic, VDMIC LDO */
[
AB8500_LDO_DMIC
]
=
{
.
constraints
=
{
.
name
=
"V-DMIC"
,
.
valid_ops_mask
=
REGULATOR_CHANGE_STATUS
,
},
.
num_consumer_supplies
=
ARRAY_SIZE
(
ab8500_vdmic_consumers
),
.
consumer_supplies
=
ab8500_vdmic_consumers
,
},
/* supply for v-intcore12, VINTCORE12 LDO */
[
AB8500_LDO_INTCORE
]
=
{
.
constraints
=
{
.
name
=
"V-INTCORE"
,
.
min_uV
=
1250000
,
.
max_uV
=
1350000
,
.
input_uV
=
1800000
,
.
valid_ops_mask
=
REGULATOR_CHANGE_VOLTAGE
|
REGULATOR_CHANGE_STATUS
|
REGULATOR_CHANGE_MODE
|
REGULATOR_CHANGE_DRMS
,
.
valid_modes_mask
=
REGULATOR_MODE_NORMAL
|
REGULATOR_MODE_IDLE
,
},
.
num_consumer_supplies
=
ARRAY_SIZE
(
ab8500_vintcore_consumers
),
.
consumer_supplies
=
ab8500_vintcore_consumers
,
},
/* supply for U8500 CSI-DSI, VANA LDO */
[
AB8500_LDO_ANA
]
=
{
.
constraints
=
{
.
name
=
"V-CSI-DSI"
,
.
valid_ops_mask
=
REGULATOR_CHANGE_STATUS
,
},
.
num_consumer_supplies
=
ARRAY_SIZE
(
ab8500_vana_consumers
),
.
consumer_supplies
=
ab8500_vana_consumers
,
},
struct
ab8500_ext_regulator_cfg
{
bool
hwreq
;
/* requires hw mode or high power mode */
};
/* supply for VextSupply3 */
...
...
@@ -465,15 +79,6 @@ static struct regulator_init_data ab8500_ext_regulators[] = {
},
};
static
struct
ab8500_regulator_platform_data
ab8500_regulator_plat_data
=
{
.
reg_init
=
ab8500_reg_init
,
.
num_reg_init
=
ARRAY_SIZE
(
ab8500_reg_init
),
.
regulator
=
ab8500_regulators
,
.
num_regulator
=
ARRAY_SIZE
(
ab8500_regulators
),
.
ext_regulator
=
ab8500_ext_regulators
,
.
num_ext_regulator
=
ARRAY_SIZE
(
ab8500_ext_regulators
),
};
/**
* struct ab8500_ext_regulator_info - ab8500 regulator information
* @dev: device pointer
...
...
@@ -788,7 +393,6 @@ static struct ab8500_ext_regulator_info
static
int
ab8500_ext_regulator_probe
(
struct
platform_device
*
pdev
)
{
struct
ab8500
*
ab8500
=
dev_get_drvdata
(
pdev
->
dev
.
parent
);
struct
ab8500_regulator_platform_data
*
pdata
=
&
ab8500_regulator_plat_data
;
struct
regulator_config
config
=
{
};
struct
regulator_dev
*
rdev
;
int
i
;
...
...
@@ -798,12 +402,6 @@ static int ab8500_ext_regulator_probe(struct platform_device *pdev)
return
-
EINVAL
;
}
/* make sure the platform data has the correct size */
if
(
pdata
->
num_ext_regulator
!=
ARRAY_SIZE
(
ab8500_ext_regulator_info
))
{
dev_err
(
&
pdev
->
dev
,
"Configuration error: size mismatch.
\n
"
);
return
-
EINVAL
;
}
/* check for AB8500 2.x */
if
(
is_ab8500_2p0_or_earlier
(
ab8500
))
{
struct
ab8500_ext_regulator_info
*
info
;
...
...
@@ -823,11 +421,11 @@ static int ab8500_ext_regulator_probe(struct platform_device *pdev)
info
=
&
ab8500_ext_regulator_info
[
i
];
info
->
dev
=
&
pdev
->
dev
;
info
->
cfg
=
(
struct
ab8500_ext_regulator_cfg
*
)
pdata
->
ext_regulator
[
i
].
driver_data
;
ab8500_ext_regulators
[
i
].
driver_data
;
config
.
dev
=
&
pdev
->
dev
;
config
.
driver_data
=
info
;
config
.
init_data
=
&
pdata
->
ext_regulator
[
i
];
config
.
init_data
=
&
ab8500_ext_regulators
[
i
];
/* register regulator with framework */
rdev
=
devm_regulator_register
(
&
pdev
->
dev
,
&
info
->
desc
,
...
...
drivers/regulator/ab8500.c
View file @
f03e2a72
...
...
@@ -25,9 +25,123 @@
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/ab8500.h>
#include <linux/slab.h>
/* AB8500 regulators */
enum
ab8500_regulator_id
{
AB8500_LDO_AUX1
,
AB8500_LDO_AUX2
,
AB8500_LDO_AUX3
,
AB8500_LDO_INTCORE
,
AB8500_LDO_TVOUT
,
AB8500_LDO_AUDIO
,
AB8500_LDO_ANAMIC1
,
AB8500_LDO_ANAMIC2
,
AB8500_LDO_DMIC
,
AB8500_LDO_ANA
,
AB8500_NUM_REGULATORS
,
};
/* AB8505 regulators */
enum
ab8505_regulator_id
{
AB8505_LDO_AUX1
,
AB8505_LDO_AUX2
,
AB8505_LDO_AUX3
,
AB8505_LDO_AUX4
,
AB8505_LDO_AUX5
,
AB8505_LDO_AUX6
,
AB8505_LDO_INTCORE
,
AB8505_LDO_ADC
,
AB8505_LDO_AUDIO
,
AB8505_LDO_ANAMIC1
,
AB8505_LDO_ANAMIC2
,
AB8505_LDO_AUX8
,
AB8505_LDO_ANA
,
AB8505_NUM_REGULATORS
,
};
/* AB8500 registers */
enum
ab8500_regulator_reg
{
AB8500_REGUREQUESTCTRL2
,
AB8500_REGUREQUESTCTRL3
,
AB8500_REGUREQUESTCTRL4
,
AB8500_REGUSYSCLKREQ1HPVALID1
,
AB8500_REGUSYSCLKREQ1HPVALID2
,
AB8500_REGUHWHPREQ1VALID1
,
AB8500_REGUHWHPREQ1VALID2
,
AB8500_REGUHWHPREQ2VALID1
,
AB8500_REGUHWHPREQ2VALID2
,
AB8500_REGUSWHPREQVALID1
,
AB8500_REGUSWHPREQVALID2
,
AB8500_REGUSYSCLKREQVALID1
,
AB8500_REGUSYSCLKREQVALID2
,
AB8500_REGUMISC1
,
AB8500_VAUDIOSUPPLY
,
AB8500_REGUCTRL1VAMIC
,
AB8500_VPLLVANAREGU
,
AB8500_VREFDDR
,
AB8500_EXTSUPPLYREGU
,
AB8500_VAUX12REGU
,
AB8500_VRF1VAUX3REGU
,
AB8500_VAUX1SEL
,
AB8500_VAUX2SEL
,
AB8500_VRF1VAUX3SEL
,
AB8500_REGUCTRL2SPARE
,
AB8500_REGUCTRLDISCH
,
AB8500_REGUCTRLDISCH2
,
AB8500_NUM_REGULATOR_REGISTERS
,
};
/* AB8505 registers */
enum
ab8505_regulator_reg
{
AB8505_REGUREQUESTCTRL1
,
AB8505_REGUREQUESTCTRL2
,
AB8505_REGUREQUESTCTRL3
,
AB8505_REGUREQUESTCTRL4
,
AB8505_REGUSYSCLKREQ1HPVALID1
,
AB8505_REGUSYSCLKREQ1HPVALID2
,
AB8505_REGUHWHPREQ1VALID1
,
AB8505_REGUHWHPREQ1VALID2
,
AB8505_REGUHWHPREQ2VALID1
,
AB8505_REGUHWHPREQ2VALID2
,
AB8505_REGUSWHPREQVALID1
,
AB8505_REGUSWHPREQVALID2
,
AB8505_REGUSYSCLKREQVALID1
,
AB8505_REGUSYSCLKREQVALID2
,
AB8505_REGUVAUX4REQVALID
,
AB8505_REGUMISC1
,
AB8505_VAUDIOSUPPLY
,
AB8505_REGUCTRL1VAMIC
,
AB8505_VSMPSAREGU
,
AB8505_VSMPSBREGU
,
AB8505_VSAFEREGU
,
/* NOTE! PRCMU register */
AB8505_VPLLVANAREGU
,
AB8505_EXTSUPPLYREGU
,
AB8505_VAUX12REGU
,
AB8505_VRF1VAUX3REGU
,
AB8505_VSMPSASEL1
,
AB8505_VSMPSASEL2
,
AB8505_VSMPSASEL3
,
AB8505_VSMPSBSEL1
,
AB8505_VSMPSBSEL2
,
AB8505_VSMPSBSEL3
,
AB8505_VSAFESEL1
,
/* NOTE! PRCMU register */
AB8505_VSAFESEL2
,
/* NOTE! PRCMU register */
AB8505_VSAFESEL3
,
/* NOTE! PRCMU register */
AB8505_VAUX1SEL
,
AB8505_VAUX2SEL
,
AB8505_VRF1VAUX3SEL
,
AB8505_VAUX4REQCTRL
,
AB8505_VAUX4REGU
,
AB8505_VAUX4SEL
,
AB8505_REGUCTRLDISCH
,
AB8505_REGUCTRLDISCH2
,
AB8505_REGUCTRLDISCH3
,
AB8505_CTRLVAUX5
,
AB8505_CTRLVAUX6
,
AB8505_NUM_REGULATOR_REGISTERS
,
};
/**
* struct ab8500_shared_mode - is used when mode is shared between
* two regulators.
...
...
drivers/regulator/atc260x-regulator.c
0 → 100644
View file @
f03e2a72
// SPDX-License-Identifier: GPL-2.0+
//
// Regulator driver for ATC260x PMICs
//
// Copyright (C) 2019 Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
// Copyright (C) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
#include <linux/mfd/atc260x/core.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
struct
atc260x_regulator_data
{
int
voltage_time_dcdc
;
int
voltage_time_ldo
;
};
static
const
struct
linear_range
atc2603c_dcdc_voltage_ranges
[]
=
{
REGULATOR_LINEAR_RANGE
(
1300000
,
0
,
13
,
50000
),
REGULATOR_LINEAR_RANGE
(
1950000
,
14
,
15
,
100000
),
};
static
const
struct
linear_range
atc2609a_dcdc_voltage_ranges
[]
=
{
REGULATOR_LINEAR_RANGE
(
600000
,
0
,
127
,
6250
),
REGULATOR_LINEAR_RANGE
(
1400000
,
128
,
232
,
25000
),
};
static
const
struct
linear_range
atc2609a_ldo_voltage_ranges0
[]
=
{
REGULATOR_LINEAR_RANGE
(
700000
,
0
,
15
,
100000
),
REGULATOR_LINEAR_RANGE
(
2100000
,
16
,
28
,
100000
),
};
static
const
struct
linear_range
atc2609a_ldo_voltage_ranges1
[]
=
{
REGULATOR_LINEAR_RANGE
(
850000
,
0
,
15
,
100000
),
REGULATOR_LINEAR_RANGE
(
2100000
,
16
,
27
,
100000
),
};
static
const
unsigned
int
atc260x_ldo_voltage_range_sel
[]
=
{
0x0
,
0x1
,
};
static
int
atc260x_dcdc_set_voltage_time_sel
(
struct
regulator_dev
*
rdev
,
unsigned
int
old_selector
,
unsigned
int
new_selector
)
{
struct
atc260x_regulator_data
*
data
=
rdev_get_drvdata
(
rdev
);
if
(
new_selector
>
old_selector
)
return
data
->
voltage_time_dcdc
;
return
0
;
}
static
int
atc260x_ldo_set_voltage_time_sel
(
struct
regulator_dev
*
rdev
,
unsigned
int
old_selector
,
unsigned
int
new_selector
)
{
struct
atc260x_regulator_data
*
data
=
rdev_get_drvdata
(
rdev
);
if
(
new_selector
>
old_selector
)
return
data
->
voltage_time_ldo
;
return
0
;
}
static
const
struct
regulator_ops
atc260x_dcdc_ops
=
{
.
enable
=
regulator_enable_regmap
,
.
disable
=
regulator_disable_regmap
,
.
is_enabled
=
regulator_is_enabled_regmap
,
.
list_voltage
=
regulator_list_voltage_linear
,
.
set_voltage_sel
=
regulator_set_voltage_sel_regmap
,
.
get_voltage_sel
=
regulator_get_voltage_sel_regmap
,
.
set_voltage_time_sel
=
atc260x_dcdc_set_voltage_time_sel
,
};
static
const
struct
regulator_ops
atc260x_ldo_ops
=
{
.
enable
=
regulator_enable_regmap
,
.
disable
=
regulator_disable_regmap
,
.
is_enabled
=
regulator_is_enabled_regmap
,
.
list_voltage
=
regulator_list_voltage_linear
,
.
set_voltage_sel
=
regulator_set_voltage_sel_regmap
,
.
get_voltage_sel
=
regulator_get_voltage_sel_regmap
,
.
set_voltage_time_sel
=
atc260x_ldo_set_voltage_time_sel
,
};
static
const
struct
regulator_ops
atc260x_ldo_bypass_ops
=
{
.
enable
=
regulator_enable_regmap
,
.
disable
=
regulator_disable_regmap
,
.
is_enabled
=
regulator_is_enabled_regmap
,
.
list_voltage
=
regulator_list_voltage_linear
,
.
set_voltage_sel
=
regulator_set_voltage_sel_regmap
,
.
get_voltage_sel
=
regulator_get_voltage_sel_regmap
,
.
set_voltage_time_sel
=
atc260x_ldo_set_voltage_time_sel
,
.
set_bypass
=
regulator_set_bypass_regmap
,
.
get_bypass
=
regulator_get_bypass_regmap
,
};
static
const
struct
regulator_ops
atc260x_ldo_bypass_discharge_ops
=
{
.
enable
=
regulator_enable_regmap
,
.
disable
=
regulator_disable_regmap
,
.
is_enabled
=
regulator_is_enabled_regmap
,
.
list_voltage
=
regulator_list_voltage_linear
,
.
set_voltage_sel
=
regulator_set_voltage_sel_regmap
,
.
get_voltage_sel
=
regulator_get_voltage_sel_regmap
,
.
set_voltage_time_sel
=
atc260x_ldo_set_voltage_time_sel
,
.
set_bypass
=
regulator_set_bypass_regmap
,
.
get_bypass
=
regulator_get_bypass_regmap
,
.
set_active_discharge
=
regulator_set_active_discharge_regmap
,
};
static
const
struct
regulator_ops
atc260x_dcdc_range_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
=
atc260x_dcdc_set_voltage_time_sel
,
};
static
const
struct
regulator_ops
atc260x_ldo_range_pick_ops
=
{
.
enable
=
regulator_enable_regmap
,
.
disable
=
regulator_disable_regmap
,
.
is_enabled
=
regulator_is_enabled_regmap
,
.
list_voltage
=
regulator_list_voltage_pickable_linear_range
,
.
set_voltage_sel
=
regulator_set_voltage_sel_pickable_regmap
,
.
get_voltage_sel
=
regulator_get_voltage_sel_pickable_regmap
,
.
set_voltage_time_sel
=
atc260x_ldo_set_voltage_time_sel
,
};
static
const
struct
regulator_ops
atc260x_dcdc_fixed_ops
=
{
.
list_voltage
=
regulator_list_voltage_linear
,
.
set_voltage_sel
=
regulator_set_voltage_sel_regmap
,
.
get_voltage_sel
=
regulator_get_voltage_sel_regmap
,
.
set_voltage_time_sel
=
atc260x_dcdc_set_voltage_time_sel
,
};
static
const
struct
regulator_ops
atc260x_ldo_fixed_ops
=
{
.
list_voltage
=
regulator_list_voltage_linear
,
.
set_voltage_sel
=
regulator_set_voltage_sel_regmap
,
.
get_voltage_sel
=
regulator_get_voltage_sel_regmap
,
.
set_voltage_time_sel
=
atc260x_ldo_set_voltage_time_sel
,
};
static
const
struct
regulator_ops
atc260x_no_ops
=
{
};
/*
* Note LDO8 is not documented in datasheet (v2.4), but supported
* in the vendor's driver implementation (xapp-le-kernel).
*/
enum
atc2603c_reg_ids
{
ATC2603C_ID_DCDC1
,
ATC2603C_ID_DCDC2
,
ATC2603C_ID_DCDC3
,
ATC2603C_ID_LDO1
,
ATC2603C_ID_LDO2
,
ATC2603C_ID_LDO3
,
ATC2603C_ID_LDO5
,
ATC2603C_ID_LDO6
,
ATC2603C_ID_LDO7
,
ATC2603C_ID_LDO8
,
ATC2603C_ID_LDO11
,
ATC2603C_ID_LDO12
,
ATC2603C_ID_SWITCHLDO1
,
ATC2603C_ID_MAX
,
};
#define atc2603c_reg_desc_dcdc(num, min, step, n_volt, vsel_h, vsel_l) { \
.name = "DCDC"#num, \
.supply_name = "dcdc"#num, \
.of_match = of_match_ptr("dcdc"#num), \
.regulators_node = of_match_ptr("regulators"), \
.id = ATC2603C_ID_DCDC##num, \
.ops = &atc260x_dcdc_ops, \
.type = REGULATOR_VOLTAGE, \
.min_uV = min, \
.uV_step = step, \
.n_voltages = n_volt, \
.vsel_reg = ATC2603C_PMU_DC##num##_CTL0, \
.vsel_mask = GENMASK(vsel_h, vsel_l), \
.enable_reg = ATC2603C_PMU_DC##num##_CTL0, \
.enable_mask = BIT(15), \
.enable_time = 800, \
.owner = THIS_MODULE, \
}
#define atc2603c_reg_desc_dcdc_range(num, vsel_h, vsel_l) { \
.name = "DCDC"#num, \
.supply_name = "dcdc"#num, \
.of_match = of_match_ptr("dcdc"#num), \
.regulators_node = of_match_ptr("regulators"), \
.id = ATC2603C_ID_DCDC##num, \
.ops = &atc260x_dcdc_range_ops, \
.type = REGULATOR_VOLTAGE, \
.n_voltages = 16, \
.linear_ranges = atc2603c_dcdc_voltage_ranges, \
.n_linear_ranges = ARRAY_SIZE(atc2603c_dcdc_voltage_ranges), \
.vsel_reg = ATC2603C_PMU_DC##num##_CTL0, \
.vsel_mask = GENMASK(vsel_h, vsel_l), \
.enable_reg = ATC2603C_PMU_DC##num##_CTL0, \
.enable_mask = BIT(15), \
.enable_time = 800, \
.owner = THIS_MODULE, \
}
#define atc2603c_reg_desc_dcdc_fixed(num, min, step, n_volt, vsel_h, vsel_l) { \
.name = "DCDC"#num, \
.supply_name = "dcdc"#num, \
.of_match = of_match_ptr("dcdc"#num), \
.regulators_node = of_match_ptr("regulators"), \
.id = ATC2603C_ID_DCDC##num, \
.ops = &atc260x_dcdc_fixed_ops, \
.type = REGULATOR_VOLTAGE, \
.min_uV = min, \
.uV_step = step, \
.n_voltages = n_volt, \
.vsel_reg = ATC2603C_PMU_DC##num##_CTL0, \
.vsel_mask = GENMASK(vsel_h, vsel_l), \
.enable_time = 800, \
.owner = THIS_MODULE, \
}
#define atc2603c_reg_desc_ldo(num, min, step, n_volt, vsel_h, vsel_l) { \
.name = "LDO"#num, \
.supply_name = "ldo"#num, \
.of_match = of_match_ptr("ldo"#num), \
.regulators_node = of_match_ptr("regulators"), \
.id = ATC2603C_ID_LDO##num, \
.ops = &atc260x_ldo_ops, \
.type = REGULATOR_VOLTAGE, \
.min_uV = min, \
.uV_step = step, \
.n_voltages = n_volt, \
.vsel_reg = ATC2603C_PMU_LDO##num##_CTL, \
.vsel_mask = GENMASK(vsel_h, vsel_l), \
.enable_reg = ATC2603C_PMU_LDO##num##_CTL, \
.enable_mask = BIT(0), \
.enable_time = 2000, \
.owner = THIS_MODULE, \
}
#define atc2603c_reg_desc_ldo_fixed(num, min, step, n_volt, vsel_h, vsel_l) { \
.name = "LDO"#num, \
.supply_name = "ldo"#num, \
.of_match = of_match_ptr("ldo"#num), \
.regulators_node = of_match_ptr("regulators"), \
.id = ATC2603C_ID_LDO##num, \
.ops = &atc260x_ldo_fixed_ops, \
.type = REGULATOR_VOLTAGE, \
.min_uV = min, \
.uV_step = step, \
.n_voltages = n_volt, \
.vsel_reg = ATC2603C_PMU_LDO##num##_CTL, \
.vsel_mask = GENMASK(vsel_h, vsel_l), \
.enable_time = 2000, \
.owner = THIS_MODULE, \
}
#define atc2603c_reg_desc_ldo_noops(num, vfixed) { \
.name = "LDO"#num, \
.supply_name = "ldo"#num, \
.of_match = of_match_ptr("ldo"#num), \
.regulators_node = of_match_ptr("regulators"), \
.id = ATC2603C_ID_LDO##num, \
.ops = &atc260x_no_ops, \
.type = REGULATOR_VOLTAGE, \
.fixed_uV = vfixed, \
.n_voltages = 1, \
.owner = THIS_MODULE, \
}
#define atc2603c_reg_desc_ldo_switch(num, min, step, n_volt, vsel_h, vsel_l) { \
.name = "SWITCHLDO"#num, \
.supply_name = "switchldo"#num, \
.of_match = of_match_ptr("switchldo"#num), \
.regulators_node = of_match_ptr("regulators"), \
.id = ATC2603C_ID_SWITCHLDO##num, \
.ops = &atc260x_ldo_bypass_discharge_ops, \
.type = REGULATOR_VOLTAGE, \
.min_uV = min, \
.uV_step = step, \
.n_voltages = n_volt, \
.vsel_reg = ATC2603C_PMU_SWITCH_CTL, \
.vsel_mask = GENMASK(vsel_h, vsel_l), \
.enable_reg = ATC2603C_PMU_SWITCH_CTL, \
.enable_mask = BIT(15), \
.enable_is_inverted = true, \
.enable_time = 2000, \
.bypass_reg = ATC2603C_PMU_SWITCH_CTL, \
.bypass_mask = BIT(5), \
.active_discharge_reg = ATC2603C_PMU_SWITCH_CTL, \
.active_discharge_mask = BIT(1), \
.owner = THIS_MODULE, \
}
static
const
struct
regulator_desc
atc2603c_reg
[]
=
{
atc2603c_reg_desc_dcdc_fixed
(
1
,
700000
,
25000
,
29
,
11
,
7
),
atc2603c_reg_desc_dcdc_range
(
2
,
12
,
8
),
atc2603c_reg_desc_dcdc_fixed
(
3
,
2600000
,
100000
,
8
,
11
,
9
),
atc2603c_reg_desc_ldo_fixed
(
1
,
2600000
,
100000
,
8
,
15
,
13
),
atc2603c_reg_desc_ldo_fixed
(
2
,
2600000
,
100000
,
8
,
15
,
13
),
atc2603c_reg_desc_ldo_fixed
(
3
,
1500000
,
100000
,
6
,
15
,
13
),
atc2603c_reg_desc_ldo
(
5
,
2600000
,
100000
,
8
,
15
,
13
),
atc2603c_reg_desc_ldo_fixed
(
6
,
700000
,
25000
,
29
,
15
,
11
),
atc2603c_reg_desc_ldo
(
7
,
1500000
,
100000
,
6
,
15
,
13
),
atc2603c_reg_desc_ldo
(
8
,
2300000
,
100000
,
11
,
15
,
12
),
atc2603c_reg_desc_ldo_fixed
(
11
,
2600000
,
100000
,
8
,
15
,
13
),
atc2603c_reg_desc_ldo_noops
(
12
,
1800000
),
atc2603c_reg_desc_ldo_switch
(
1
,
3000000
,
100000
,
4
,
4
,
3
),
};
static
const
struct
regulator_desc
atc2603c_reg_dcdc2_ver_b
=
atc2603c_reg_desc_dcdc
(
2
,
1000000
,
50000
,
18
,
12
,
8
);
enum
atc2609a_reg_ids
{
ATC2609A_ID_DCDC0
,
ATC2609A_ID_DCDC1
,
ATC2609A_ID_DCDC2
,
ATC2609A_ID_DCDC3
,
ATC2609A_ID_DCDC4
,
ATC2609A_ID_LDO0
,
ATC2609A_ID_LDO1
,
ATC2609A_ID_LDO2
,
ATC2609A_ID_LDO3
,
ATC2609A_ID_LDO4
,
ATC2609A_ID_LDO5
,
ATC2609A_ID_LDO6
,
ATC2609A_ID_LDO7
,
ATC2609A_ID_LDO8
,
ATC2609A_ID_LDO9
,
ATC2609A_ID_MAX
,
};
#define atc2609a_reg_desc_dcdc(num, en_bit) { \
.name = "DCDC"#num, \
.supply_name = "dcdc"#num, \
.of_match = of_match_ptr("dcdc"#num), \
.regulators_node = of_match_ptr("regulators"), \
.id = ATC2609A_ID_DCDC##num, \
.ops = &atc260x_dcdc_ops, \
.type = REGULATOR_VOLTAGE, \
.min_uV = 600000, \
.uV_step = 6250, \
.n_voltages = 256, \
.vsel_reg = ATC2609A_PMU_DC##num##_CTL0, \
.vsel_mask = GENMASK(15, 8), \
.enable_reg = ATC2609A_PMU_DC_OSC, \
.enable_mask = BIT(en_bit), \
.enable_time = 800, \
.owner = THIS_MODULE, \
}
#define atc2609a_reg_desc_dcdc_range(num, en_bit) { \
.name = "DCDC"#num, \
.supply_name = "dcdc"#num, \
.of_match = of_match_ptr("dcdc"#num), \
.regulators_node = of_match_ptr("regulators"), \
.id = ATC2609A_ID_DCDC##num, \
.ops = &atc260x_dcdc_range_ops, \
.type = REGULATOR_VOLTAGE, \
.n_voltages = 233, \
.linear_ranges = atc2609a_dcdc_voltage_ranges, \
.n_linear_ranges = ARRAY_SIZE(atc2609a_dcdc_voltage_ranges), \
.vsel_reg = ATC2609A_PMU_DC##num##_CTL0, \
.vsel_mask = GENMASK(15, 8), \
.enable_reg = ATC2609A_PMU_DC_OSC, \
.enable_mask = BIT(en_bit), \
.enable_time = 800, \
.owner = THIS_MODULE, \
}
#define atc2609a_reg_desc_ldo(num) { \
.name = "LDO"#num, \
.supply_name = "ldo"#num, \
.of_match = of_match_ptr("ldo"#num), \
.regulators_node = of_match_ptr("regulators"), \
.id = ATC2609A_ID_LDO##num, \
.ops = &atc260x_ldo_ops, \
.type = REGULATOR_VOLTAGE, \
.min_uV = 700000, \
.uV_step = 100000, \
.n_voltages = 16, \
.vsel_reg = ATC2609A_PMU_LDO##num##_CTL0, \
.vsel_mask = GENMASK(4, 1), \
.enable_reg = ATC2609A_PMU_LDO##num##_CTL0, \
.enable_mask = BIT(0), \
.enable_time = 2000, \
.owner = THIS_MODULE, \
}
#define atc2609a_reg_desc_ldo_bypass(num) { \
.name = "LDO"#num, \
.supply_name = "ldo"#num, \
.of_match = of_match_ptr("ldo"#num), \
.regulators_node = of_match_ptr("regulators"), \
.id = ATC2609A_ID_LDO##num, \
.ops = &atc260x_ldo_bypass_ops, \
.type = REGULATOR_VOLTAGE, \
.min_uV = 2300000, \
.uV_step = 100000, \
.n_voltages = 12, \
.vsel_reg = ATC2609A_PMU_LDO##num##_CTL0, \
.vsel_mask = GENMASK(5, 2), \
.enable_reg = ATC2609A_PMU_LDO##num##_CTL0, \
.enable_mask = BIT(0), \
.enable_time = 2000, \
.bypass_reg = ATC2609A_PMU_LDO##num##_CTL0, \
.bypass_mask = BIT(1), \
.owner = THIS_MODULE, \
}
#define atc2609a_reg_desc_ldo_range_pick(num, n_range) { \
.name = "LDO"#num, \
.supply_name = "ldo"#num, \
.of_match = of_match_ptr("ldo"#num), \
.regulators_node = of_match_ptr("regulators"), \
.id = ATC2609A_ID_LDO##num, \
.ops = &atc260x_ldo_range_pick_ops, \
.type = REGULATOR_VOLTAGE, \
.linear_ranges = atc2609a_ldo_voltage_ranges##n_range, \
.n_linear_ranges = ARRAY_SIZE(atc2609a_ldo_voltage_ranges##n_range), \
.vsel_reg = ATC2609A_PMU_LDO##num##_CTL0, \
.vsel_mask = GENMASK(4, 1), \
.vsel_range_reg = ATC2609A_PMU_LDO##num##_CTL0, \
.vsel_range_mask = BIT(5), \
.linear_range_selectors = atc260x_ldo_voltage_range_sel, \
.enable_reg = ATC2609A_PMU_LDO##num##_CTL0, \
.enable_mask = BIT(0), \
.enable_time = 2000, \
.owner = THIS_MODULE, \
}
#define atc2609a_reg_desc_ldo_fixed(num) { \
.name = "LDO"#num, \
.supply_name = "ldo"#num, \
.of_match = of_match_ptr("ldo"#num), \
.regulators_node = of_match_ptr("regulators"), \
.id = ATC2609A_ID_LDO##num, \
.ops = &atc260x_ldo_fixed_ops, \
.type = REGULATOR_VOLTAGE, \
.min_uV = 2600000, \
.uV_step = 100000, \
.n_voltages = 8, \
.vsel_reg = ATC2609A_PMU_LDO##num##_CTL, \
.vsel_mask = GENMASK(15, 13), \
.enable_time = 2000, \
.owner = THIS_MODULE, \
}
static
const
struct
regulator_desc
atc2609a_reg
[]
=
{
atc2609a_reg_desc_dcdc
(
0
,
4
),
atc2609a_reg_desc_dcdc
(
1
,
5
),
atc2609a_reg_desc_dcdc
(
2
,
6
),
atc2609a_reg_desc_dcdc_range
(
3
,
7
),
atc2609a_reg_desc_dcdc
(
4
,
8
),
atc2609a_reg_desc_ldo_bypass
(
0
),
atc2609a_reg_desc_ldo_bypass
(
1
),
atc2609a_reg_desc_ldo_bypass
(
2
),
atc2609a_reg_desc_ldo_range_pick
(
3
,
0
),
atc2609a_reg_desc_ldo_range_pick
(
4
,
0
),
atc2609a_reg_desc_ldo
(
5
),
atc2609a_reg_desc_ldo_range_pick
(
6
,
1
),
atc2609a_reg_desc_ldo_range_pick
(
7
,
0
),
atc2609a_reg_desc_ldo_range_pick
(
8
,
0
),
atc2609a_reg_desc_ldo_fixed
(
9
),
};
static
int
atc260x_regulator_probe
(
struct
platform_device
*
pdev
)
{
struct
atc260x
*
atc260x
=
dev_get_drvdata
(
pdev
->
dev
.
parent
);
struct
device
*
dev
=
atc260x
->
dev
;
struct
atc260x_regulator_data
*
atc260x_data
;
struct
regulator_config
config
=
{};
struct
regulator_dev
*
atc260x_rdev
;
const
struct
regulator_desc
*
regulators
;
bool
atc2603c_ver_b
=
false
;
int
i
,
nregulators
;
atc260x_data
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
atc260x_data
),
GFP_KERNEL
);
if
(
!
atc260x_data
)
return
-
ENOMEM
;
atc260x_data
->
voltage_time_dcdc
=
350
;
atc260x_data
->
voltage_time_ldo
=
800
;
switch
(
atc260x
->
ic_type
)
{
case
ATC2603C
:
regulators
=
atc2603c_reg
;
nregulators
=
ATC2603C_ID_MAX
;
atc2603c_ver_b
=
atc260x
->
ic_ver
==
ATC260X_B
;
break
;
case
ATC2609A
:
atc260x_data
->
voltage_time_dcdc
=
250
;
regulators
=
atc2609a_reg
;
nregulators
=
ATC2609A_ID_MAX
;
break
;
default:
dev_err
(
dev
,
"unsupported ATC260X ID %d
\n
"
,
atc260x
->
ic_type
);
return
-
EINVAL
;
}
config
.
dev
=
dev
;
config
.
regmap
=
atc260x
->
regmap
;
config
.
driver_data
=
atc260x_data
;
/* Instantiate the regulators */
for
(
i
=
0
;
i
<
nregulators
;
i
++
)
{
if
(
atc2603c_ver_b
&&
regulators
[
i
].
id
==
ATC2603C_ID_DCDC2
)
atc260x_rdev
=
devm_regulator_register
(
&
pdev
->
dev
,
&
atc2603c_reg_dcdc2_ver_b
,
&
config
);
else
atc260x_rdev
=
devm_regulator_register
(
&
pdev
->
dev
,
&
regulators
[
i
],
&
config
);
if
(
IS_ERR
(
atc260x_rdev
))
{
dev_err
(
dev
,
"failed to register regulator: %d
\n
"
,
i
);
return
PTR_ERR
(
atc260x_rdev
);
}
}
return
0
;
}
static
struct
platform_driver
atc260x_regulator_driver
=
{
.
probe
=
atc260x_regulator_probe
,
.
driver
=
{
.
name
=
"atc260x-regulator"
,
},
};
module_platform_driver
(
atc260x_regulator_driver
);
MODULE_DESCRIPTION
(
"Regulator driver for ATC260x PMICs"
);
MODULE_AUTHOR
(
"Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>"
);
MODULE_AUTHOR
(
"Cristian Ciocaltea <cristian.ciocaltea@gmail.com>"
);
MODULE_LICENSE
(
"GPL"
);
drivers/regulator/axp20x-regulator.c
View file @
f03e2a72
...
...
@@ -1070,7 +1070,7 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
static
int
axp20x_regulator_parse_dt
(
struct
platform_device
*
pdev
)
{
struct
device_node
*
np
,
*
regulators
;
int
ret
;
int
ret
=
0
;
u32
dcdcfreq
=
0
;
np
=
of_node_get
(
pdev
->
dev
.
parent
->
of_node
);
...
...
@@ -1085,13 +1085,12 @@ static int axp20x_regulator_parse_dt(struct platform_device *pdev)
ret
=
axp20x_set_dcdc_freq
(
pdev
,
dcdcfreq
);
if
(
ret
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"Error setting dcdc frequency: %d
\n
"
,
ret
);
return
ret
;
}
of_node_put
(
regulators
);
}
return
0
;
of_node_put
(
np
);
return
ret
;
}
static
int
axp20x_set_dcdc_workmode
(
struct
regulator_dev
*
rdev
,
int
id
,
u32
workmode
)
...
...
drivers/regulator/bd70528-regulator.c
View file @
f03e2a72
...
...
@@ -244,19 +244,14 @@ static const struct regulator_desc bd70528_desc[] = {
static
int
bd70528_probe
(
struct
platform_device
*
pdev
)
{
struct
rohm_regmap_dev
*
bd70528
;
int
i
;
struct
regulator_config
config
=
{
.
dev
=
pdev
->
dev
.
parent
,
};
bd70528
=
dev_get_drvdata
(
pdev
->
dev
.
parent
);
if
(
!
bd70528
)
{
dev_err
(
&
pdev
->
dev
,
"No MFD driver data
\n
"
);
return
-
EINVAL
;
}
config
.
regmap
=
bd70528
->
regmap
;
config
.
regmap
=
dev_get_regmap
(
pdev
->
dev
.
parent
,
NULL
);
if
(
!
config
.
regmap
)
return
-
ENODEV
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
bd70528_desc
);
i
++
)
{
struct
regulator_dev
*
rdev
;
...
...
drivers/regulator/bd71828-regulator.c
View file @
f03e2a72
...
...
@@ -749,19 +749,14 @@ static const struct bd71828_regulator_data bd71828_rdata[] = {
static
int
bd71828_probe
(
struct
platform_device
*
pdev
)
{
struct
rohm_regmap_dev
*
bd71828
;
int
i
,
j
,
ret
;
struct
regulator_config
config
=
{
.
dev
=
pdev
->
dev
.
parent
,
};
bd71828
=
dev_get_drvdata
(
pdev
->
dev
.
parent
);
if
(
!
bd71828
)
{
dev_err
(
&
pdev
->
dev
,
"No MFD driver data
\n
"
);
return
-
EINVAL
;
}
config
.
regmap
=
bd71828
->
regmap
;
config
.
regmap
=
dev_get_regmap
(
pdev
->
dev
.
parent
,
NULL
);
if
(
!
config
.
regmap
)
return
-
ENODEV
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
bd71828_rdata
);
i
++
)
{
struct
regulator_dev
*
rdev
;
...
...
@@ -777,7 +772,7 @@ static int bd71828_probe(struct platform_device *pdev)
return
PTR_ERR
(
rdev
);
}
for
(
j
=
0
;
j
<
rd
->
reg_init_amnt
;
j
++
)
{
ret
=
regmap_update_bits
(
bd71828
->
regmap
,
ret
=
regmap_update_bits
(
config
.
regmap
,
rd
->
reg_inits
[
j
].
reg
,
rd
->
reg_inits
[
j
].
mask
,
rd
->
reg_inits
[
j
].
val
);
...
...
drivers/regulator/bd718x7-regulator.c
View file @
f03e2a72
...
...
@@ -1554,7 +1554,7 @@ static int get_special_regulators(struct device *dev,
static
int
bd718xx_probe
(
struct
platform_device
*
pdev
)
{
struct
bd718xx
*
mfd
;
struct
regmap
*
regmap
;
struct
regulator_config
config
=
{
0
};
int
i
,
j
,
err
,
omit_enable
;
bool
use_snvs
;
...
...
@@ -1563,11 +1563,10 @@ static int bd718xx_probe(struct platform_device *pdev)
enum
rohm_chip_type
chip
=
platform_get_device_id
(
pdev
)
->
driver_data
;
const
struct
regulator_ops
**
swops
,
**
hwops
;
mfd
=
dev_get_drvdata
(
pdev
->
dev
.
parent
);
if
(
!
mfd
)
{
regmap
=
dev_get_regmap
(
pdev
->
dev
.
parent
,
NULL
);
if
(
!
regmap
)
{
dev_err
(
&
pdev
->
dev
,
"No MFD driver data
\n
"
);
err
=
-
EINVAL
;
goto
err
;
return
-
EINVAL
;
}
switch
(
chip
)
{
...
...
@@ -1590,7 +1589,7 @@ static int bd718xx_probe(struct platform_device *pdev)
}
/* Register LOCK release */
err
=
regmap_update_bits
(
mfd
->
chip
.
regmap
,
BD718XX_REG_REGLOCK
,
err
=
regmap_update_bits
(
regmap
,
BD718XX_REG_REGLOCK
,
(
REGLOCK_PWRSEQ
|
REGLOCK_VREG
),
0
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"Failed to unlock PMIC (%d)
\n
"
,
err
);
...
...
@@ -1609,8 +1608,7 @@ static int bd718xx_probe(struct platform_device *pdev)
* bit allowing HW defaults for power rails to be used
*/
if
(
!
use_snvs
)
{
err
=
regmap_update_bits
(
mfd
->
chip
.
regmap
,
BD718XX_REG_TRANS_COND1
,
err
=
regmap_update_bits
(
regmap
,
BD718XX_REG_TRANS_COND1
,
BD718XX_ON_REQ_POWEROFF_MASK
|
BD718XX_SWRESET_POWEROFF_MASK
|
BD718XX_WDOG_POWEROFF_MASK
|
...
...
@@ -1626,7 +1624,7 @@ static int bd718xx_probe(struct platform_device *pdev)
}
config
.
dev
=
pdev
->
dev
.
parent
;
config
.
regmap
=
mfd
->
chip
.
regmap
;
config
.
regmap
=
regmap
;
/*
* There are cases when we want to leave the enable-control for
* the HW state machine and use this driver only for voltage control.
...
...
@@ -1685,7 +1683,7 @@ static int bd718xx_probe(struct platform_device *pdev)
if
(
!
no_enable_control
&&
(
!
use_snvs
||
!
rdev
->
constraints
->
always_on
||
!
rdev
->
constraints
->
boot_on
))
{
err
=
regmap_update_bits
(
mfd
->
chip
.
regmap
,
r
->
init
.
reg
,
err
=
regmap_update_bits
(
regmap
,
r
->
init
.
reg
,
r
->
init
.
mask
,
r
->
init
.
val
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
...
...
@@ -1695,7 +1693,7 @@ static int bd718xx_probe(struct platform_device *pdev)
}
}
for
(
j
=
0
;
j
<
r
->
additional_init_amnt
;
j
++
)
{
err
=
regmap_update_bits
(
mfd
->
chip
.
regmap
,
err
=
regmap_update_bits
(
regmap
,
r
->
additional_inits
[
j
].
reg
,
r
->
additional_inits
[
j
].
mask
,
r
->
additional_inits
[
j
].
val
);
...
...
drivers/regulator/core.c
View file @
f03e2a72
...
...
@@ -1617,7 +1617,7 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
const
char
*
supply_name
)
{
struct
regulator
*
regulator
;
int
err
;
int
err
=
0
;
if
(
dev
)
{
char
buf
[
REG_STR_SIZE
];
...
...
@@ -1663,8 +1663,8 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
}
}
regulator
->
debugfs
=
debugfs_create_dir
(
supply_name
,
rdev
->
debugfs
);
if
(
err
!=
-
EEXIST
)
regulator
->
debugfs
=
debugfs_create_dir
(
supply_name
,
rdev
->
debugfs
);
if
(
!
regulator
->
debugfs
)
{
rdev_dbg
(
rdev
,
"Failed to create debugfs directory
\n
"
);
}
else
{
...
...
@@ -2042,7 +2042,7 @@ struct regulator *_regulator_get(struct device *dev, const char *id,
* Returns a struct regulator corresponding to the regulator producer,
* or IS_ERR() condition containing errno.
*
* Use of supply names configured via
regulator_set
_device_supply() is
* Use of supply names configured via
set_consumer
_device_supply() is
* strongly encouraged. It is recommended that the supply name used
* should match the name used for the supply and/or the relevant
* device pins in the datasheet.
...
...
@@ -2069,7 +2069,7 @@ EXPORT_SYMBOL_GPL(regulator_get);
* regulator off for correct operation of the hardware they are
* controlling.
*
* Use of supply names configured via
regulator_set
_device_supply() is
* Use of supply names configured via
set_consumer
_device_supply() is
* strongly encouraged. It is recommended that the supply name used
* should match the name used for the supply and/or the relevant
* device pins in the datasheet.
...
...
@@ -2095,7 +2095,7 @@ EXPORT_SYMBOL_GPL(regulator_get_exclusive);
* disrupting the operation of drivers that can handle absent
* supplies.
*
* Use of supply names configured via
regulator_set
_device_supply() is
* Use of supply names configured via
set_consumer
_device_supply() is
* strongly encouraged. It is recommended that the supply name used
* should match the name used for the supply and/or the relevant
* device pins in the datasheet.
...
...
@@ -4153,7 +4153,11 @@ int regulator_sync_voltage(struct regulator *regulator)
if
(
ret
<
0
)
goto
out
;
ret
=
_regulator_do_set_voltage
(
rdev
,
min_uV
,
max_uV
);
/* balance only, if regulator is coupled */
if
(
rdev
->
coupling_desc
.
n_coupled
>
1
)
ret
=
regulator_balance_voltage
(
rdev
,
PM_SUSPEND_ON
);
else
ret
=
_regulator_do_set_voltage
(
rdev
,
min_uV
,
max_uV
);
out:
regulator_unlock
(
rdev
);
...
...
drivers/regulator/mcp16502.c
View file @
f03e2a72
...
...
@@ -550,7 +550,7 @@ static int mcp16502_probe(struct i2c_client *client,
config
.
regmap
=
rmap
;
config
.
driver_data
=
mcp
;
mcp
->
lpm
=
devm_gpiod_get
(
dev
,
"lpm"
,
GPIOD_OUT_LOW
);
mcp
->
lpm
=
devm_gpiod_get
_optional
(
dev
,
"lpm"
,
GPIOD_OUT_LOW
);
if
(
IS_ERR
(
mcp
->
lpm
))
{
dev_err
(
dev
,
"failed to get lpm pin: %ld
\n
"
,
PTR_ERR
(
mcp
->
lpm
));
return
PTR_ERR
(
mcp
->
lpm
);
...
...
drivers/regulator/mt6315-regulator.c
0 → 100644
View file @
f03e2a72
// SPDX-License-Identifier: GPL-2.0
//
// Copyright (c) 2021 MediaTek Inc.
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/mt6315-regulator.h>
#include <linux/regulator/of_regulator.h>
#include <linux/spmi.h>
#define MT6315_BUCK_MODE_AUTO 0
#define MT6315_BUCK_MODE_FORCE_PWM 1
#define MT6315_BUCK_MODE_LP 2
struct
mt6315_regulator_info
{
struct
regulator_desc
desc
;
u32
status_reg
;
u32
lp_mode_mask
;
u32
lp_mode_shift
;
};
struct
mt_regulator_init_data
{
u32
modeset_mask
[
MT6315_VBUCK_MAX
];
};
struct
mt6315_chip
{
struct
device
*
dev
;
struct
regmap
*
regmap
;
};
#define MT_BUCK(_name, _bid, _vsel) \
[_bid] = { \
.desc = { \
.name = _name, \
.of_match = of_match_ptr(_name), \
.regulators_node = "regulators", \
.ops = &mt6315_volt_range_ops, \
.type = REGULATOR_VOLTAGE, \
.id = _bid, \
.owner = THIS_MODULE, \
.n_voltages = 0xbf, \
.linear_ranges = mt_volt_range1, \
.n_linear_ranges = ARRAY_SIZE(mt_volt_range1), \
.vsel_reg = _vsel, \
.vsel_mask = 0xff, \
.enable_reg = MT6315_BUCK_TOP_CON0, \
.enable_mask = BIT(_bid), \
.of_map_mode = mt6315_map_mode, \
}, \
.status_reg = _bid##_DBG4, \
.lp_mode_mask = BIT(_bid), \
.lp_mode_shift = _bid, \
}
static
const
struct
linear_range
mt_volt_range1
[]
=
{
REGULATOR_LINEAR_RANGE
(
0
,
0
,
0xbf
,
6250
),
};
static
unsigned
int
mt6315_map_mode
(
u32
mode
)
{
switch
(
mode
)
{
case
MT6315_BUCK_MODE_AUTO
:
return
REGULATOR_MODE_NORMAL
;
case
MT6315_BUCK_MODE_FORCE_PWM
:
return
REGULATOR_MODE_FAST
;
case
MT6315_BUCK_MODE_LP
:
return
REGULATOR_MODE_IDLE
;
default:
return
-
EINVAL
;
}
}
static
unsigned
int
mt6315_regulator_get_mode
(
struct
regulator_dev
*
rdev
)
{
struct
mt_regulator_init_data
*
init
=
rdev_get_drvdata
(
rdev
);
const
struct
mt6315_regulator_info
*
info
;
int
ret
,
regval
;
u32
modeset_mask
;
info
=
container_of
(
rdev
->
desc
,
struct
mt6315_regulator_info
,
desc
);
modeset_mask
=
init
->
modeset_mask
[
rdev_get_id
(
rdev
)];
ret
=
regmap_read
(
rdev
->
regmap
,
MT6315_BUCK_TOP_4PHASE_ANA_CON42
,
&
regval
);
if
(
ret
!=
0
)
{
dev_notice
(
&
rdev
->
dev
,
"Failed to get mode: %d
\n
"
,
ret
);
return
ret
;
}
if
((
regval
&
modeset_mask
)
==
modeset_mask
)
return
REGULATOR_MODE_FAST
;
ret
=
regmap_read
(
rdev
->
regmap
,
MT6315_BUCK_TOP_CON1
,
&
regval
);
if
(
ret
!=
0
)
{
dev_notice
(
&
rdev
->
dev
,
"Failed to get lp mode: %d
\n
"
,
ret
);
return
ret
;
}
if
(
regval
&
info
->
lp_mode_mask
)
return
REGULATOR_MODE_IDLE
;
else
return
REGULATOR_MODE_NORMAL
;
}
static
int
mt6315_regulator_set_mode
(
struct
regulator_dev
*
rdev
,
u32
mode
)
{
struct
mt_regulator_init_data
*
init
=
rdev_get_drvdata
(
rdev
);
const
struct
mt6315_regulator_info
*
info
;
int
ret
,
val
,
curr_mode
;
u32
modeset_mask
;
info
=
container_of
(
rdev
->
desc
,
struct
mt6315_regulator_info
,
desc
);
modeset_mask
=
init
->
modeset_mask
[
rdev_get_id
(
rdev
)];
curr_mode
=
mt6315_regulator_get_mode
(
rdev
);
switch
(
mode
)
{
case
REGULATOR_MODE_FAST
:
ret
=
regmap_update_bits
(
rdev
->
regmap
,
MT6315_BUCK_TOP_4PHASE_ANA_CON42
,
modeset_mask
,
modeset_mask
);
break
;
case
REGULATOR_MODE_NORMAL
:
if
(
curr_mode
==
REGULATOR_MODE_FAST
)
{
ret
=
regmap_update_bits
(
rdev
->
regmap
,
MT6315_BUCK_TOP_4PHASE_ANA_CON42
,
modeset_mask
,
0
);
}
else
if
(
curr_mode
==
REGULATOR_MODE_IDLE
)
{
ret
=
regmap_update_bits
(
rdev
->
regmap
,
MT6315_BUCK_TOP_CON1
,
info
->
lp_mode_mask
,
0
);
usleep_range
(
100
,
110
);
}
else
{
ret
=
-
EINVAL
;
}
break
;
case
REGULATOR_MODE_IDLE
:
val
=
MT6315_BUCK_MODE_LP
>>
1
;
val
<<=
info
->
lp_mode_shift
;
ret
=
regmap_update_bits
(
rdev
->
regmap
,
MT6315_BUCK_TOP_CON1
,
info
->
lp_mode_mask
,
val
);
break
;
default:
ret
=
-
EINVAL
;
dev_notice
(
&
rdev
->
dev
,
"Unsupported mode: %d
\n
"
,
mode
);
break
;
}
if
(
ret
!=
0
)
{
dev_notice
(
&
rdev
->
dev
,
"Failed to set mode: %d
\n
"
,
ret
);
return
ret
;
}
return
0
;
}
static
int
mt6315_get_status
(
struct
regulator_dev
*
rdev
)
{
const
struct
mt6315_regulator_info
*
info
;
int
ret
;
u32
regval
;
info
=
container_of
(
rdev
->
desc
,
struct
mt6315_regulator_info
,
desc
);
ret
=
regmap_read
(
rdev
->
regmap
,
info
->
status_reg
,
&
regval
);
if
(
ret
<
0
)
{
dev_notice
(
&
rdev
->
dev
,
"Failed to get enable reg: %d
\n
"
,
ret
);
return
ret
;
}
return
(
regval
&
BIT
(
0
))
?
REGULATOR_STATUS_ON
:
REGULATOR_STATUS_OFF
;
}
static
const
struct
regulator_ops
mt6315_volt_range_ops
=
{
.
list_voltage
=
regulator_list_voltage_linear_range
,
.
map_voltage
=
regulator_map_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
,
.
enable
=
regulator_enable_regmap
,
.
disable
=
regulator_disable_regmap
,
.
is_enabled
=
regulator_is_enabled_regmap
,
.
get_status
=
mt6315_get_status
,
.
set_mode
=
mt6315_regulator_set_mode
,
.
get_mode
=
mt6315_regulator_get_mode
,
};
static
const
struct
mt6315_regulator_info
mt6315_regulators
[
MT6315_VBUCK_MAX
]
=
{
MT_BUCK
(
"vbuck1"
,
MT6315_VBUCK1
,
MT6315_BUCK_TOP_ELR0
),
MT_BUCK
(
"vbuck2"
,
MT6315_VBUCK2
,
MT6315_BUCK_TOP_ELR2
),
MT_BUCK
(
"vbuck3"
,
MT6315_VBUCK3
,
MT6315_BUCK_TOP_ELR4
),
MT_BUCK
(
"vbuck4"
,
MT6315_VBUCK4
,
MT6315_BUCK_TOP_ELR6
),
};
static
const
struct
regmap_config
mt6315_regmap_config
=
{
.
reg_bits
=
16
,
.
val_bits
=
8
,
.
max_register
=
0x16d0
,
.
fast_io
=
true
,
};
static
const
struct
of_device_id
mt6315_of_match
[]
=
{
{
.
compatible
=
"mediatek,mt6315-regulator"
,
},
{
/* sentinel */
},
};
MODULE_DEVICE_TABLE
(
of
,
mt6315_of_match
);
static
int
mt6315_regulator_probe
(
struct
spmi_device
*
pdev
)
{
struct
device
*
dev
=
&
pdev
->
dev
;
struct
regmap
*
regmap
;
struct
mt6315_chip
*
chip
;
struct
mt_regulator_init_data
*
init_data
;
struct
regulator_config
config
=
{};
struct
regulator_dev
*
rdev
;
int
i
;
regmap
=
devm_regmap_init_spmi_ext
(
pdev
,
&
mt6315_regmap_config
);
if
(
!
regmap
)
return
-
ENODEV
;
chip
=
devm_kzalloc
(
dev
,
sizeof
(
struct
mt6315_chip
),
GFP_KERNEL
);
if
(
!
chip
)
return
-
ENOMEM
;
init_data
=
devm_kzalloc
(
dev
,
sizeof
(
struct
mt_regulator_init_data
),
GFP_KERNEL
);
if
(
!
init_data
)
return
-
ENOMEM
;
switch
(
pdev
->
usid
)
{
case
MT6315_PP
:
init_data
->
modeset_mask
[
MT6315_VBUCK1
]
=
BIT
(
MT6315_VBUCK1
)
|
BIT
(
MT6315_VBUCK2
)
|
BIT
(
MT6315_VBUCK4
);
break
;
case
MT6315_SP
:
case
MT6315_RP
:
init_data
->
modeset_mask
[
MT6315_VBUCK1
]
=
BIT
(
MT6315_VBUCK1
)
|
BIT
(
MT6315_VBUCK2
);
break
;
default:
init_data
->
modeset_mask
[
MT6315_VBUCK1
]
=
BIT
(
MT6315_VBUCK1
);
break
;
}
for
(
i
=
MT6315_VBUCK2
;
i
<
MT6315_VBUCK_MAX
;
i
++
)
init_data
->
modeset_mask
[
i
]
=
BIT
(
i
);
chip
->
dev
=
dev
;
chip
->
regmap
=
regmap
;
dev_set_drvdata
(
dev
,
chip
);
config
.
dev
=
dev
;
config
.
regmap
=
regmap
;
for
(
i
=
MT6315_VBUCK1
;
i
<
MT6315_VBUCK_MAX
;
i
++
)
{
config
.
driver_data
=
init_data
;
rdev
=
devm_regulator_register
(
dev
,
&
mt6315_regulators
[
i
].
desc
,
&
config
);
if
(
IS_ERR
(
rdev
))
{
dev_notice
(
dev
,
"Failed to register %s
\n
"
,
mt6315_regulators
[
i
].
desc
.
name
);
continue
;
}
}
return
0
;
}
static
void
mt6315_regulator_shutdown
(
struct
spmi_device
*
pdev
)
{
struct
mt6315_chip
*
chip
=
dev_get_drvdata
(
&
pdev
->
dev
);
int
ret
=
0
;
ret
|=
regmap_write
(
chip
->
regmap
,
MT6315_TOP_TMA_KEY_H
,
PROTECTION_KEY_H
);
ret
|=
regmap_write
(
chip
->
regmap
,
MT6315_TOP_TMA_KEY
,
PROTECTION_KEY
);
ret
|=
regmap_update_bits
(
chip
->
regmap
,
MT6315_TOP2_ELR7
,
1
,
1
);
ret
|=
regmap_write
(
chip
->
regmap
,
MT6315_TOP_TMA_KEY
,
0
);
ret
|=
regmap_write
(
chip
->
regmap
,
MT6315_TOP_TMA_KEY_H
,
0
);
if
(
ret
<
0
)
dev_notice
(
&
pdev
->
dev
,
"[%#x] Failed to enable power off sequence. %d
\n
"
,
pdev
->
usid
,
ret
);
}
static
struct
spmi_driver
mt6315_regulator_driver
=
{
.
driver
=
{
.
name
=
"mt6315-regulator"
,
.
of_match_table
=
mt6315_of_match
,
},
.
probe
=
mt6315_regulator_probe
,
.
shutdown
=
mt6315_regulator_shutdown
,
};
module_spmi_driver
(
mt6315_regulator_driver
);
MODULE_AUTHOR
(
"Hsin-Hsiung Wang <hsin-hsiung.wang@mediatek.com>"
);
MODULE_DESCRIPTION
(
"Regulator Driver for MediaTek MT6315 PMIC"
);
MODULE_LICENSE
(
"GPL"
);
drivers/regulator/mtk-dvfsrc-regulator.c
0 → 100644
View file @
f03e2a72
// SPDX-License-Identifier: GPL-2.0
//
// Copyright (c) 2020 MediaTek Inc.
#include <linux/err.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
#include <linux/soc/mediatek/mtk_dvfsrc.h>
#define DVFSRC_ID_VCORE 0
#define DVFSRC_ID_VSCP 1
#define MT_DVFSRC_REGULAR(match, _name, _volt_table) \
[DVFSRC_ID_##_name] = { \
.desc = { \
.name = match, \
.of_match = of_match_ptr(match), \
.ops = &dvfsrc_vcore_ops, \
.type = REGULATOR_VOLTAGE, \
.id = DVFSRC_ID_##_name, \
.owner = THIS_MODULE, \
.n_voltages = ARRAY_SIZE(_volt_table), \
.volt_table = _volt_table, \
}, \
}
/*
* DVFSRC regulators' information
*
* @desc: standard fields of regulator description.
* @voltage_selector: Selector used for get_voltage_sel() and
* set_voltage_sel() callbacks
*/
struct
dvfsrc_regulator
{
struct
regulator_desc
desc
;
};
/*
* MTK DVFSRC regulators' init data
*
* @size: num of regulators
* @regulator_info: regulator info.
*/
struct
dvfsrc_regulator_init_data
{
u32
size
;
struct
dvfsrc_regulator
*
regulator_info
;
};
static
inline
struct
device
*
to_dvfsrc_dev
(
struct
regulator_dev
*
rdev
)
{
return
rdev_get_dev
(
rdev
)
->
parent
;
}
static
int
dvfsrc_set_voltage_sel
(
struct
regulator_dev
*
rdev
,
unsigned
int
selector
)
{
struct
device
*
dvfsrc_dev
=
to_dvfsrc_dev
(
rdev
);
int
id
=
rdev_get_id
(
rdev
);
if
(
id
==
DVFSRC_ID_VCORE
)
mtk_dvfsrc_send_request
(
dvfsrc_dev
,
MTK_DVFSRC_CMD_VCORE_REQUEST
,
selector
);
else
if
(
id
==
DVFSRC_ID_VSCP
)
mtk_dvfsrc_send_request
(
dvfsrc_dev
,
MTK_DVFSRC_CMD_VSCP_REQUEST
,
selector
);
else
return
-
EINVAL
;
return
0
;
}
static
int
dvfsrc_get_voltage_sel
(
struct
regulator_dev
*
rdev
)
{
struct
device
*
dvfsrc_dev
=
to_dvfsrc_dev
(
rdev
);
int
id
=
rdev_get_id
(
rdev
);
int
val
,
ret
;
if
(
id
==
DVFSRC_ID_VCORE
)
ret
=
mtk_dvfsrc_query_info
(
dvfsrc_dev
,
MTK_DVFSRC_CMD_VCORE_LEVEL_QUERY
,
&
val
);
else
if
(
id
==
DVFSRC_ID_VSCP
)
ret
=
mtk_dvfsrc_query_info
(
dvfsrc_dev
,
MTK_DVFSRC_CMD_VSCP_LEVEL_QUERY
,
&
val
);
else
return
-
EINVAL
;
if
(
ret
!=
0
)
return
ret
;
return
val
;
}
static
const
struct
regulator_ops
dvfsrc_vcore_ops
=
{
.
list_voltage
=
regulator_list_voltage_table
,
.
get_voltage_sel
=
dvfsrc_get_voltage_sel
,
.
set_voltage_sel
=
dvfsrc_set_voltage_sel
,
};
static
const
unsigned
int
mt8183_voltages
[]
=
{
725000
,
800000
,
};
static
struct
dvfsrc_regulator
mt8183_regulators
[]
=
{
MT_DVFSRC_REGULAR
(
"dvfsrc-vcore"
,
VCORE
,
mt8183_voltages
),
};
static
const
struct
dvfsrc_regulator_init_data
regulator_mt8183_data
=
{
.
size
=
ARRAY_SIZE
(
mt8183_regulators
),
.
regulator_info
=
&
mt8183_regulators
[
0
],
};
static
const
unsigned
int
mt6873_voltages
[]
=
{
575000
,
600000
,
650000
,
725000
,
};
static
struct
dvfsrc_regulator
mt6873_regulators
[]
=
{
MT_DVFSRC_REGULAR
(
"dvfsrc-vcore"
,
VCORE
,
mt6873_voltages
),
MT_DVFSRC_REGULAR
(
"dvfsrc-vscp"
,
VSCP
,
mt6873_voltages
),
};
static
const
struct
dvfsrc_regulator_init_data
regulator_mt6873_data
=
{
.
size
=
ARRAY_SIZE
(
mt6873_regulators
),
.
regulator_info
=
&
mt6873_regulators
[
0
],
};
static
const
struct
of_device_id
mtk_dvfsrc_regulator_match
[]
=
{
{
.
compatible
=
"mediatek,mt8183-dvfsrc"
,
.
data
=
&
regulator_mt8183_data
,
},
{
.
compatible
=
"mediatek,mt8192-dvfsrc"
,
.
data
=
&
regulator_mt6873_data
,
},
{
.
compatible
=
"mediatek,mt6873-dvfsrc"
,
.
data
=
&
regulator_mt6873_data
,
},
{
/* sentinel */
},
};
MODULE_DEVICE_TABLE
(
of
,
mtk_dvfsrc_regulator_match
);
static
int
dvfsrc_vcore_regulator_probe
(
struct
platform_device
*
pdev
)
{
const
struct
of_device_id
*
match
;
struct
device
*
dev
=
&
pdev
->
dev
;
struct
regulator_config
config
=
{
};
struct
regulator_dev
*
rdev
;
const
struct
dvfsrc_regulator_init_data
*
regulator_init_data
;
struct
dvfsrc_regulator
*
mt_regulators
;
int
i
;
match
=
of_match_node
(
mtk_dvfsrc_regulator_match
,
dev
->
parent
->
of_node
);
if
(
!
match
)
{
dev_err
(
dev
,
"invalid compatible string
\n
"
);
return
-
ENODEV
;
}
regulator_init_data
=
match
->
data
;
mt_regulators
=
regulator_init_data
->
regulator_info
;
for
(
i
=
0
;
i
<
regulator_init_data
->
size
;
i
++
)
{
config
.
dev
=
dev
->
parent
;
config
.
driver_data
=
(
mt_regulators
+
i
);
rdev
=
devm_regulator_register
(
dev
->
parent
,
&
(
mt_regulators
+
i
)
->
desc
,
&
config
);
if
(
IS_ERR
(
rdev
))
{
dev_err
(
dev
,
"failed to register %s
\n
"
,
(
mt_regulators
+
i
)
->
desc
.
name
);
return
PTR_ERR
(
rdev
);
}
}
return
0
;
}
static
struct
platform_driver
mtk_dvfsrc_regulator_driver
=
{
.
driver
=
{
.
name
=
"mtk-dvfsrc-regulator"
,
},
.
probe
=
dvfsrc_vcore_regulator_probe
,
};
static
int
__init
mtk_dvfsrc_regulator_init
(
void
)
{
return
platform_driver_register
(
&
mtk_dvfsrc_regulator_driver
);
}
subsys_initcall
(
mtk_dvfsrc_regulator_init
);
static
void
__exit
mtk_dvfsrc_regulator_exit
(
void
)
{
platform_driver_unregister
(
&
mtk_dvfsrc_regulator_driver
);
}
module_exit
(
mtk_dvfsrc_regulator_exit
);
MODULE_AUTHOR
(
"Arvin wang <arvin.wang@mediatek.com>"
);
MODULE_LICENSE
(
"GPL v2"
);
drivers/regulator/pca9450-regulator.c
View file @
f03e2a72
...
...
@@ -5,6 +5,7 @@
*/
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
...
...
@@ -32,6 +33,7 @@ struct pca9450_regulator_desc {
struct
pca9450
{
struct
device
*
dev
;
struct
regmap
*
regmap
;
struct
gpio_desc
*
sd_vsel_gpio
;
enum
pca9450_chip_type
type
;
unsigned
int
rcnt
;
int
irq
;
...
...
@@ -795,6 +797,26 @@ static int pca9450_i2c_probe(struct i2c_client *i2c,
return
ret
;
}
/* Set reset behavior on assertion of WDOG_B signal */
ret
=
regmap_update_bits
(
pca9450
->
regmap
,
PCA9450_REG_RESET_CTRL
,
WDOG_B_CFG_MASK
,
WDOG_B_CFG_COLD_LDO12
);
if
(
ret
)
{
dev_err
(
&
i2c
->
dev
,
"Failed to set WDOG_B reset behavior
\n
"
);
return
ret
;
}
/*
* The driver uses the LDO5CTRL_H register to control the LDO5 regulator.
* This is only valid if the SD_VSEL input of the PMIC is high. Let's
* check if the pin is available as GPIO and set it to high.
*/
pca9450
->
sd_vsel_gpio
=
gpiod_get_optional
(
pca9450
->
dev
,
"sd-vsel"
,
GPIOD_OUT_HIGH
);
if
(
IS_ERR
(
pca9450
->
sd_vsel_gpio
))
{
dev_err
(
&
i2c
->
dev
,
"Failed to get SD_VSEL GPIO
\n
"
);
return
ret
;
}
dev_info
(
&
i2c
->
dev
,
"%s probed.
\n
"
,
type
==
PCA9450_TYPE_PCA9450A
?
"pca9450a"
:
"pca9450bc"
);
...
...
drivers/regulator/pf8x00-regulator.c
View file @
f03e2a72
...
...
@@ -114,7 +114,6 @@ enum swxilim_bits {
#define PF8X00_SWXILIM_SHIFT 3
#define PF8X00_SWXILIM_MASK GENMASK(4, 3)
#define PF8X00_SWXPHASE_MASK GENMASK(2, 0)
#define PF8X00_SWXPHASE_DEFAULT 0
#define PF8X00_SWXPHASE_SHIFT 7
enum
pf8x00_devid
{
...
...
@@ -126,10 +125,12 @@ enum pf8x00_devid {
#define PF8X00_DEVICE_FAM_MASK GENMASK(7, 4)
#define PF8X00_DEVICE_ID_MASK GENMASK(3, 0)
struct
pf8x00_regulator
{
struct
pf8x00_regulator
_data
{
struct
regulator_desc
desc
;
u8
ilim
;
u8
phase_shift
;
unsigned
int
suspend_enable_reg
;
unsigned
int
suspend_enable_mask
;
unsigned
int
suspend_voltage_reg
;
unsigned
int
suspend_voltage_cache
;
};
struct
pf8x00_chip
{
...
...
@@ -150,35 +151,16 @@ static const int pf8x00_ldo_voltages[] = {
3100000
,
3150000
,
3200000
,
3300000
,
3350000
,
1650000
,
1700000
,
5000000
,
};
#define SWV(i) (6250 * i + 400000)
#define SWV_LINE(i) SWV(i*8+0), SWV(i*8+1), SWV(i*8+2), SWV(i*8+3), \
SWV(i*8+4), SWV(i*8+5), SWV(i*8+6), SWV(i*8+7)
/* Output: 2.1A to 4.5A */
static
const
unsigned
int
pf8x00_sw_current_table
[]
=
{
2100000
,
2600000
,
3000000
,
4500000
,
};
/* Output: 0.4V to 1.8V */
static
const
int
pf8x00_sw1_to_6_voltages
[]
=
{
SWV_LINE
(
0
),
SWV_LINE
(
1
),
SWV_LINE
(
2
),
SWV_LINE
(
3
),
SWV_LINE
(
4
),
SWV_LINE
(
5
),
SWV_LINE
(
6
),
SWV_LINE
(
7
),
SWV_LINE
(
8
),
SWV_LINE
(
9
),
SWV_LINE
(
10
),
SWV_LINE
(
11
),
SWV_LINE
(
12
),
SWV_LINE
(
13
),
SWV_LINE
(
14
),
SWV_LINE
(
15
),
SWV_LINE
(
16
),
SWV_LINE
(
17
),
SWV_LINE
(
18
),
SWV_LINE
(
19
),
SWV_LINE
(
20
),
SWV_LINE
(
21
),
1500000
,
1800000
,
#define PF8XOO_SW1_6_VOLTAGE_NUM 0xB2
static
const
struct
linear_range
pf8x00_sw1_to_6_voltages
[]
=
{
REGULATOR_LINEAR_RANGE
(
400000
,
0x00
,
0xB0
,
6250
),
REGULATOR_LINEAR_RANGE
(
1800000
,
0xB1
,
0xB1
,
0
),
};
/* Output: 1.0V to 4.1V */
...
...
@@ -194,15 +176,10 @@ static const int pf8x00_vsnvs_voltages[] = {
0
,
1800000
,
3000000
,
3300000
,
};
static
struct
pf8x00_regulator
*
desc_to_regulator
(
const
struct
regulator_desc
*
desc
)
{
return
container_of
(
desc
,
struct
pf8x00_regulator
,
desc
);
}
static
void
swxilim_select
(
const
struct
regulator_desc
*
desc
,
int
ilim
)
static
void
swxilim_select
(
struct
pf8x00_chip
*
chip
,
int
id
,
int
ilim
)
{
struct
pf8x00_regulator
*
data
=
desc_to_regulator
(
desc
);
u8
ilim_sel
;
u8
reg
=
PF8X00_SW_BASE
(
id
)
+
SW_CONFIG2
;
switch
(
ilim
)
{
case
2100
:
...
...
@@ -222,43 +199,130 @@ static void swxilim_select(const struct regulator_desc *desc, int ilim)
break
;
}
data
->
ilim
=
ilim_sel
;
regmap_update_bits
(
chip
->
regmap
,
reg
,
PF8X00_SWXILIM_MASK
,
ilim_sel
<<
PF8X00_SWXILIM_SHIFT
);
}
static
int
pf8x00_of_parse_cb
(
struct
device_node
*
np
,
static
void
handle_ilim_property
(
struct
device_node
*
np
,
const
struct
regulator_desc
*
desc
,
struct
regulator_config
*
config
)
{
struct
pf8x00_regulator
*
data
=
desc_to_regulator
(
desc
);
struct
pf8x00_chip
*
chip
=
config
->
driver_data
;
int
ret
;
int
val
;
if
((
desc
->
id
>=
PF8X00_BUCK1
)
&&
(
desc
->
id
<=
PF8X00_BUCK7
))
{
ret
=
of_property_read_u32
(
np
,
"nxp,ilim-ma"
,
&
val
);
if
(
ret
)
{
dev_dbg
(
chip
->
dev
,
"unspecified ilim for BUCK%d, use value stored in OTP
\n
"
,
desc
->
id
-
PF8X00_LDO4
);
return
;
}
dev_warn
(
chip
->
dev
,
"nxp,ilim-ma is deprecated, please use regulator-max-microamp
\n
"
);
swxilim_select
(
chip
,
desc
->
id
,
val
);
}
else
dev_warn
(
chip
->
dev
,
"nxp,ilim-ma used with incorrect regulator (%d)
\n
"
,
desc
->
id
);
}
static
void
handle_shift_property
(
struct
device_node
*
np
,
const
struct
regulator_desc
*
desc
,
struct
regulator_config
*
config
)
{
unsigned
char
id
=
desc
->
id
-
PF8X00_LDO4
;
unsigned
char
reg
=
PF8X00_SW_BASE
(
id
)
+
SW_CONFIG2
;
struct
pf8x00_chip
*
chip
=
config
->
driver_data
;
int
phase
;
int
val
;
int
ret
;
if
((
desc
->
id
>=
PF8X00_BUCK1
)
&&
(
desc
->
id
<=
PF8X00_BUCK7
))
{
ret
=
of_property_read_u32
(
np
,
"nxp,phase-shift"
,
&
val
);
if
(
ret
)
{
dev_dbg
(
chip
->
dev
,
"unspecified phase-shift for BUCK%d, using OTP configuration
\n
"
,
id
);
return
;
}
ret
=
of_property_read_u32
(
np
,
"nxp,ilim-ma"
,
&
val
);
if
(
ret
)
dev_dbg
(
chip
->
dev
,
"unspecified ilim for BUCK%d, use 2100 mA
\n
"
,
desc
->
id
-
PF8X00_LDO4
);
if
(
val
<
0
||
val
>
315
||
val
%
45
!=
0
)
{
dev_warn
(
config
->
dev
,
"invalid phase_shift %d for BUCK%d, using OTP configuration
\n
"
,
val
,
id
);
return
;
}
swxilim_select
(
desc
,
val
)
;
phase
=
val
/
45
;
ret
=
of_property_read_u32
(
np
,
"nxp,phase-shift"
,
&
val
);
if
(
ret
)
{
dev_dbg
(
chip
->
dev
,
"unspecified phase-shift for BUCK%d, use 0 degrees
\n
"
,
desc
->
id
-
PF8X00_LDO4
);
val
=
PF8X00_SWXPHASE_DEFAULT
;
if
(
phase
>=
1
)
phase
-=
1
;
else
phase
=
PF8X00_SWXPHASE_SHIFT
;
regmap_update_bits
(
chip
->
regmap
,
reg
,
PF8X00_SWXPHASE_MASK
,
phase
);
}
else
dev_warn
(
chip
->
dev
,
"nxp,phase-shift used with incorrect regulator (%d)
\n
"
,
id
);
}
static
int
pf8x00_of_parse_cb
(
struct
device_node
*
np
,
const
struct
regulator_desc
*
desc
,
struct
regulator_config
*
config
)
{
handle_ilim_property
(
np
,
desc
,
config
);
handle_shift_property
(
np
,
desc
,
config
);
return
0
;
}
static
int
pf8x00_suspend_enable
(
struct
regulator_dev
*
rdev
)
{
struct
pf8x00_regulator_data
*
regl
=
rdev_get_drvdata
(
rdev
);
struct
regmap
*
rmap
=
rdev_get_regmap
(
rdev
);
return
regmap_update_bits
(
rmap
,
regl
->
suspend_enable_reg
,
regl
->
suspend_enable_mask
,
regl
->
suspend_enable_mask
);
}
static
int
pf8x00_suspend_disable
(
struct
regulator_dev
*
rdev
)
{
struct
pf8x00_regulator_data
*
regl
=
rdev_get_drvdata
(
rdev
);
struct
regmap
*
rmap
=
rdev_get_regmap
(
rdev
);
return
regmap_update_bits
(
rmap
,
regl
->
suspend_enable_reg
,
regl
->
suspend_enable_mask
,
0
);
}
static
int
pf8x00_set_suspend_voltage
(
struct
regulator_dev
*
rdev
,
int
uV
)
{
struct
pf8x00_regulator_data
*
regl
=
rdev_get_drvdata
(
rdev
);
int
ret
;
if
(
regl
->
suspend_voltage_cache
==
uV
)
return
0
;
ret
=
regulator_map_voltage_iterate
(
rdev
,
uV
,
uV
);
if
(
ret
<
0
)
{
dev_err
(
rdev_get_dev
(
rdev
),
"failed to map %i uV
\n
"
,
uV
);
return
ret
;
}
phase
=
val
/
45
;
if
((
phase
*
45
)
!=
val
)
{
dev_warn
(
config
->
dev
,
"invalid phase_shift %d for BUCK%d, use 0 degrees
\n
"
,
(
phase
*
45
),
desc
->
id
-
PF8X00_LDO4
);
phase
=
PF8X00_SWXPHASE_SHIFT
;
dev_dbg
(
rdev_get_dev
(
rdev
),
"uV: %i, reg: 0x%x, msk: 0x%x, val: 0x%x
\n
"
,
uV
,
regl
->
suspend_voltage_reg
,
regl
->
desc
.
vsel_mask
,
ret
);
ret
=
regmap_update_bits
(
rdev
->
regmap
,
regl
->
suspend_voltage_reg
,
regl
->
desc
.
vsel_mask
,
ret
);
if
(
ret
<
0
)
{
dev_err
(
rdev_get_dev
(
rdev
),
"failed to set %i uV
\n
"
,
uV
);
return
ret
;
}
data
->
phase_shift
=
(
phase
>=
1
)
?
phase
-
1
:
PF8X00_SWXPHASE_SHIFT
;
regl
->
suspend_voltage_cache
=
uV
;
return
0
;
}
...
...
@@ -270,15 +334,37 @@ static const struct regulator_ops pf8x00_ldo_ops = {
.
list_voltage
=
regulator_list_voltage_table
,
.
set_voltage_sel
=
regulator_set_voltage_sel_regmap
,
.
get_voltage_sel
=
regulator_get_voltage_sel_regmap
,
.
set_suspend_enable
=
pf8x00_suspend_enable
,
.
set_suspend_disable
=
pf8x00_suspend_disable
,
.
set_suspend_voltage
=
pf8x00_set_suspend_voltage
,
};
static
const
struct
regulator_ops
pf8x00_buck1_6_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
,
.
get_current_limit
=
regulator_get_current_limit_regmap
,
.
set_current_limit
=
regulator_set_current_limit_regmap
,
.
set_suspend_enable
=
pf8x00_suspend_enable
,
.
set_suspend_disable
=
pf8x00_suspend_disable
,
.
set_suspend_voltage
=
pf8x00_set_suspend_voltage
,
};
static
const
struct
regulator_ops
pf8x00_buck_ops
=
{
static
const
struct
regulator_ops
pf8x00_buck
7
_ops
=
{
.
enable
=
regulator_enable_regmap
,
.
disable
=
regulator_disable_regmap
,
.
is_enabled
=
regulator_is_enabled_regmap
,
.
list_voltage
=
regulator_list_voltage_table
,
.
set_voltage_sel
=
regulator_set_voltage_sel_regmap
,
.
get_voltage_sel
=
regulator_get_voltage_sel_regmap
,
.
get_current_limit
=
regulator_get_current_limit_regmap
,
.
set_current_limit
=
regulator_set_current_limit_regmap
,
.
set_suspend_enable
=
pf8x00_suspend_enable
,
.
set_suspend_disable
=
pf8x00_suspend_disable
,
};
static
const
struct
regulator_ops
pf8x00_vsnvs_ops
=
{
...
...
@@ -310,6 +396,9 @@ static const struct regulator_ops pf8x00_vsnvs_ops = {
.disable_val = 0x0, \
.enable_mask = 2, \
}, \
.suspend_enable_reg = (base) + LDO_CONFIG2, \
.suspend_enable_mask = 1, \
.suspend_voltage_reg = (base) + LDO_STBY_VOLT, \
}
#define PF8X00BUCK(_id, _name, base, voltages) \
...
...
@@ -319,14 +408,54 @@ static const struct regulator_ops pf8x00_vsnvs_ops = {
.of_match = _name, \
.regulators_node = "regulators", \
.of_parse_cb = pf8x00_of_parse_cb, \
.n_voltages =
ARRAY_SIZE(voltages)
, \
.ops = &pf8x00_buck_ops, \
.n_voltages =
PF8XOO_SW1_6_VOLTAGE_NUM
, \
.ops = &pf8x00_buck
1_6
_ops, \
.type = REGULATOR_VOLTAGE, \
.id = PF8X00_BUCK ## _id, \
.owner = THIS_MODULE, \
.ramp_delay = 19000, \
.linear_ranges = pf8x00_sw1_to_6_voltages, \
.n_linear_ranges = \
ARRAY_SIZE(pf8x00_sw1_to_6_voltages), \
.vsel_reg = (base) + SW_RUN_VOLT, \
.vsel_mask = 0xff, \
.curr_table = pf8x00_sw_current_table, \
.n_current_limits = \
ARRAY_SIZE(pf8x00_sw_current_table), \
.csel_reg = (base) + SW_CONFIG2, \
.csel_mask = PF8X00_SWXILIM_MASK, \
.enable_reg = (base) + SW_MODE1, \
.enable_val = 0x3, \
.disable_val = 0x0, \
.enable_mask = 0x3, \
.enable_time = 500, \
}, \
.suspend_enable_reg = (base) + SW_MODE1, \
.suspend_enable_mask = 0xc, \
.suspend_voltage_reg = (base) + SW_STBY_VOLT, \
}
#define PF8X00BUCK7(_name, base, voltages) \
[PF8X00_BUCK7] = { \
.desc = { \
.name = _name, \
.of_match = _name, \
.regulators_node = "regulators", \
.of_parse_cb = pf8x00_of_parse_cb, \
.n_voltages = ARRAY_SIZE(voltages), \
.ops = &pf8x00_buck7_ops, \
.type = REGULATOR_VOLTAGE, \
.id = PF8X00_BUCK7, \
.owner = THIS_MODULE, \
.ramp_delay = 19000, \
.volt_table = voltages, \
.vsel_reg = (base) + SW_RUN_VOLT, \
.vsel_mask = 0xff, \
.curr_table = pf8x00_sw_current_table, \
.n_current_limits = \
ARRAY_SIZE(pf8x00_sw_current_table), \
.csel_reg = (base) + SW_CONFIG2, \
.csel_mask = PF8X00_SWXILIM_MASK, \
.enable_reg = (base) + SW_MODE1, \
.enable_val = 0x3, \
.disable_val = 0x0, \
...
...
@@ -335,6 +464,7 @@ static const struct regulator_ops pf8x00_vsnvs_ops = {
}, \
}
#define PF8X00VSNVS(_name, base, voltages) \
[PF8X00_VSNVS] = { \
.desc = { \
...
...
@@ -352,7 +482,7 @@ static const struct regulator_ops pf8x00_vsnvs_ops = {
}, \
}
static
struct
pf8x00_regulator
pf8x00_regulator
s_data
[
PF8X00_MAX_REGULATORS
]
=
{
static
struct
pf8x00_regulator
_data
pf8x00_reg
s_data
[
PF8X00_MAX_REGULATORS
]
=
{
PF8X00LDO
(
1
,
"ldo1"
,
PF8X00_LDO_BASE
(
PF8X00_LDO1
),
pf8x00_ldo_voltages
),
PF8X00LDO
(
2
,
"ldo2"
,
PF8X00_LDO_BASE
(
PF8X00_LDO2
),
pf8x00_ldo_voltages
),
PF8X00LDO
(
3
,
"ldo3"
,
PF8X00_LDO_BASE
(
PF8X00_LDO3
),
pf8x00_ldo_voltages
),
...
...
@@ -363,7 +493,7 @@ static struct pf8x00_regulator pf8x00_regulators_data[PF8X00_MAX_REGULATORS] = {
PF8X00BUCK
(
4
,
"buck4"
,
PF8X00_SW_BASE
(
PF8X00_BUCK4
),
pf8x00_sw1_to_6_voltages
),
PF8X00BUCK
(
5
,
"buck5"
,
PF8X00_SW_BASE
(
PF8X00_BUCK5
),
pf8x00_sw1_to_6_voltages
),
PF8X00BUCK
(
6
,
"buck6"
,
PF8X00_SW_BASE
(
PF8X00_BUCK6
),
pf8x00_sw1_to_6_voltages
),
PF8X00BUCK
(
7
,
"buck7"
,
PF8X00_SW_BASE
(
PF8X00_BUCK7
),
pf8x00_sw7_voltages
),
PF8X00BUCK
7
(
"buck7"
,
PF8X00_SW_BASE
(
PF8X00_BUCK7
),
pf8x00_sw7_voltages
),
PF8X00VSNVS
(
"vsnvs"
,
PF8X00_VSNVS_CONFIG1
,
pf8x00_vsnvs_voltages
),
};
...
...
@@ -437,12 +567,12 @@ static int pf8x00_i2c_probe(struct i2c_client *client)
if
(
ret
)
return
ret
;
for
(
id
=
0
;
id
<
ARRAY_SIZE
(
pf8x00_reg
ulator
s_data
);
id
++
)
{
struct
pf8x00_regulator
*
data
=
&
pf8x00_regulator
s_data
[
id
];
for
(
id
=
0
;
id
<
ARRAY_SIZE
(
pf8x00_regs_data
);
id
++
)
{
struct
pf8x00_regulator
_data
*
data
=
&
pf8x00_reg
s_data
[
id
];
struct
regulator_dev
*
rdev
;
config
.
dev
=
chip
->
dev
;
config
.
driver_data
=
chip
;
config
.
driver_data
=
data
;
config
.
regmap
=
chip
->
regmap
;
rdev
=
devm_regulator_register
(
&
client
->
dev
,
&
data
->
desc
,
&
config
);
...
...
@@ -451,18 +581,6 @@ static int pf8x00_i2c_probe(struct i2c_client *client)
"failed to register %s regulator
\n
"
,
data
->
desc
.
name
);
return
PTR_ERR
(
rdev
);
}
if
((
id
>=
PF8X00_BUCK1
)
&&
(
id
<=
PF8X00_BUCK7
))
{
u8
reg
=
PF8X00_SW_BASE
(
id
)
+
SW_CONFIG2
;
regmap_update_bits
(
chip
->
regmap
,
reg
,
PF8X00_SWXPHASE_MASK
,
data
->
phase_shift
);
regmap_update_bits
(
chip
->
regmap
,
reg
,
PF8X00_SWXILIM_MASK
,
data
->
ilim
<<
PF8X00_SWXILIM_SHIFT
);
}
}
return
0
;
...
...
drivers/regulator/qcom-labibb-regulator.c
View file @
f03e2a72
...
...
@@ -17,11 +17,48 @@
#define PMI8998_LAB_REG_BASE 0xde00
#define PMI8998_IBB_REG_BASE 0xdc00
#define PMI8998_IBB_LAB_REG_OFFSET 0x200
#define REG_LABIBB_STATUS1 0x08
#define LABIBB_STATUS1_SC_BIT BIT(6)
#define LABIBB_STATUS1_VREG_OK_BIT BIT(7)
#define REG_LABIBB_INT_SET_TYPE 0x11
#define REG_LABIBB_INT_POLARITY_HIGH 0x12
#define REG_LABIBB_INT_POLARITY_LOW 0x13
#define REG_LABIBB_INT_LATCHED_CLR 0x14
#define REG_LABIBB_INT_EN_SET 0x15
#define REG_LABIBB_INT_EN_CLR 0x16
#define LABIBB_INT_VREG_OK BIT(0)
#define LABIBB_INT_VREG_TYPE_LEVEL 0
#define REG_LABIBB_VOLTAGE 0x41
#define LABIBB_VOLTAGE_OVERRIDE_EN BIT(7)
#define LAB_VOLTAGE_SET_MASK GENMASK(3, 0)
#define IBB_VOLTAGE_SET_MASK GENMASK(5, 0)
#define REG_LABIBB_ENABLE_CTL 0x46
#define LABIBB_STATUS1_VREG_OK_BIT BIT(7)
#define LABIBB_CONTROL_ENABLE BIT(7)
#define LABIBB_CONTROL_ENABLE BIT(7)
#define REG_LABIBB_PD_CTL 0x47
#define LAB_PD_CTL_MASK GENMASK(1, 0)
#define IBB_PD_CTL_MASK (BIT(0) | BIT(7))
#define LAB_PD_CTL_STRONG_PULL BIT(0)
#define IBB_PD_CTL_HALF_STRENGTH BIT(0)
#define IBB_PD_CTL_EN BIT(7)
#define REG_LABIBB_CURRENT_LIMIT 0x4b
#define LAB_CURRENT_LIMIT_MASK GENMASK(2, 0)
#define IBB_CURRENT_LIMIT_MASK GENMASK(4, 0)
#define LAB_CURRENT_LIMIT_OVERRIDE_EN BIT(3)
#define LABIBB_CURRENT_LIMIT_EN BIT(7)
#define REG_IBB_PWRUP_PWRDN_CTL_1 0x58
#define IBB_CTL_1_DISCHARGE_EN BIT(2)
#define REG_LABIBB_SOFT_START_CTL 0x5f
#define REG_LABIBB_SEC_ACCESS 0xd0
#define LABIBB_SEC_UNLOCK_CODE 0xa5
#define LAB_ENABLE_CTL_MASK BIT(7)
#define IBB_ENABLE_CTL_MASK (BIT(7) | BIT(6))
...
...
@@ -30,14 +67,35 @@
#define LAB_ENABLE_TIME (LABIBB_OFF_ON_DELAY * 2)
#define IBB_ENABLE_TIME (LABIBB_OFF_ON_DELAY * 10)
#define LABIBB_POLL_ENABLED_TIME 1000
#define OCP_RECOVERY_INTERVAL_MS 500
#define SC_RECOVERY_INTERVAL_MS 250
#define LABIBB_MAX_OCP_COUNT 4
#define LABIBB_MAX_SC_COUNT 3
#define LABIBB_MAX_FATAL_COUNT 2
struct
labibb_current_limits
{
u32
uA_min
;
u32
uA_step
;
u8
ovr_val
;
};
struct
labibb_regulator
{
struct
regulator_desc
desc
;
struct
device
*
dev
;
struct
regmap
*
regmap
;
struct
regulator_dev
*
rdev
;
struct
labibb_current_limits
uA_limits
;
struct
delayed_work
ocp_recovery_work
;
struct
delayed_work
sc_recovery_work
;
u16
base
;
u8
type
;
u8
dischg_sel
;
u8
soft_start_sel
;
int
sc_irq
;
int
sc_count
;
int
ocp_irq
;
int
ocp_irq_count
;
int
fatal_count
;
};
struct
labibb_regulator_data
{
...
...
@@ -47,10 +105,579 @@ struct labibb_regulator_data {
const
struct
regulator_desc
*
desc
;
};
static
int
qcom_labibb_ocp_hw_enable
(
struct
regulator_dev
*
rdev
)
{
struct
labibb_regulator
*
vreg
=
rdev_get_drvdata
(
rdev
);
int
ret
;
/* Clear irq latch status to avoid spurious event */
ret
=
regmap_update_bits
(
rdev
->
regmap
,
vreg
->
base
+
REG_LABIBB_INT_LATCHED_CLR
,
LABIBB_INT_VREG_OK
,
1
);
if
(
ret
)
return
ret
;
/* Enable OCP HW interrupt */
return
regmap_update_bits
(
rdev
->
regmap
,
vreg
->
base
+
REG_LABIBB_INT_EN_SET
,
LABIBB_INT_VREG_OK
,
1
);
}
static
int
qcom_labibb_ocp_hw_disable
(
struct
regulator_dev
*
rdev
)
{
struct
labibb_regulator
*
vreg
=
rdev_get_drvdata
(
rdev
);
return
regmap_update_bits
(
rdev
->
regmap
,
vreg
->
base
+
REG_LABIBB_INT_EN_CLR
,
LABIBB_INT_VREG_OK
,
1
);
}
/**
* qcom_labibb_check_ocp_status - Check the Over-Current Protection status
* @vreg: Main driver structure
*
* This function checks the STATUS1 register for the VREG_OK bit: if it is
* set, then there is no Over-Current event.
*
* Returns: Zero if there is no over-current, 1 if in over-current or
* negative number for error
*/
static
int
qcom_labibb_check_ocp_status
(
struct
labibb_regulator
*
vreg
)
{
u32
cur_status
;
int
ret
;
ret
=
regmap_read
(
vreg
->
rdev
->
regmap
,
vreg
->
base
+
REG_LABIBB_STATUS1
,
&
cur_status
);
if
(
ret
)
return
ret
;
return
!
(
cur_status
&
LABIBB_STATUS1_VREG_OK_BIT
);
}
/**
* qcom_labibb_ocp_recovery_worker - Handle OCP event
* @work: OCP work structure
*
* This is the worker function to handle the Over Current Protection
* hardware event; This will check if the hardware is still
* signaling an over-current condition and will eventually stop
* the regulator if such condition is still signaled after
* LABIBB_MAX_OCP_COUNT times.
*
* If the driver that is consuming the regulator did not take action
* for the OCP condition, or the hardware did not stabilize, a cut
* of the LAB and IBB regulators will be forced (regulators will be
* disabled).
*
* As last, if the writes to shut down the LAB/IBB regulators fail
* for more than LABIBB_MAX_FATAL_COUNT, then a kernel panic will be
* triggered, as a last resort to protect the hardware from burning;
* this, however, is expected to never happen, but this is kept to
* try to further ensure that we protect the hardware at all costs.
*/
static
void
qcom_labibb_ocp_recovery_worker
(
struct
work_struct
*
work
)
{
struct
labibb_regulator
*
vreg
;
const
struct
regulator_ops
*
ops
;
int
ret
;
vreg
=
container_of
(
work
,
struct
labibb_regulator
,
ocp_recovery_work
.
work
);
ops
=
vreg
->
rdev
->
desc
->
ops
;
if
(
vreg
->
ocp_irq_count
>=
LABIBB_MAX_OCP_COUNT
)
{
/*
* If we tried to disable the regulator multiple times but
* we kept failing, there's only one last hope to save our
* hardware from the death: raise a kernel bug, reboot and
* hope that the bootloader kindly saves us. This, though
* is done only as paranoid checking, because failing the
* regmap write to disable the vreg is almost impossible,
* since we got here after multiple regmap R/W.
*/
BUG_ON
(
vreg
->
fatal_count
>
LABIBB_MAX_FATAL_COUNT
);
dev_err
(
&
vreg
->
rdev
->
dev
,
"LABIBB: CRITICAL: Disabling regulator
\n
"
);
/* Disable the regulator immediately to avoid damage */
ret
=
ops
->
disable
(
vreg
->
rdev
);
if
(
ret
)
{
vreg
->
fatal_count
++
;
goto
reschedule
;
}
enable_irq
(
vreg
->
ocp_irq
);
vreg
->
fatal_count
=
0
;
return
;
}
ret
=
qcom_labibb_check_ocp_status
(
vreg
);
if
(
ret
!=
0
)
{
vreg
->
ocp_irq_count
++
;
goto
reschedule
;
}
ret
=
qcom_labibb_ocp_hw_enable
(
vreg
->
rdev
);
if
(
ret
)
{
/* We cannot trust it without OCP enabled. */
dev_err
(
vreg
->
dev
,
"Cannot enable OCP IRQ
\n
"
);
vreg
->
ocp_irq_count
++
;
goto
reschedule
;
}
enable_irq
(
vreg
->
ocp_irq
);
/* Everything went fine: reset the OCP count! */
vreg
->
ocp_irq_count
=
0
;
return
;
reschedule:
mod_delayed_work
(
system_wq
,
&
vreg
->
ocp_recovery_work
,
msecs_to_jiffies
(
OCP_RECOVERY_INTERVAL_MS
));
}
/**
* qcom_labibb_ocp_isr - Interrupt routine for OverCurrent Protection
* @irq: Interrupt number
* @chip: Main driver structure
*
* Over Current Protection (OCP) will signal to the client driver
* that an over-current event has happened and then will schedule
* a recovery worker.
*
* Disabling and eventually re-enabling the regulator is expected
* to be done by the driver, as some hardware may be triggering an
* over-current condition only at first initialization or it may
* be expected only for a very brief amount of time, after which
* the attached hardware may be expected to stabilize its current
* draw.
*
* Returns: IRQ_HANDLED for success or IRQ_NONE for failure.
*/
static
irqreturn_t
qcom_labibb_ocp_isr
(
int
irq
,
void
*
chip
)
{
struct
labibb_regulator
*
vreg
=
chip
;
const
struct
regulator_ops
*
ops
=
vreg
->
rdev
->
desc
->
ops
;
int
ret
;
/* If the regulator is not enabled, this is a fake event */
if
(
!
ops
->
is_enabled
(
vreg
->
rdev
))
return
0
;
/* If we tried to recover for too many times it's not getting better */
if
(
vreg
->
ocp_irq_count
>
LABIBB_MAX_OCP_COUNT
)
return
IRQ_NONE
;
/*
* If we (unlikely) can't read this register, to prevent hardware
* damage at all costs, we assume that the overcurrent event was
* real; Moreover, if the status register is not signaling OCP,
* it was a spurious event, so it's all ok.
*/
ret
=
qcom_labibb_check_ocp_status
(
vreg
);
if
(
ret
==
0
)
{
vreg
->
ocp_irq_count
=
0
;
goto
end
;
}
vreg
->
ocp_irq_count
++
;
/*
* Disable the interrupt temporarily, or it will fire continuously;
* we will re-enable it in the recovery worker function.
*/
disable_irq_nosync
(
irq
);
/* Warn the user for overcurrent */
dev_warn
(
vreg
->
dev
,
"Over-Current interrupt fired!
\n
"
);
/* Disable the interrupt to avoid hogging */
ret
=
qcom_labibb_ocp_hw_disable
(
vreg
->
rdev
);
if
(
ret
)
goto
end
;
/* Signal overcurrent event to drivers */
regulator_notifier_call_chain
(
vreg
->
rdev
,
REGULATOR_EVENT_OVER_CURRENT
,
NULL
);
end:
/* Schedule the recovery work */
schedule_delayed_work
(
&
vreg
->
ocp_recovery_work
,
msecs_to_jiffies
(
OCP_RECOVERY_INTERVAL_MS
));
if
(
ret
)
return
IRQ_NONE
;
return
IRQ_HANDLED
;
}
static
int
qcom_labibb_set_ocp
(
struct
regulator_dev
*
rdev
)
{
struct
labibb_regulator
*
vreg
=
rdev_get_drvdata
(
rdev
);
char
*
ocp_irq_name
;
u32
irq_flags
=
IRQF_ONESHOT
;
int
irq_trig_low
,
ret
;
/* If there is no OCP interrupt, there's nothing to set */
if
(
vreg
->
ocp_irq
<=
0
)
return
-
EINVAL
;
ocp_irq_name
=
devm_kasprintf
(
vreg
->
dev
,
GFP_KERNEL
,
"%s-over-current"
,
vreg
->
desc
.
name
);
if
(
!
ocp_irq_name
)
return
-
ENOMEM
;
/* IRQ polarities - LAB: trigger-low, IBB: trigger-high */
switch
(
vreg
->
type
)
{
case
QCOM_LAB_TYPE
:
irq_flags
|=
IRQF_TRIGGER_LOW
;
irq_trig_low
=
1
;
break
;
case
QCOM_IBB_TYPE
:
irq_flags
|=
IRQF_TRIGGER_HIGH
;
irq_trig_low
=
0
;
break
;
default:
return
-
EINVAL
;
}
/* Activate OCP HW level interrupt */
ret
=
regmap_update_bits
(
rdev
->
regmap
,
vreg
->
base
+
REG_LABIBB_INT_SET_TYPE
,
LABIBB_INT_VREG_OK
,
LABIBB_INT_VREG_TYPE_LEVEL
);
if
(
ret
)
return
ret
;
/* Set OCP interrupt polarity */
ret
=
regmap_update_bits
(
rdev
->
regmap
,
vreg
->
base
+
REG_LABIBB_INT_POLARITY_HIGH
,
LABIBB_INT_VREG_OK
,
!
irq_trig_low
);
if
(
ret
)
return
ret
;
ret
=
regmap_update_bits
(
rdev
->
regmap
,
vreg
->
base
+
REG_LABIBB_INT_POLARITY_LOW
,
LABIBB_INT_VREG_OK
,
irq_trig_low
);
if
(
ret
)
return
ret
;
ret
=
qcom_labibb_ocp_hw_enable
(
rdev
);
if
(
ret
)
return
ret
;
return
devm_request_threaded_irq
(
vreg
->
dev
,
vreg
->
ocp_irq
,
NULL
,
qcom_labibb_ocp_isr
,
irq_flags
,
ocp_irq_name
,
vreg
);
}
/**
* qcom_labibb_check_sc_status - Check the Short Circuit Protection status
* @vreg: Main driver structure
*
* This function checks the STATUS1 register on both LAB and IBB regulators
* for the ShortCircuit bit: if it is set on *any* of them, then we have
* experienced a short-circuit event.
*
* Returns: Zero if there is no short-circuit, 1 if in short-circuit or
* negative number for error
*/
static
int
qcom_labibb_check_sc_status
(
struct
labibb_regulator
*
vreg
)
{
u32
ibb_status
,
ibb_reg
,
lab_status
,
lab_reg
;
int
ret
;
/* We have to work on both regulators due to PBS... */
lab_reg
=
ibb_reg
=
vreg
->
base
+
REG_LABIBB_STATUS1
;
if
(
vreg
->
type
==
QCOM_LAB_TYPE
)
ibb_reg
-=
PMI8998_IBB_LAB_REG_OFFSET
;
else
lab_reg
+=
PMI8998_IBB_LAB_REG_OFFSET
;
ret
=
regmap_read
(
vreg
->
rdev
->
regmap
,
lab_reg
,
&
lab_status
);
if
(
ret
)
return
ret
;
ret
=
regmap_read
(
vreg
->
rdev
->
regmap
,
ibb_reg
,
&
ibb_status
);
if
(
ret
)
return
ret
;
return
!!
(
lab_status
&
LABIBB_STATUS1_SC_BIT
)
||
!!
(
ibb_status
&
LABIBB_STATUS1_SC_BIT
);
}
/**
* qcom_labibb_sc_recovery_worker - Handle Short Circuit event
* @work: SC work structure
*
* This is the worker function to handle the Short Circuit Protection
* hardware event; This will check if the hardware is still
* signaling a short-circuit condition and will eventually never
* re-enable the regulator if such condition is still signaled after
* LABIBB_MAX_SC_COUNT times.
*
* If the driver that is consuming the regulator did not take action
* for the SC condition, or the hardware did not stabilize, this
* worker will stop rescheduling, leaving the regulators disabled
* as already done by the Portable Batch System (PBS).
*
* Returns: IRQ_HANDLED for success or IRQ_NONE for failure.
*/
static
void
qcom_labibb_sc_recovery_worker
(
struct
work_struct
*
work
)
{
struct
labibb_regulator
*
vreg
;
const
struct
regulator_ops
*
ops
;
u32
lab_reg
,
ibb_reg
,
lab_val
,
ibb_val
,
val
;
bool
pbs_cut
=
false
;
int
i
,
sc
,
ret
;
vreg
=
container_of
(
work
,
struct
labibb_regulator
,
sc_recovery_work
.
work
);
ops
=
vreg
->
rdev
->
desc
->
ops
;
/*
* If we tried to check the regulator status multiple times but we
* kept failing, then just bail out, as the Portable Batch System
* (PBS) will disable the vregs for us, preventing hardware damage.
*/
if
(
vreg
->
fatal_count
>
LABIBB_MAX_FATAL_COUNT
)
return
;
/* Too many short-circuit events. Throw in the towel. */
if
(
vreg
->
sc_count
>
LABIBB_MAX_SC_COUNT
)
return
;
/*
* The Portable Batch System (PBS) automatically disables LAB
* and IBB when a short-circuit event is detected, so we have to
* check and work on both of them at the same time.
*/
lab_reg
=
ibb_reg
=
vreg
->
base
+
REG_LABIBB_ENABLE_CTL
;
if
(
vreg
->
type
==
QCOM_LAB_TYPE
)
ibb_reg
-=
PMI8998_IBB_LAB_REG_OFFSET
;
else
lab_reg
+=
PMI8998_IBB_LAB_REG_OFFSET
;
sc
=
qcom_labibb_check_sc_status
(
vreg
);
if
(
sc
)
goto
reschedule
;
for
(
i
=
0
;
i
<
LABIBB_MAX_SC_COUNT
;
i
++
)
{
ret
=
regmap_read
(
vreg
->
regmap
,
lab_reg
,
&
lab_val
);
if
(
ret
)
{
vreg
->
fatal_count
++
;
goto
reschedule
;
}
ret
=
regmap_read
(
vreg
->
regmap
,
ibb_reg
,
&
ibb_val
);
if
(
ret
)
{
vreg
->
fatal_count
++
;
goto
reschedule
;
}
val
=
lab_val
&
ibb_val
;
if
(
!
(
val
&
LABIBB_CONTROL_ENABLE
))
{
pbs_cut
=
true
;
break
;
}
usleep_range
(
5000
,
6000
);
}
if
(
pbs_cut
)
goto
reschedule
;
/*
* If we have reached this point, we either have successfully
* recovered from the SC condition or we had a spurious SC IRQ,
* which means that we can re-enable the regulators, if they
* have ever been disabled by the PBS.
*/
ret
=
ops
->
enable
(
vreg
->
rdev
);
if
(
ret
)
goto
reschedule
;
/* Everything went fine: reset the OCP count! */
vreg
->
sc_count
=
0
;
enable_irq
(
vreg
->
sc_irq
);
return
;
reschedule:
/*
* Now that we have done basic handling of the short-circuit,
* reschedule this worker in the regular system workqueue, as
* taking action is not truly urgent anymore.
*/
vreg
->
sc_count
++
;
mod_delayed_work
(
system_wq
,
&
vreg
->
sc_recovery_work
,
msecs_to_jiffies
(
SC_RECOVERY_INTERVAL_MS
));
}
/**
* qcom_labibb_sc_isr - Interrupt routine for Short Circuit Protection
* @irq: Interrupt number
* @chip: Main driver structure
*
* Short Circuit Protection (SCP) will signal to the client driver
* that a regulation-out event has happened and then will schedule
* a recovery worker.
*
* The LAB and IBB regulators will be automatically disabled by the
* Portable Batch System (PBS) and they will be enabled again by
* the worker function if the hardware stops signaling the short
* circuit event.
*
* Returns: IRQ_HANDLED for success or IRQ_NONE for failure.
*/
static
irqreturn_t
qcom_labibb_sc_isr
(
int
irq
,
void
*
chip
)
{
struct
labibb_regulator
*
vreg
=
chip
;
if
(
vreg
->
sc_count
>
LABIBB_MAX_SC_COUNT
)
return
IRQ_NONE
;
/* Warn the user for short circuit */
dev_warn
(
vreg
->
dev
,
"Short-Circuit interrupt fired!
\n
"
);
/*
* Disable the interrupt temporarily, or it will fire continuously;
* we will re-enable it in the recovery worker function.
*/
disable_irq_nosync
(
irq
);
/* Signal out of regulation event to drivers */
regulator_notifier_call_chain
(
vreg
->
rdev
,
REGULATOR_EVENT_REGULATION_OUT
,
NULL
);
/* Schedule the short-circuit handling as high-priority work */
mod_delayed_work
(
system_highpri_wq
,
&
vreg
->
sc_recovery_work
,
msecs_to_jiffies
(
SC_RECOVERY_INTERVAL_MS
));
return
IRQ_HANDLED
;
}
static
int
qcom_labibb_set_current_limit
(
struct
regulator_dev
*
rdev
,
int
min_uA
,
int
max_uA
)
{
struct
labibb_regulator
*
vreg
=
rdev_get_drvdata
(
rdev
);
struct
regulator_desc
*
desc
=
&
vreg
->
desc
;
struct
labibb_current_limits
*
lim
=
&
vreg
->
uA_limits
;
u32
mask
,
val
;
int
i
,
ret
,
sel
=
-
1
;
if
(
min_uA
<
lim
->
uA_min
||
max_uA
<
lim
->
uA_min
)
return
-
EINVAL
;
for
(
i
=
0
;
i
<
desc
->
n_current_limits
;
i
++
)
{
int
uA_limit
=
(
lim
->
uA_step
*
i
)
+
lim
->
uA_min
;
if
(
max_uA
>=
uA_limit
&&
min_uA
<=
uA_limit
)
sel
=
i
;
}
if
(
sel
<
0
)
return
-
EINVAL
;
/* Current limit setting needs secure access */
ret
=
regmap_write
(
vreg
->
regmap
,
vreg
->
base
+
REG_LABIBB_SEC_ACCESS
,
LABIBB_SEC_UNLOCK_CODE
);
if
(
ret
)
return
ret
;
mask
=
desc
->
csel_mask
|
lim
->
ovr_val
;
mask
|=
LABIBB_CURRENT_LIMIT_EN
;
val
=
(
u32
)
sel
|
lim
->
ovr_val
;
val
|=
LABIBB_CURRENT_LIMIT_EN
;
return
regmap_update_bits
(
vreg
->
regmap
,
desc
->
csel_reg
,
mask
,
val
);
}
static
int
qcom_labibb_get_current_limit
(
struct
regulator_dev
*
rdev
)
{
struct
labibb_regulator
*
vreg
=
rdev_get_drvdata
(
rdev
);
struct
regulator_desc
*
desc
=
&
vreg
->
desc
;
struct
labibb_current_limits
*
lim
=
&
vreg
->
uA_limits
;
unsigned
int
cur_step
;
int
ret
;
ret
=
regmap_read
(
vreg
->
regmap
,
desc
->
csel_reg
,
&
cur_step
);
if
(
ret
)
return
ret
;
cur_step
&=
desc
->
csel_mask
;
return
(
cur_step
*
lim
->
uA_step
)
+
lim
->
uA_min
;
}
static
int
qcom_labibb_set_soft_start
(
struct
regulator_dev
*
rdev
)
{
struct
labibb_regulator
*
vreg
=
rdev_get_drvdata
(
rdev
);
u32
val
=
0
;
if
(
vreg
->
type
==
QCOM_IBB_TYPE
)
val
=
vreg
->
dischg_sel
;
else
val
=
vreg
->
soft_start_sel
;
return
regmap_write
(
rdev
->
regmap
,
rdev
->
desc
->
soft_start_reg
,
val
);
}
static
int
qcom_labibb_get_table_sel
(
const
int
*
table
,
int
sz
,
u32
value
)
{
int
i
;
for
(
i
=
0
;
i
<
sz
;
i
++
)
if
(
table
[
i
]
==
value
)
return
i
;
return
-
EINVAL
;
}
/* IBB discharge resistor values in KOhms */
static
const
int
dischg_resistor_values
[]
=
{
300
,
64
,
32
,
16
};
/* Soft start time in microseconds */
static
const
int
soft_start_values
[]
=
{
200
,
400
,
600
,
800
};
static
int
qcom_labibb_of_parse_cb
(
struct
device_node
*
np
,
const
struct
regulator_desc
*
desc
,
struct
regulator_config
*
config
)
{
struct
labibb_regulator
*
vreg
=
config
->
driver_data
;
u32
dischg_kohms
,
soft_start_time
;
int
ret
;
ret
=
of_property_read_u32
(
np
,
"qcom,discharge-resistor-kohms"
,
&
dischg_kohms
);
if
(
ret
)
dischg_kohms
=
300
;
ret
=
qcom_labibb_get_table_sel
(
dischg_resistor_values
,
ARRAY_SIZE
(
dischg_resistor_values
),
dischg_kohms
);
if
(
ret
<
0
)
return
ret
;
vreg
->
dischg_sel
=
(
u8
)
ret
;
ret
=
of_property_read_u32
(
np
,
"qcom,soft-start-us"
,
&
soft_start_time
);
if
(
ret
)
soft_start_time
=
200
;
ret
=
qcom_labibb_get_table_sel
(
soft_start_values
,
ARRAY_SIZE
(
soft_start_values
),
soft_start_time
);
if
(
ret
<
0
)
return
ret
;
vreg
->
soft_start_sel
=
(
u8
)
ret
;
return
0
;
}
static
const
struct
regulator_ops
qcom_labibb_ops
=
{
.
enable
=
regulator_enable_regmap
,
.
disable
=
regulator_disable_regmap
,
.
is_enabled
=
regulator_is_enabled_regmap
,
.
set_voltage_sel
=
regulator_set_voltage_sel_regmap
,
.
get_voltage_sel
=
regulator_get_voltage_sel_regmap
,
.
list_voltage
=
regulator_list_voltage_linear
,
.
map_voltage
=
regulator_map_voltage_linear
,
.
set_active_discharge
=
regulator_set_active_discharge_regmap
,
.
set_pull_down
=
regulator_set_pull_down_regmap
,
.
set_current_limit
=
qcom_labibb_set_current_limit
,
.
get_current_limit
=
qcom_labibb_get_current_limit
,
.
set_soft_start
=
qcom_labibb_set_soft_start
,
.
set_over_current_protection
=
qcom_labibb_set_ocp
,
};
static
const
struct
regulator_desc
pmi8998_lab_desc
=
{
...
...
@@ -59,10 +686,25 @@ static const struct regulator_desc pmi8998_lab_desc = {
.
enable_val
=
LABIBB_CONTROL_ENABLE
,
.
enable_time
=
LAB_ENABLE_TIME
,
.
poll_enabled_time
=
LABIBB_POLL_ENABLED_TIME
,
.
soft_start_reg
=
(
PMI8998_LAB_REG_BASE
+
REG_LABIBB_SOFT_START_CTL
),
.
pull_down_reg
=
(
PMI8998_LAB_REG_BASE
+
REG_LABIBB_PD_CTL
),
.
pull_down_mask
=
LAB_PD_CTL_MASK
,
.
pull_down_val_on
=
LAB_PD_CTL_STRONG_PULL
,
.
vsel_reg
=
(
PMI8998_LAB_REG_BASE
+
REG_LABIBB_VOLTAGE
),
.
vsel_mask
=
LAB_VOLTAGE_SET_MASK
,
.
apply_reg
=
(
PMI8998_LAB_REG_BASE
+
REG_LABIBB_VOLTAGE
),
.
apply_bit
=
LABIBB_VOLTAGE_OVERRIDE_EN
,
.
csel_reg
=
(
PMI8998_LAB_REG_BASE
+
REG_LABIBB_CURRENT_LIMIT
),
.
csel_mask
=
LAB_CURRENT_LIMIT_MASK
,
.
n_current_limits
=
8
,
.
off_on_delay
=
LABIBB_OFF_ON_DELAY
,
.
owner
=
THIS_MODULE
,
.
type
=
REGULATOR_VOLTAGE
,
.
min_uV
=
4600000
,
.
uV_step
=
100000
,
.
n_voltages
=
16
,
.
ops
=
&
qcom_labibb_ops
,
.
of_parse_cb
=
qcom_labibb_of_parse_cb
,
};
static
const
struct
regulator_desc
pmi8998_ibb_desc
=
{
...
...
@@ -71,10 +713,29 @@ static const struct regulator_desc pmi8998_ibb_desc = {
.
enable_val
=
LABIBB_CONTROL_ENABLE
,
.
enable_time
=
IBB_ENABLE_TIME
,
.
poll_enabled_time
=
LABIBB_POLL_ENABLED_TIME
,
.
soft_start_reg
=
(
PMI8998_IBB_REG_BASE
+
REG_LABIBB_SOFT_START_CTL
),
.
active_discharge_off
=
0
,
.
active_discharge_on
=
IBB_CTL_1_DISCHARGE_EN
,
.
active_discharge_mask
=
IBB_CTL_1_DISCHARGE_EN
,
.
active_discharge_reg
=
(
PMI8998_IBB_REG_BASE
+
REG_IBB_PWRUP_PWRDN_CTL_1
),
.
pull_down_reg
=
(
PMI8998_IBB_REG_BASE
+
REG_LABIBB_PD_CTL
),
.
pull_down_mask
=
IBB_PD_CTL_MASK
,
.
pull_down_val_on
=
IBB_PD_CTL_HALF_STRENGTH
|
IBB_PD_CTL_EN
,
.
vsel_reg
=
(
PMI8998_IBB_REG_BASE
+
REG_LABIBB_VOLTAGE
),
.
vsel_mask
=
IBB_VOLTAGE_SET_MASK
,
.
apply_reg
=
(
PMI8998_IBB_REG_BASE
+
REG_LABIBB_VOLTAGE
),
.
apply_bit
=
LABIBB_VOLTAGE_OVERRIDE_EN
,
.
csel_reg
=
(
PMI8998_IBB_REG_BASE
+
REG_LABIBB_CURRENT_LIMIT
),
.
csel_mask
=
IBB_CURRENT_LIMIT_MASK
,
.
n_current_limits
=
32
,
.
off_on_delay
=
LABIBB_OFF_ON_DELAY
,
.
owner
=
THIS_MODULE
,
.
type
=
REGULATOR_VOLTAGE
,
.
min_uV
=
1400000
,
.
uV_step
=
100000
,
.
n_voltages
=
64
,
.
ops
=
&
qcom_labibb_ops
,
.
of_parse_cb
=
qcom_labibb_of_parse_cb
,
};
static
const
struct
labibb_regulator_data
pmi8998_labibb_data
[]
=
{
...
...
@@ -94,7 +755,7 @@ static int qcom_labibb_regulator_probe(struct platform_device *pdev)
struct
labibb_regulator
*
vreg
;
struct
device
*
dev
=
&
pdev
->
dev
;
struct
regulator_config
cfg
=
{};
struct
device_node
*
reg_node
;
const
struct
of_device_id
*
match
;
const
struct
labibb_regulator_data
*
reg_data
;
struct
regmap
*
reg_regmap
;
...
...
@@ -112,6 +773,8 @@ static int qcom_labibb_regulator_probe(struct platform_device *pdev)
return
-
ENODEV
;
for
(
reg_data
=
match
->
data
;
reg_data
->
name
;
reg_data
++
)
{
char
*
sc_irq_name
;
int
irq
=
0
;
/* Validate if the type of regulator is indeed
* what's mentioned in DT.
...
...
@@ -134,10 +797,61 @@ static int qcom_labibb_regulator_probe(struct platform_device *pdev)
if
(
!
vreg
)
return
-
ENOMEM
;
sc_irq_name
=
devm_kasprintf
(
dev
,
GFP_KERNEL
,
"%s-short-circuit"
,
reg_data
->
name
);
if
(
!
sc_irq_name
)
return
-
ENOMEM
;
reg_node
=
of_get_child_by_name
(
pdev
->
dev
.
of_node
,
reg_data
->
name
);
if
(
!
reg_node
)
return
-
EINVAL
;
/* The Short Circuit interrupt is critical */
irq
=
of_irq_get_byname
(
reg_node
,
"sc-err"
);
if
(
irq
<=
0
)
{
if
(
irq
==
0
)
irq
=
-
EINVAL
;
return
dev_err_probe
(
vreg
->
dev
,
irq
,
"Short-circuit irq not found.
\n
"
);
}
vreg
->
sc_irq
=
irq
;
/* OverCurrent Protection IRQ is optional */
irq
=
of_irq_get_byname
(
reg_node
,
"ocp"
);
vreg
->
ocp_irq
=
irq
;
vreg
->
ocp_irq_count
=
0
;
of_node_put
(
reg_node
);
vreg
->
regmap
=
reg_regmap
;
vreg
->
dev
=
dev
;
vreg
->
base
=
reg_data
->
base
;
vreg
->
type
=
reg_data
->
type
;
INIT_DELAYED_WORK
(
&
vreg
->
sc_recovery_work
,
qcom_labibb_sc_recovery_worker
);
if
(
vreg
->
ocp_irq
>
0
)
INIT_DELAYED_WORK
(
&
vreg
->
ocp_recovery_work
,
qcom_labibb_ocp_recovery_worker
);
switch
(
vreg
->
type
)
{
case
QCOM_LAB_TYPE
:
/* LAB Limits: 200-1600mA */
vreg
->
uA_limits
.
uA_min
=
200000
;
vreg
->
uA_limits
.
uA_step
=
200000
;
vreg
->
uA_limits
.
ovr_val
=
LAB_CURRENT_LIMIT_OVERRIDE_EN
;
break
;
case
QCOM_IBB_TYPE
:
/* IBB Limits: 0-1550mA */
vreg
->
uA_limits
.
uA_min
=
0
;
vreg
->
uA_limits
.
uA_step
=
50000
;
vreg
->
uA_limits
.
ovr_val
=
0
;
/* No override bit */
break
;
default:
return
-
EINVAL
;
}
memcpy
(
&
vreg
->
desc
,
reg_data
->
desc
,
sizeof
(
vreg
->
desc
));
vreg
->
desc
.
of_match
=
reg_data
->
name
;
...
...
@@ -155,6 +869,14 @@ static int qcom_labibb_regulator_probe(struct platform_device *pdev)
reg_data
->
name
,
ret
);
return
PTR_ERR
(
vreg
->
rdev
);
}
ret
=
devm_request_threaded_irq
(
vreg
->
dev
,
vreg
->
sc_irq
,
NULL
,
qcom_labibb_sc_isr
,
IRQF_ONESHOT
|
IRQF_TRIGGER_RISING
,
sc_irq_name
,
vreg
);
if
(
ret
)
return
ret
;
}
return
0
;
...
...
drivers/regulator/qcom-rpmh-regulator.c
View file @
f03e2a72
...
...
@@ -732,6 +732,15 @@ static const struct rpmh_vreg_hw_data pmic5_hfsmps515 = {
.
of_map_mode
=
rpmh_regulator_pmic4_smps_of_map_mode
,
};
static
const
struct
rpmh_vreg_hw_data
pmic5_hfsmps515_1
=
{
.
regulator_type
=
VRM
,
.
ops
=
&
rpmh_regulator_vrm_ops
,
.
voltage_range
=
REGULATOR_LINEAR_RANGE
(
900000
,
0
,
4
,
16000
),
.
n_voltages
=
5
,
.
pmic_mode_map
=
pmic_mode_map_pmic5_smps
,
.
of_map_mode
=
rpmh_regulator_pmic4_smps_of_map_mode
,
};
static
const
struct
rpmh_vreg_hw_data
pmic5_bob
=
{
.
regulator_type
=
VRM
,
.
ops
=
&
rpmh_regulator_vrm_bypass_ops
,
...
...
@@ -932,6 +941,19 @@ static const struct rpmh_vreg_init_data pm8009_vreg_data[] = {
{},
};
static
const
struct
rpmh_vreg_init_data
pm8009_1_vreg_data
[]
=
{
RPMH_VREG
(
"smps1"
,
"smp%s1"
,
&
pmic5_hfsmps510
,
"vdd-s1"
),
RPMH_VREG
(
"smps2"
,
"smp%s2"
,
&
pmic5_hfsmps515_1
,
"vdd-s2"
),
RPMH_VREG
(
"ldo1"
,
"ldo%s1"
,
&
pmic5_nldo
,
"vdd-l1"
),
RPMH_VREG
(
"ldo2"
,
"ldo%s2"
,
&
pmic5_nldo
,
"vdd-l2"
),
RPMH_VREG
(
"ldo3"
,
"ldo%s3"
,
&
pmic5_nldo
,
"vdd-l3"
),
RPMH_VREG
(
"ldo4"
,
"ldo%s4"
,
&
pmic5_nldo
,
"vdd-l4"
),
RPMH_VREG
(
"ldo5"
,
"ldo%s5"
,
&
pmic5_pldo
,
"vdd-l5-l6"
),
RPMH_VREG
(
"ldo6"
,
"ldo%s6"
,
&
pmic5_pldo
,
"vdd-l5-l6"
),
RPMH_VREG
(
"ldo7"
,
"ldo%s6"
,
&
pmic5_pldo_lv
,
"vdd-l7"
),
{},
};
static
const
struct
rpmh_vreg_init_data
pm6150_vreg_data
[]
=
{
RPMH_VREG
(
"smps1"
,
"smp%s1"
,
&
pmic5_ftsmps510
,
"vdd-s1"
),
RPMH_VREG
(
"smps2"
,
"smp%s2"
,
&
pmic5_ftsmps510
,
"vdd-s2"
),
...
...
@@ -1057,6 +1079,10 @@ static const struct of_device_id __maybe_unused rpmh_regulator_match_table[] = {
.
compatible
=
"qcom,pm8009-rpmh-regulators"
,
.
data
=
pm8009_vreg_data
,
},
{
.
compatible
=
"qcom,pm8009-1-rpmh-regulators"
,
.
data
=
pm8009_1_vreg_data
,
},
{
.
compatible
=
"qcom,pm8150-rpmh-regulators"
,
.
data
=
pm8150_vreg_data
,
...
...
@@ -1089,6 +1115,14 @@ static const struct of_device_id __maybe_unused rpmh_regulator_match_table[] = {
.
compatible
=
"qcom,pm6150l-rpmh-regulators"
,
.
data
=
pm6150l_vreg_data
,
},
{
.
compatible
=
"qcom,pmc8180-rpmh-regulators"
,
.
data
=
pm8150_vreg_data
,
},
{
.
compatible
=
"qcom,pmc8180c-rpmh-regulators"
,
.
data
=
pm8150l_vreg_data
,
},
{
.
compatible
=
"qcom,pmx55-rpmh-regulators"
,
.
data
=
pmx55_vreg_data
,
...
...
drivers/regulator/rt4831-regulator.c
0 → 100644
View file @
f03e2a72
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/bitops.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/driver.h>
enum
{
DSV_OUT_VLCM
=
0
,
DSV_OUT_VPOS
,
DSV_OUT_VNEG
,
DSV_OUT_MAX
};
#define RT4831_REG_DSVEN 0x09
#define RT4831_REG_VLCM 0x0c
#define RT4831_REG_VPOS 0x0d
#define RT4831_REG_VNEG 0x0e
#define RT4831_REG_FLAGS 0x0f
#define RT4831_VOLT_MASK GENMASK(5, 0)
#define RT4831_DSVMODE_SHIFT 5
#define RT4831_DSVMODE_MASK GENMASK(7, 5)
#define RT4831_POSADEN_MASK BIT(4)
#define RT4831_NEGADEN_MASK BIT(3)
#define RT4831_POSEN_MASK BIT(2)
#define RT4831_NEGEN_MASK BIT(1)
#define RT4831_OTP_MASK BIT(6)
#define RT4831_LCMOVP_MASK BIT(5)
#define RT4831_VPOSSCP_MASK BIT(3)
#define RT4831_VNEGSCP_MASK BIT(2)
#define DSV_MODE_NORMAL (0x4 << RT4831_DSVMODE_SHIFT)
#define DSV_MODE_BYPASS (0x6 << RT4831_DSVMODE_SHIFT)
#define STEP_UV 50000
#define VLCM_MIN_UV 4000000
#define VLCM_MAX_UV 7150000
#define VLCM_N_VOLTAGES ((VLCM_MAX_UV - VLCM_MIN_UV) / STEP_UV + 1)
#define VPN_MIN_UV 4000000
#define VPN_MAX_UV 6500000
#define VPN_N_VOLTAGES ((VPN_MAX_UV - VPN_MIN_UV) / STEP_UV + 1)
static
int
rt4831_get_error_flags
(
struct
regulator_dev
*
rdev
,
unsigned
int
*
flags
)
{
struct
regmap
*
regmap
=
rdev_get_regmap
(
rdev
);
int
rid
=
rdev_get_id
(
rdev
);
unsigned
int
val
,
events
=
0
;
int
ret
;
ret
=
regmap_read
(
regmap
,
RT4831_REG_FLAGS
,
&
val
);
if
(
ret
)
return
ret
;
if
(
val
&
RT4831_OTP_MASK
)
events
|=
REGULATOR_ERROR_OVER_TEMP
;
if
(
rid
==
DSV_OUT_VLCM
&&
(
val
&
RT4831_LCMOVP_MASK
))
events
|=
REGULATOR_ERROR_OVER_CURRENT
;
if
(
rid
==
DSV_OUT_VPOS
&&
(
val
&
RT4831_VPOSSCP_MASK
))
events
|=
REGULATOR_ERROR_OVER_CURRENT
;
if
(
rid
==
DSV_OUT_VNEG
&&
(
val
&
RT4831_VNEGSCP_MASK
))
events
|=
REGULATOR_ERROR_OVER_CURRENT
;
*
flags
=
events
;
return
0
;
}
static
const
struct
regulator_ops
rt4831_dsvlcm_ops
=
{
.
list_voltage
=
regulator_list_voltage_linear
,
.
set_voltage_sel
=
regulator_set_voltage_sel_regmap
,
.
get_voltage_sel
=
regulator_get_voltage_sel_regmap
,
.
set_bypass
=
regulator_set_bypass_regmap
,
.
get_bypass
=
regulator_get_bypass_regmap
,
.
get_error_flags
=
rt4831_get_error_flags
,
};
static
const
struct
regulator_ops
rt4831_dsvpn_ops
=
{
.
list_voltage
=
regulator_list_voltage_linear
,
.
set_voltage_sel
=
regulator_set_voltage_sel_regmap
,
.
get_voltage_sel
=
regulator_get_voltage_sel_regmap
,
.
enable
=
regulator_enable_regmap
,
.
disable
=
regulator_disable_regmap
,
.
is_enabled
=
regulator_is_enabled_regmap
,
.
set_active_discharge
=
regulator_set_active_discharge_regmap
,
.
get_error_flags
=
rt4831_get_error_flags
,
};
static
const
struct
regulator_desc
rt4831_regulator_descs
[]
=
{
{
.
name
=
"DSVLCM"
,
.
ops
=
&
rt4831_dsvlcm_ops
,
.
of_match
=
of_match_ptr
(
"DSVLCM"
),
.
regulators_node
=
of_match_ptr
(
"regulators"
),
.
type
=
REGULATOR_VOLTAGE
,
.
id
=
DSV_OUT_VLCM
,
.
n_voltages
=
VLCM_N_VOLTAGES
,
.
min_uV
=
VLCM_MIN_UV
,
.
uV_step
=
STEP_UV
,
.
vsel_reg
=
RT4831_REG_VLCM
,
.
vsel_mask
=
RT4831_VOLT_MASK
,
.
bypass_reg
=
RT4831_REG_DSVEN
,
.
bypass_val_on
=
DSV_MODE_BYPASS
,
.
bypass_val_off
=
DSV_MODE_NORMAL
,
},
{
.
name
=
"DSVP"
,
.
ops
=
&
rt4831_dsvpn_ops
,
.
of_match
=
of_match_ptr
(
"DSVP"
),
.
regulators_node
=
of_match_ptr
(
"regulators"
),
.
type
=
REGULATOR_VOLTAGE
,
.
id
=
DSV_OUT_VPOS
,
.
n_voltages
=
VPN_N_VOLTAGES
,
.
min_uV
=
VPN_MIN_UV
,
.
uV_step
=
STEP_UV
,
.
vsel_reg
=
RT4831_REG_VPOS
,
.
vsel_mask
=
RT4831_VOLT_MASK
,
.
enable_reg
=
RT4831_REG_DSVEN
,
.
enable_mask
=
RT4831_POSEN_MASK
,
.
active_discharge_reg
=
RT4831_REG_DSVEN
,
.
active_discharge_mask
=
RT4831_POSADEN_MASK
,
},
{
.
name
=
"DSVN"
,
.
ops
=
&
rt4831_dsvpn_ops
,
.
of_match
=
of_match_ptr
(
"DSVN"
),
.
regulators_node
=
of_match_ptr
(
"regulators"
),
.
type
=
REGULATOR_VOLTAGE
,
.
id
=
DSV_OUT_VNEG
,
.
n_voltages
=
VPN_N_VOLTAGES
,
.
min_uV
=
VPN_MIN_UV
,
.
uV_step
=
STEP_UV
,
.
vsel_reg
=
RT4831_REG_VNEG
,
.
vsel_mask
=
RT4831_VOLT_MASK
,
.
enable_reg
=
RT4831_REG_DSVEN
,
.
enable_mask
=
RT4831_NEGEN_MASK
,
.
active_discharge_reg
=
RT4831_REG_DSVEN
,
.
active_discharge_mask
=
RT4831_NEGADEN_MASK
,
}
};
static
int
rt4831_regulator_probe
(
struct
platform_device
*
pdev
)
{
struct
regmap
*
regmap
;
struct
regulator_dev
*
rdev
;
struct
regulator_config
config
=
{};
int
i
,
ret
;
regmap
=
dev_get_regmap
(
pdev
->
dev
.
parent
,
NULL
);
if
(
IS_ERR
(
regmap
))
{
dev_err
(
&
pdev
->
dev
,
"Failed to init regmap
\n
"
);
return
PTR_ERR
(
regmap
);
}
/* Configure DSV mode to normal by default */
ret
=
regmap_update_bits
(
regmap
,
RT4831_REG_DSVEN
,
RT4831_DSVMODE_MASK
,
DSV_MODE_NORMAL
);
if
(
ret
)
{
dev_err
(
&
pdev
->
dev
,
"Failed to configure dsv mode to normal
\n
"
);
return
ret
;
}
config
.
dev
=
pdev
->
dev
.
parent
;
config
.
regmap
=
regmap
;
for
(
i
=
0
;
i
<
DSV_OUT_MAX
;
i
++
)
{
rdev
=
devm_regulator_register
(
&
pdev
->
dev
,
rt4831_regulator_descs
+
i
,
&
config
);
if
(
IS_ERR
(
rdev
))
{
dev_err
(
&
pdev
->
dev
,
"Failed to register %d regulator
\n
"
,
i
);
return
PTR_ERR
(
rdev
);
}
}
return
0
;
}
static
const
struct
platform_device_id
rt4831_regulator_match
[]
=
{
{
"rt4831-regulator"
,
0
},
{}
};
MODULE_DEVICE_TABLE
(
platform
,
rt4831_regulator_match
);
static
struct
platform_driver
rt4831_regulator_driver
=
{
.
driver
=
{
.
name
=
"rt4831-regulator"
,
},
.
id_table
=
rt4831_regulator_match
,
.
probe
=
rt4831_regulator_probe
,
};
module_platform_driver
(
rt4831_regulator_driver
);
MODULE_AUTHOR
(
"ChiYuan Huang <cy_huang@richtek.com>"
);
MODULE_LICENSE
(
"GPL v2"
);
drivers/regulator/s5m8767.c
View file @
f03e2a72
...
...
@@ -544,14 +544,18 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
rdata
=
devm_kcalloc
(
&
pdev
->
dev
,
pdata
->
num_regulators
,
sizeof
(
*
rdata
),
GFP_KERNEL
);
if
(
!
rdata
)
if
(
!
rdata
)
{
of_node_put
(
regulators_np
);
return
-
ENOMEM
;
}
rmode
=
devm_kcalloc
(
&
pdev
->
dev
,
pdata
->
num_regulators
,
sizeof
(
*
rmode
),
GFP_KERNEL
);
if
(
!
rmode
)
if
(
!
rmode
)
{
of_node_put
(
regulators_np
);
return
-
ENOMEM
;
}
pdata
->
regulators
=
rdata
;
pdata
->
opmode
=
rmode
;
...
...
@@ -573,10 +577,13 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
"s5m8767,pmic-ext-control"
,
GPIOD_OUT_HIGH
|
GPIOD_FLAGS_BIT_NONEXCLUSIVE
,
"s5m8767"
);
if
(
PTR_ERR
(
rdata
->
ext_control_gpiod
)
==
-
ENOENT
)
if
(
PTR_ERR
(
rdata
->
ext_control_gpiod
)
==
-
ENOENT
)
{
rdata
->
ext_control_gpiod
=
NULL
;
else
if
(
IS_ERR
(
rdata
->
ext_control_gpiod
))
}
else
if
(
IS_ERR
(
rdata
->
ext_control_gpiod
))
{
of_node_put
(
reg_np
);
of_node_put
(
regulators_np
);
return
PTR_ERR
(
rdata
->
ext_control_gpiod
);
}
rdata
->
id
=
i
;
rdata
->
initdata
=
of_get_regulator_init_data
(
...
...
include/linux/mfd/abx500/ab8500.h
View file @
f03e2a72
...
...
@@ -368,7 +368,6 @@ struct ab8500 {
int
it_latchhier_num
;
};
struct
ab8500_regulator_platform_data
;
struct
ab8500_codec_platform_data
;
struct
ab8500_sysctrl_platform_data
;
...
...
@@ -376,11 +375,9 @@ struct ab8500_sysctrl_platform_data;
* struct ab8500_platform_data - AB8500 platform data
* @irq_base: start of AB8500 IRQs, AB8500_NR_IRQS will be used
* @init: board-specific initialization after detection of ab8500
* @regulator: machine-specific constraints for regulators
*/
struct
ab8500_platform_data
{
void
(
*
init
)
(
struct
ab8500
*
);
struct
ab8500_regulator_platform_data
*
regulator
;
struct
ab8500_codec_platform_data
*
codec
;
struct
ab8500_sysctrl_platform_data
*
sysctrl
;
};
...
...
include/linux/regulator/ab8500.h
deleted
100644 → 0
View file @
8571bdc2
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) ST-Ericsson SA 2010
*
* Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
* Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
* Daniel Willerud <daniel.willerud@stericsson.com> for ST-Ericsson
*/
#ifndef __LINUX_MFD_AB8500_REGULATOR_H
#define __LINUX_MFD_AB8500_REGULATOR_H
#include <linux/platform_device.h>
/* AB8500 regulators */
enum
ab8500_regulator_id
{
AB8500_LDO_AUX1
,
AB8500_LDO_AUX2
,
AB8500_LDO_AUX3
,
AB8500_LDO_INTCORE
,
AB8500_LDO_TVOUT
,
AB8500_LDO_AUDIO
,
AB8500_LDO_ANAMIC1
,
AB8500_LDO_ANAMIC2
,
AB8500_LDO_DMIC
,
AB8500_LDO_ANA
,
AB8500_NUM_REGULATORS
,
};
/* AB8505 regulators */
enum
ab8505_regulator_id
{
AB8505_LDO_AUX1
,
AB8505_LDO_AUX2
,
AB8505_LDO_AUX3
,
AB8505_LDO_AUX4
,
AB8505_LDO_AUX5
,
AB8505_LDO_AUX6
,
AB8505_LDO_INTCORE
,
AB8505_LDO_ADC
,
AB8505_LDO_AUDIO
,
AB8505_LDO_ANAMIC1
,
AB8505_LDO_ANAMIC2
,
AB8505_LDO_AUX8
,
AB8505_LDO_ANA
,
AB8505_NUM_REGULATORS
,
};
/* AB8500 and AB8505 register initialization */
struct
ab8500_regulator_reg_init
{
int
id
;
u8
mask
;
u8
value
;
};
#define INIT_REGULATOR_REGISTER(_id, _mask, _value) \
{ \
.id = _id, \
.mask = _mask, \
.value = _value, \
}
/* AB8500 registers */
enum
ab8500_regulator_reg
{
AB8500_REGUREQUESTCTRL2
,
AB8500_REGUREQUESTCTRL3
,
AB8500_REGUREQUESTCTRL4
,
AB8500_REGUSYSCLKREQ1HPVALID1
,
AB8500_REGUSYSCLKREQ1HPVALID2
,
AB8500_REGUHWHPREQ1VALID1
,
AB8500_REGUHWHPREQ1VALID2
,
AB8500_REGUHWHPREQ2VALID1
,
AB8500_REGUHWHPREQ2VALID2
,
AB8500_REGUSWHPREQVALID1
,
AB8500_REGUSWHPREQVALID2
,
AB8500_REGUSYSCLKREQVALID1
,
AB8500_REGUSYSCLKREQVALID2
,
AB8500_REGUMISC1
,
AB8500_VAUDIOSUPPLY
,
AB8500_REGUCTRL1VAMIC
,
AB8500_VPLLVANAREGU
,
AB8500_VREFDDR
,
AB8500_EXTSUPPLYREGU
,
AB8500_VAUX12REGU
,
AB8500_VRF1VAUX3REGU
,
AB8500_VAUX1SEL
,
AB8500_VAUX2SEL
,
AB8500_VRF1VAUX3SEL
,
AB8500_REGUCTRL2SPARE
,
AB8500_REGUCTRLDISCH
,
AB8500_REGUCTRLDISCH2
,
AB8500_NUM_REGULATOR_REGISTERS
,
};
/* AB8505 registers */
enum
ab8505_regulator_reg
{
AB8505_REGUREQUESTCTRL1
,
AB8505_REGUREQUESTCTRL2
,
AB8505_REGUREQUESTCTRL3
,
AB8505_REGUREQUESTCTRL4
,
AB8505_REGUSYSCLKREQ1HPVALID1
,
AB8505_REGUSYSCLKREQ1HPVALID2
,
AB8505_REGUHWHPREQ1VALID1
,
AB8505_REGUHWHPREQ1VALID2
,
AB8505_REGUHWHPREQ2VALID1
,
AB8505_REGUHWHPREQ2VALID2
,
AB8505_REGUSWHPREQVALID1
,
AB8505_REGUSWHPREQVALID2
,
AB8505_REGUSYSCLKREQVALID1
,
AB8505_REGUSYSCLKREQVALID2
,
AB8505_REGUVAUX4REQVALID
,
AB8505_REGUMISC1
,
AB8505_VAUDIOSUPPLY
,
AB8505_REGUCTRL1VAMIC
,
AB8505_VSMPSAREGU
,
AB8505_VSMPSBREGU
,
AB8505_VSAFEREGU
,
/* NOTE! PRCMU register */
AB8505_VPLLVANAREGU
,
AB8505_EXTSUPPLYREGU
,
AB8505_VAUX12REGU
,
AB8505_VRF1VAUX3REGU
,
AB8505_VSMPSASEL1
,
AB8505_VSMPSASEL2
,
AB8505_VSMPSASEL3
,
AB8505_VSMPSBSEL1
,
AB8505_VSMPSBSEL2
,
AB8505_VSMPSBSEL3
,
AB8505_VSAFESEL1
,
/* NOTE! PRCMU register */
AB8505_VSAFESEL2
,
/* NOTE! PRCMU register */
AB8505_VSAFESEL3
,
/* NOTE! PRCMU register */
AB8505_VAUX1SEL
,
AB8505_VAUX2SEL
,
AB8505_VRF1VAUX3SEL
,
AB8505_VAUX4REQCTRL
,
AB8505_VAUX4REGU
,
AB8505_VAUX4SEL
,
AB8505_REGUCTRLDISCH
,
AB8505_REGUCTRLDISCH2
,
AB8505_REGUCTRLDISCH3
,
AB8505_CTRLVAUX5
,
AB8505_CTRLVAUX6
,
AB8505_NUM_REGULATOR_REGISTERS
,
};
/* AB8500 external regulators */
struct
ab8500_ext_regulator_cfg
{
bool
hwreq
;
/* requires hw mode or high power mode */
};
enum
ab8500_ext_regulator_id
{
AB8500_EXT_SUPPLY1
,
AB8500_EXT_SUPPLY2
,
AB8500_EXT_SUPPLY3
,
AB8500_NUM_EXT_REGULATORS
,
};
/* AB8500 regulator platform data */
struct
ab8500_regulator_platform_data
{
int
num_reg_init
;
struct
ab8500_regulator_reg_init
*
reg_init
;
int
num_regulator
;
struct
regulator_init_data
*
regulator
;
int
num_ext_regulator
;
struct
regulator_init_data
*
ext_regulator
;
};
#endif
include/linux/regulator/mt6315-regulator.h
0 → 100644
View file @
f03e2a72
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2021 MediaTek Inc.
*/
#ifndef __LINUX_REGULATOR_MT6315_H
#define __LINUX_REGULATOR_MT6315_H
#define MT6315_RP 3
#define MT6315_PP 6
#define MT6315_SP 7
enum
{
MT6315_VBUCK1
=
0
,
MT6315_VBUCK2
,
MT6315_VBUCK3
,
MT6315_VBUCK4
,
MT6315_VBUCK_MAX
,
};
/* Register */
#define MT6315_TOP2_ELR7 0x139
#define MT6315_TOP_TMA_KEY 0x39F
#define MT6315_TOP_TMA_KEY_H 0x3A0
#define MT6315_BUCK_TOP_CON0 0x1440
#define MT6315_BUCK_TOP_CON1 0x1443
#define MT6315_BUCK_TOP_ELR0 0x1449
#define MT6315_BUCK_TOP_ELR2 0x144B
#define MT6315_BUCK_TOP_ELR4 0x144D
#define MT6315_BUCK_TOP_ELR6 0x144F
#define MT6315_VBUCK1_DBG0 0x1499
#define MT6315_VBUCK1_DBG4 0x149D
#define MT6315_VBUCK2_DBG0 0x1519
#define MT6315_VBUCK2_DBG4 0x151D
#define MT6315_VBUCK3_DBG0 0x1599
#define MT6315_VBUCK3_DBG4 0x159D
#define MT6315_VBUCK4_DBG0 0x1619
#define MT6315_VBUCK4_DBG4 0x161D
#define MT6315_BUCK_TOP_4PHASE_ANA_CON42 0x16B1
#define PROTECTION_KEY_H 0x9C
#define PROTECTION_KEY 0xEA
#endif
/* __LINUX_REGULATOR_MT6315_H */
include/linux/regulator/pca9450.h
View file @
f03e2a72
...
...
@@ -216,4 +216,11 @@ enum {
#define IRQ_THERM_105 0x02
#define IRQ_THERM_125 0x01
/* PCA9450_REG_RESET_CTRL bits */
#define WDOG_B_CFG_MASK 0xC0
#define WDOG_B_CFG_NONE 0x00
#define WDOG_B_CFG_WARM 0x40
#define WDOG_B_CFG_COLD_LDO12 0x80
#define WDOG_B_CFG_COLD 0xC0
#endif
/* __LINUX_REG_PCA9450_H__ */
lib/linear_ranges.c
View file @
f03e2a72
...
...
@@ -128,7 +128,7 @@ EXPORT_SYMBOL_GPL(linear_range_get_value_array);
* @selector: address where found selector value is updated
* @found: flag to indicate that given value was in the range
*
* Return selector
which
which range value is closest match for given
* Return selector
for
which range value is closest match for given
* input value. Value is matching if it is equal or smaller than given
* value. If given value is in the range, then @found is set true.
*
...
...
@@ -168,11 +168,11 @@ EXPORT_SYMBOL_GPL(linear_range_get_selector_low);
* @selector: address where found selector value is updated
* @found: flag to indicate that given value was in the range
*
* Scan array of ranges for selector
which
which range value matches given
* Scan array of ranges for selector
for
which range value matches given
* input value. Value is matching if it is equal or smaller than given
* value. If given value is found to be in a range scanning is stopped and
* @found is set true. If a range with values smaller than given value is found
* but the range max is being smaller than given value, then the ranges
* but the range max is being smaller than given value, then the range
'
s
* biggest selector is updated to @selector but scanning ranges is continued
* and @found is set to false.
*
...
...
@@ -209,7 +209,7 @@ EXPORT_SYMBOL_GPL(linear_range_get_selector_low_array);
* @selector: address where found selector value is updated
* @found: flag to indicate that given value was in the range
*
* Return selector
which
which range value is closest match for given
* Return selector
for
which range value is closest match for given
* input value. Value is matching if it is equal or higher than given
* value. If given value is in the range, then @found is set true.
*
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment