Commit 3860cae6 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'regulator-v4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator

Pull regulator updates from Mark Brown:
 "The biggest set of changes in here is the addition of the Qualcomm
  RPMH driver. As well as the regualtor driver itself being quite large
  due to the usual involved Qualcomm regulator stuff there's also some
  code shared with the arm-soc tree, a bus driver required to
  communicate with the hardware that actually winds up being much larger
  than the regulator driver itself and a LLCC driver that was part of
  the same signed tag used with the arm-soc tree.

  Other than that it's a fairly standard and quiet release, highlights
  include:

   - Addition of device links from regulator consumers to their
     regulators, helping the core avoid dependency issues during
     suspend.

   - Support for the entertainingly innovative suspend implementation in
     the BD9571MWV.

   - Support for switch regulators on the PFUZE100, this required two
     goes due to backwards compatibility issues with old DTs that were
     discovered.

   - Support for Freescale PFUZE3001 and SocioNext UniPhier.

   - The aforementioned Qualcomm RPMH driver together with the driver
     changes required to support it"

* tag 'regulator-v4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (52 commits)
  regulator: add QCOM RPMh regulator driver
  regulator: dt-bindings: add QCOM RPMh regulator bindings
  regulator: samsung: Add SPDX license identifiers
  regulator: maxim: Add SPDX license identifiers
  regulator: bd71837: adobt MFD changes to regulator driver
  regulator: tps65217: Fix NULL pointer dereference on probe
  regulator: Add support for CPCAP regulators on Motorola Xoom devices.
  regulator: Add sw2_sw4 voltage table to cpcap regulator.
  regulator: bd9571mwv: Make symbol 'dev_attr_backup_mode' static
  regulator: pfuze100: add support to en-/disable switch regulators
  regulator: pfuze100: add optional disable switch-regulators binding
  soc: qcom: rmtfs-mem: fix memleak in probe error paths
  soc: qcom: llc-slice: Add missing MODULE_LICENSE()
  drivers: qcom: rpmh: fix unwanted error check for get_tcs_of_type()
  drivers: qcom: rpmh-rsc: fix the loop index check in get_req_from_tcs
  firmware: qcom: scm: add a dummy qcom_scm_assign_mem()
  drivers: qcom: rpmh-rsc: Check cmd_db_ready() to help children
  drivers: qcom: rpmh-rsc: allow active requests from wake TCS
  drivers: qcom: rpmh: add support for batch RPMH request
  drivers: qcom: rpmh: allow requests to be sent asynchronously
  ...
parents 010b0e70 d22d5936
What: /sys/bus/i2c/devices/.../bd9571mwv-regulator.*.auto/backup_mode
Date: Jul 2018
KernelVersion: 4.19
Contact: Geert Uytterhoeven <geert+renesas@glider.be>
Description: Read/write the current state of DDR Backup Mode, which controls
if DDR power rails will be kept powered during system suspend.
("on"/"1" = enabled, "off"/"0" = disabled).
Two types of power switches (or control signals) can be used:
A. With a momentary power switch (or pulse signal), DDR
Backup Mode is enabled by default when available, as the
PMIC will be configured only during system suspend.
B. With a toggle power switch (or level signal), the
following steps must be followed exactly:
1. Configure PMIC for backup mode, to change the role of
the accessory power switch from a power switch to a
wake-up switch,
2. Switch accessory power switch off, to prepare for
system suspend, which is a manual step not controlled
by software,
3. Suspend system,
4. Switch accessory power switch on, to resume the
system.
DDR Backup Mode must be explicitly enabled by the user,
to invoke step 1.
See also Documentation/devicetree/bindings/mfd/bd9571mwv.txt.
Users: User space applications for embedded boards equipped with a
BD9571MWV PMIC.
== Introduction==
LLCC (Last Level Cache Controller) provides last level of cache memory in SOC,
that can be shared by multiple clients. Clients here are different cores in the
SOC, the idea is to minimize the local caches at the clients and migrate to
common pool of memory. Cache memory is divided into partitions called slices
which are assigned to clients. Clients can query the slice details, activate
and deactivate them.
Properties:
- compatible:
Usage: required
Value type: <string>
Definition: must be "qcom,sdm845-llcc"
- reg:
Usage: required
Value Type: <prop-encoded-array>
Definition: Start address and the the size of the register region.
Example:
cache-controller@1100000 {
compatible = "qcom,sdm845-llcc";
reg = <0x1100000 0x250000>;
};
......@@ -5,6 +5,7 @@ Requires node properties:
- "compatible" value one of:
"motorola,cpcap-regulator"
"motorola,mapphone-cpcap-regulator"
"motorola,xoom-cpcap-regulator"
Required regulator properties:
- "regulator-name"
......
PFUZE100 family of regulators
Required properties:
- compatible: "fsl,pfuze100", "fsl,pfuze200", "fsl,pfuze3000"
- compatible: "fsl,pfuze100", "fsl,pfuze200", "fsl,pfuze3000", "fsl,pfuze3001"
- reg: I2C slave address
Optional properties:
- fsl,pfuze-support-disable-sw: Boolean, if present disable all unused switch
regulators to save power consumption. Attention, ensure that all important
regulators (e.g. DDR ref, DDR supply) has set the "regulator-always-on"
property. If not present, the switched regualtors are always on and can't be
disabled. This binding is a workaround to keep backward compatibility with
old dtb's which rely on the fact that the switched regulators are always on
and don't mark them explicit as "regulator-always-on".
Required child node:
- regulators: This is the list of child nodes that specify the regulator
initialization data for defined regulators. Please refer to below doc
......@@ -16,6 +25,8 @@ Required child node:
sw1ab,sw2,sw3a,sw3b,swbst,vsnvs,vrefddr,vgen1~vgen6,coin
--PFUZE3000
sw1a,sw1b,sw2,sw3,swbst,vsnvs,vrefddr,vldo1,vldo2,vccsd,v33,vldo3,vldo4
--PFUZE3001
sw1,sw2,sw3,vsnvs,vldo1,vldo2,vccsd,v33,vldo3,vldo4
Each regulator is defined using the standard binding for regulators.
......@@ -303,3 +314,76 @@ Example 3: PFUZE3000
};
};
};
Example 4: PFUZE 3001
pfuze3001: pmic@8 {
compatible = "fsl,pfuze3001";
reg = <0x08>;
regulators {
sw1_reg: sw1 {
regulator-min-microvolt = <700000>;
regulator-max-microvolt = <3300000>;
regulator-boot-on;
regulator-always-on;
};
sw2_reg: sw2 {
regulator-min-microvolt = <1500000>;
regulator-max-microvolt = <3300000>;
regulator-boot-on;
regulator-always-on;
};
sw3_reg: sw3 {
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <1650000>;
regulator-boot-on;
regulator-always-on;
};
snvs_reg: vsnvs {
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <3000000>;
regulator-boot-on;
regulator-always-on;
};
vgen1_reg: vldo1 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
};
vgen2_reg: vldo2 {
regulator-min-microvolt = <800000>;
regulator-max-microvolt = <1550000>;
regulator-always-on;
};
vgen3_reg: vccsd {
regulator-min-microvolt = <2850000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
};
vgen4_reg: v33 {
regulator-min-microvolt = <2850000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
};
vgen5_reg: vldo3 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
};
vgen6_reg: vldo4 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
};
};
};
Qualcomm Technologies, Inc. RPMh Regulators
rpmh-regulator devices support PMIC regulator management via the Voltage
Regulator Manager (VRM) and Oscillator Buffer (XOB) RPMh accelerators. The APPS
processor communicates with these hardware blocks via a Resource State
Coordinator (RSC) using command packets. The VRM allows changing three
parameters for a given regulator: enable state, output voltage, and operating
mode. The XOB allows changing only a single parameter for a given regulator:
its enable state. Despite its name, the XOB is capable of controlling the
enable state of any PMIC peripheral. It is used for clock buffers, low-voltage
switches, and LDO/SMPS regulators which have a fixed voltage and mode.
=======================
Required Node Structure
=======================
RPMh regulators must be described in two levels of device nodes. The first
level describes the PMIC containing the regulators and must reside within an
RPMh device node. The second level describes each regulator within the PMIC
which is to be used on the board. Each of these regulators maps to a single
RPMh resource.
The names used for regulator nodes must match those supported by a given PMIC.
Supported regulator node names:
PM8998: smps1 - smps13, ldo1 - ldo28, lvs1 - lvs2
PMI8998: bob
PM8005: smps1 - smps4
========================
First Level Nodes - PMIC
========================
- compatible
Usage: required
Value type: <string>
Definition: Must be one of: "qcom,pm8998-rpmh-regulators",
"qcom,pmi8998-rpmh-regulators" or
"qcom,pm8005-rpmh-regulators".
- qcom,pmic-id
Usage: required
Value type: <string>
Definition: RPMh resource name suffix used for the regulators found on
this PMIC. Typical values: "a", "b", "c", "d", "e", "f".
- vdd-s1-supply
- vdd-s2-supply
- vdd-s3-supply
- vdd-s4-supply
Usage: optional (PM8998 and PM8005 only)
Value type: <phandle>
Definition: phandle of the parent supply regulator of one or more of the
regulators for this PMIC.
- vdd-s5-supply
- vdd-s6-supply
- vdd-s7-supply
- vdd-s8-supply
- vdd-s9-supply
- vdd-s10-supply
- vdd-s11-supply
- vdd-s12-supply
- vdd-s13-supply
- vdd-l1-l27-supply
- vdd-l2-l8-l17-supply
- vdd-l3-l11-supply
- vdd-l4-l5-supply
- vdd-l6-supply
- vdd-l7-l12-l14-l15-supply
- vdd-l9-supply
- vdd-l10-l23-l25-supply
- vdd-l13-l19-l21-supply
- vdd-l16-l28-supply
- vdd-l18-l22-supply
- vdd-l20-l24-supply
- vdd-l26-supply
- vin-lvs-1-2-supply
Usage: optional (PM8998 only)
Value type: <phandle>
Definition: phandle of the parent supply regulator of one or more of the
regulators for this PMIC.
- vdd-bob-supply
Usage: optional (PMI8998 only)
Value type: <phandle>
Definition: BOB regulator parent supply phandle
===============================
Second Level Nodes - Regulators
===============================
- qcom,always-wait-for-ack
Usage: optional
Value type: <empty>
Definition: Boolean flag which indicates that the application processor
must wait for an ACK or a NACK from RPMh for every request
sent for this regulator including those which are for a
strictly lower power state.
Other properties defined in Documentation/devicetree/bindings/regulator.txt
may also be used. regulator-initial-mode and regulator-allowed-modes may be
specified for VRM regulators using mode values from
include/dt-bindings/regulator/qcom,rpmh-regulator.h. regulator-allow-bypass
may be specified for BOB type regulators managed via VRM.
regulator-allow-set-load may be specified for LDO type regulators managed via
VRM.
========
Examples
========
#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
&apps_rsc {
pm8998-rpmh-regulators {
compatible = "qcom,pm8998-rpmh-regulators";
qcom,pmic-id = "a";
vdd-l7-l12-l14-l15-supply = <&pm8998_s5>;
smps2 {
regulator-min-microvolt = <1100000>;
regulator-max-microvolt = <1100000>;
};
pm8998_s5: smps5 {
regulator-min-microvolt = <1904000>;
regulator-max-microvolt = <2040000>;
};
ldo7 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
regulator-allowed-modes =
<RPMH_REGULATOR_MODE_LPM
RPMH_REGULATOR_MODE_HPM>;
regulator-allow-set-load;
};
lvs1 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
};
pmi8998-rpmh-regulators {
compatible = "qcom,pmi8998-rpmh-regulators";
qcom,pmic-id = "b";
bob {
regulator-min-microvolt = <3312000>;
regulator-max-microvolt = <3600000>;
regulator-allowed-modes =
<RPMH_REGULATOR_MODE_AUTO
RPMH_REGULATOR_MODE_HPM>;
regulator-initial-mode = <RPMH_REGULATOR_MODE_AUTO>;
};
};
};
ROHM BD71837 Power Management Integrated Circuit (PMIC) regulator bindings
BD71837MWV is a programmable Power Management
IC (PMIC) for powering single-core, dual-core, and
quad-core SoC’s such as NXP-i.MX 8M. It is optimized
for low BOM cost and compact solution footprint. It
integrates 8 Buck regulators and 7 LDO’s to provide all
the power rails required by the SoC and the commonly
used peripherals.
Required properties:
- regulator-name: should be "buck1", ..., "buck8" and "ldo1", ..., "ldo7"
......
Socionext UniPhier Regulator Controller
This describes the devicetree bindings for regulator controller implemented
on Socionext UniPhier SoCs.
USB3 Controller
---------------
This regulator controls VBUS and belongs to USB3 glue layer. Before using
the regulator, it is necessary to control the clocks and resets to enable
this layer. These clocks and resets should be described in each property.
Required properties:
- compatible: Should be
"socionext,uniphier-pro4-usb3-regulator" - for Pro4 SoC
"socionext,uniphier-pxs2-usb3-regulator" - for PXs2 SoC
"socionext,uniphier-ld20-usb3-regulator" - for LD20 SoC
"socionext,uniphier-pxs3-usb3-regulator" - for PXs3 SoC
- reg: Specifies offset and length of the register set for the device.
- clocks: A list of phandles to the clock gate for USB3 glue layer.
According to the clock-names, appropriate clocks are required.
- clock-names: Should contain
"gio", "link" - for Pro4 SoC
"link" - for others
- resets: A list of phandles to the reset control for USB3 glue layer.
According to the reset-names, appropriate resets are required.
- reset-names: Should contain
"gio", "link" - for Pro4 SoC
"link" - for others
See Documentation/devicetree/bindings/regulator/regulator.txt
for more details about the regulator properties.
Example:
usb-glue@65b00000 {
compatible = "socionext,uniphier-ld20-dwc3-glue",
"simple-mfd";
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 0x65b00000 0x400>;
usb_vbus0: regulators@100 {
compatible = "socionext,uniphier-ld20-usb3-regulator";
reg = <0x100 0x10>;
clock-names = "link";
clocks = <&sys_clk 14>;
reset-names = "link";
resets = <&sys_rst 14>;
};
phy {
...
phy-supply = <&usb_vbus0>;
};
...
};
RPMH RSC:
------------
Resource Power Manager Hardened (RPMH) is the mechanism for communicating with
the hardened resource accelerators on Qualcomm SoCs. Requests to the resources
can be written to the Trigger Command Set (TCS) registers and using a (addr,
val) pair and triggered. Messages in the TCS are then sent in sequence over an
internal bus.
The hardware block (Direct Resource Voter or DRV) is a part of the h/w entity
(Resource State Coordinator a.k.a RSC) that can handle multiple sleep and
active/wake resource requests. Multiple such DRVs can exist in a SoC and can
be written to from Linux. The structure of each DRV follows the same template
with a few variations that are captured by the properties here.
A TCS may be triggered from Linux or triggered by the F/W after all the CPUs
have powered off to facilitate idle power saving. TCS could be classified as -
ACTIVE /* Triggered by Linux */
SLEEP /* Triggered by F/W */
WAKE /* Triggered by F/W */
CONTROL /* Triggered by F/W */
The order in which they are described in the DT, should match the hardware
configuration.
Requests can be made for the state of a resource, when the subsystem is active
or idle. When all subsystems like Modem, GPU, CPU are idle, the resource state
will be an aggregate of the sleep votes from each of those subsystems. Clients
may request a sleep value for their shared resources in addition to the active
mode requests.
Properties:
- compatible:
Usage: required
Value type: <string>
Definition: Should be "qcom,rpmh-rsc".
- reg:
Usage: required
Value type: <prop-encoded-array>
Definition: The first register specifies the base address of the
DRV(s). The number of DRVs in the dependent on the RSC.
The tcs-offset specifies the start address of the
TCS in the DRVs.
- reg-names:
Usage: required
Value type: <string>
Definition: Maps the register specified in the reg property. Must be
"drv-0", "drv-1", "drv-2" etc and "tcs-offset". The
- interrupts:
Usage: required
Value type: <prop-encoded-interrupt>
Definition: The interrupt that trips when a message complete/response
is received for this DRV from the accelerators.
- qcom,drv-id:
Usage: required
Value type: <u32>
Definition: The id of the DRV in the RSC block that will be used by
this controller.
- qcom,tcs-config:
Usage: required
Value type: <prop-encoded-array>
Definition: The tuple defining the configuration of TCS.
Must have 2 cells which describe each TCS type.
<type number_of_tcs>.
The order of the TCS must match the hardware
configuration.
- Cell #1 (TCS Type): TCS types to be specified -
ACTIVE_TCS
SLEEP_TCS
WAKE_TCS
CONTROL_TCS
- Cell #2 (Number of TCS): <u32>
- label:
Usage: optional
Value type: <string>
Definition: Name for the RSC. The name would be used in trace logs.
Drivers that want to use the RSC to communicate with RPMH must specify their
bindings as child nodes of the RSC controllers they wish to communicate with.
Example 1:
For a TCS whose RSC base address is is 0x179C0000 and is at a DRV id of 2, the
register offsets for DRV2 start at 0D00, the register calculations are like
this -
DRV0: 0x179C0000
DRV2: 0x179C0000 + 0x10000 = 0x179D0000
DRV2: 0x179C0000 + 0x10000 * 2 = 0x179E0000
TCS-OFFSET: 0xD00
apps_rsc: rsc@179c0000 {
label = "apps_rsc";
compatible = "qcom,rpmh-rsc";
reg = <0x179c0000 0x10000>,
<0x179d0000 0x10000>,
<0x179e0000 0x10000>;
reg-names = "drv-0", "drv-1", "drv-2";
interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
qcom,tcs-offset = <0xd00>;
qcom,drv-id = <2>;
qcom,tcs-config = <ACTIVE_TCS 2>,
<SLEEP_TCS 3>,
<WAKE_TCS 3>,
<CONTROL_TCS 1>;
};
Example 2:
For a TCS whose RSC base address is 0xAF20000 and is at DRV id of 0, the
register offsets for DRV0 start at 01C00, the register calculations are like
this -
DRV0: 0xAF20000
TCS-OFFSET: 0x1C00
disp_rsc: rsc@af20000 {
label = "disp_rsc";
compatible = "qcom,rpmh-rsc";
reg = <0xaf20000 0x10000>;
reg-names = "drv-0";
interrupts = <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>;
qcom,tcs-offset = <0x1c00>;
qcom,drv-id = <0>;
qcom,tcs-config = <ACTIVE_TCS 0>,
<SLEEP_TCS 1>,
<WAKE_TCS 1>,
<CONTROL_TCS 0>;
};
......@@ -372,6 +372,36 @@ void device_link_del(struct device_link *link)
}
EXPORT_SYMBOL_GPL(device_link_del);
/**
* device_link_remove - remove a link between two devices.
* @consumer: Consumer end of the link.
* @supplier: Supplier end of the link.
*
* The caller must ensure proper synchronization of this function with runtime
* PM.
*/
void device_link_remove(void *consumer, struct device *supplier)
{
struct device_link *link;
if (WARN_ON(consumer == supplier))
return;
device_links_write_lock();
device_pm_lock();
list_for_each_entry(link, &supplier->links.consumers, s_node) {
if (link->consumer == consumer) {
kref_put(&link->kref, __device_link_del);
break;
}
}
device_pm_unlock();
device_links_write_unlock();
}
EXPORT_SYMBOL_GPL(device_link_remove);
static void device_links_missing_supplier(struct device *dev)
{
struct device_link *link;
......
......@@ -180,9 +180,9 @@ config REGULATOR_BCM590XX
BCM590xx PMUs. This will enable support for the software
controllable LDO/Switching regulators.
config REGULATOR_BD71837
config REGULATOR_BD718XX
tristate "ROHM BD71837 Power Regulator"
depends on MFD_BD71837
depends on MFD_ROHM_BD718XX
help
This driver supports voltage regulators on ROHM BD71837 PMIC.
This will enable support for the software controllable buck
......@@ -633,12 +633,12 @@ config REGULATOR_PCF50633
on PCF50633
config REGULATOR_PFUZE100
tristate "Freescale PFUZE100/200/3000 regulator driver"
tristate "Freescale PFUZE100/200/3000/3001 regulator driver"
depends on I2C
select REGMAP_I2C
help
Say y here to support the regulators found on the Freescale
PFUZE100/200/3000 PMIC.
PFUZE100/200/3000/3001 PMIC.
config REGULATOR_PV88060
tristate "Powerventure Semiconductor PV88060 regulator"
......@@ -682,6 +682,15 @@ config REGULATOR_QCOM_RPM
Qualcomm RPM as a module. The module will be named
"qcom_rpm-regulator".
config REGULATOR_QCOM_RPMH
tristate "Qualcomm Technologies, Inc. RPMh regulator driver"
depends on QCOM_RPMH || COMPILE_TEST
help
This driver supports control of PMIC regulators via the RPMh hardware
block found on Qualcomm Technologies Inc. SoCs. RPMh regulator
control allows for voting on regulator state between multiple
processors within the SoC.
config REGULATOR_QCOM_SMD_RPM
tristate "Qualcomm SMD based RPM regulator driver"
depends on QCOM_SMD_RPM
......@@ -950,6 +959,14 @@ config REGULATOR_TWL4030
This driver supports the voltage regulators provided by
this family of companion chips.
config REGULATOR_UNIPHIER
tristate "UniPhier regulator driver"
depends on ARCH_UNIPHIER || COMPILE_TEST
depends on OF && MFD_SYSCON
default ARCH_UNIPHIER
help
Support for regulators implemented on Socionext UniPhier SoCs.
config REGULATOR_VCTRL
tristate "Voltage controlled regulators"
depends on OF
......
......@@ -27,7 +27,7 @@ obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o
obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o
obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o
obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o
obj-$(CONFIG_REGULATOR_BD71837) += bd71837-regulator.o
obj-$(CONFIG_REGULATOR_BD718XX) += bd71837-regulator.o
obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o
obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o
......@@ -78,6 +78,7 @@ obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o
obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o
obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o
obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
......@@ -118,6 +119,7 @@ obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o
obj-$(CONFIG_REGULATOR_TPS80031) += tps80031-regulator.o
obj-$(CONFIG_REGULATOR_TPS65132) += tps65132-regulator.o
obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o twl6030-regulator.o
obj-$(CONFIG_REGULATOR_UNIPHIER) += uniphier-regulator.o
obj-$(CONFIG_REGULATOR_VCTRL) += vctrl-regulator.o
obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress-regulator.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
......
......@@ -36,6 +36,8 @@ struct arizona_ldo1 {
struct regulator_consumer_supply supply;
struct regulator_init_data init_data;
struct gpio_desc *ena_gpiod;
};
static int arizona_ldo1_hc_list_voltage(struct regulator_dev *rdev,
......@@ -253,12 +255,17 @@ static int arizona_ldo1_common_init(struct platform_device *pdev,
}
}
/* We assume that high output = regulator off */
config.ena_gpiod = devm_gpiod_get_optional(&pdev->dev, "wlf,ldoena",
GPIOD_OUT_HIGH);
/* We assume that high output = regulator off
* Don't use devm, since we need to get against the parent device
* so clean up would happen at the wrong time
*/
config.ena_gpiod = gpiod_get_optional(parent_dev, "wlf,ldoena",
GPIOD_OUT_LOW);
if (IS_ERR(config.ena_gpiod))
return PTR_ERR(config.ena_gpiod);
ldo1->ena_gpiod = config.ena_gpiod;
if (pdata->init_data)
config.init_data = pdata->init_data;
else
......@@ -276,6 +283,9 @@ static int arizona_ldo1_common_init(struct platform_device *pdev,
of_node_put(config.of_node);
if (IS_ERR(ldo1->regulator)) {
if (config.ena_gpiod)
gpiod_put(config.ena_gpiod);
ret = PTR_ERR(ldo1->regulator);
dev_err(&pdev->dev, "Failed to register LDO1 supply: %d\n",
ret);
......@@ -334,8 +344,19 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
return ret;
}
static int arizona_ldo1_remove(struct platform_device *pdev)
{
struct arizona_ldo1 *ldo1 = platform_get_drvdata(pdev);
if (ldo1->ena_gpiod)
gpiod_put(ldo1->ena_gpiod);
return 0;
}
static struct platform_driver arizona_ldo1_driver = {
.probe = arizona_ldo1_probe,
.remove = arizona_ldo1_remove,
.driver = {
.name = "arizona-ldo1",
},
......
......@@ -2,19 +2,18 @@
// Copyright (C) 2018 ROHM Semiconductors
// bd71837-regulator.c ROHM BD71837MWV regulator driver
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mfd/rohm-bd718x7.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/mfd/bd71837.h>
#include <linux/regulator/of_regulator.h>
#include <linux/slab.h>
struct bd71837_pmic {
struct regulator_desc descs[BD71837_REGULATOR_CNT];
......@@ -39,7 +38,7 @@ static int bd71837_buck1234_set_ramp_delay(struct regulator_dev *rdev,
int id = rdev->desc->id;
unsigned int ramp_value = BUCK_RAMPRATE_10P00MV;
dev_dbg(&(pmic->pdev->dev), "Buck[%d] Set Ramp = %d\n", id + 1,
dev_dbg(&pmic->pdev->dev, "Buck[%d] Set Ramp = %d\n", id + 1,
ramp_delay);
switch (ramp_delay) {
case 1 ... 1250:
......@@ -73,14 +72,10 @@ static int bd71837_buck1234_set_ramp_delay(struct regulator_dev *rdev,
static int bd71837_set_voltage_sel_restricted(struct regulator_dev *rdev,
unsigned int sel)
{
int ret;
ret = regulator_is_enabled_regmap(rdev);
if (!ret)
ret = regulator_set_voltage_sel_regmap(rdev, sel);
else if (ret == 1)
ret = -EBUSY;
return ret;
if (regulator_is_enabled_regmap(rdev))
return -EBUSY;
return regulator_set_voltage_sel_regmap(rdev, sel);
}
static struct regulator_ops bd71837_ldo_regulator_ops = {
......@@ -195,7 +190,7 @@ static const struct regulator_linear_range bd71837_ldo1_voltage_ranges[] = {
* LDO2
* 0.8 or 0.9V
*/
const unsigned int ldo_2_volts[] = {
static const unsigned int ldo_2_volts[] = {
900000, 800000
};
......@@ -495,7 +490,6 @@ struct reg_init {
static int bd71837_probe(struct platform_device *pdev)
{
struct bd71837_pmic *pmic;
struct bd71837_board *pdata;
struct regulator_config config = { 0 };
struct reg_init pmic_regulator_inits[] = {
{
......@@ -548,8 +542,7 @@ static int bd71837_probe(struct platform_device *pdev)
int i, err;
pmic = devm_kzalloc(&pdev->dev, sizeof(struct bd71837_pmic),
GFP_KERNEL);
pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
if (!pmic)
return -ENOMEM;
......@@ -564,7 +557,6 @@ static int bd71837_probe(struct platform_device *pdev)
goto err;
}
platform_set_drvdata(pdev, pmic);
pdata = dev_get_platdata(pmic->mfd->dev);
/* Register LOCK release */
err = regmap_update_bits(pmic->mfd->regmap, BD71837_REG_REGLOCK,
......@@ -573,8 +565,8 @@ static int bd71837_probe(struct platform_device *pdev)
dev_err(&pmic->pdev->dev, "Failed to unlock PMIC (%d)\n", err);
goto err;
} else {
dev_dbg(&pmic->pdev->dev, "%s: Unlocked lock register 0x%x\n",
__func__, BD71837_REG_REGLOCK);
dev_dbg(&pmic->pdev->dev, "Unlocked lock register 0x%x\n",
BD71837_REG_REGLOCK);
}
for (i = 0; i < ARRAY_SIZE(pmic_regulator_inits); i++) {
......@@ -584,9 +576,6 @@ static int bd71837_probe(struct platform_device *pdev)
desc = &pmic->descs[i];
if (pdata)
config.init_data = pdata->init_data[i];
config.dev = pdev->dev.parent;
config.driver_data = pmic;
config.regmap = pmic->mfd->regmap;
......@@ -619,8 +608,6 @@ static int bd71837_probe(struct platform_device *pdev)
pmic->rdev[i] = rdev;
}
return 0;
err:
return err;
}
......@@ -628,7 +615,6 @@ static int bd71837_probe(struct platform_device *pdev)
static struct platform_driver bd71837_regulator = {
.driver = {
.name = "bd71837-pmic",
.owner = THIS_MODULE,
},
.probe = bd71837_probe,
};
......
......@@ -30,6 +30,7 @@ struct bd9571mwv_reg {
/* DDR Backup Power */
u8 bkup_mode_cnt_keepon; /* from "rohm,ddr-backup-power" */
u8 bkup_mode_cnt_saved;
bool bkup_mode_enabled;
/* Power switch type */
bool rstbmode_level;
......@@ -171,13 +172,60 @@ static int bd9571mwv_bkup_mode_write(struct bd9571mwv *bd, unsigned int mode)
return 0;
}
static ssize_t backup_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct bd9571mwv_reg *bdreg = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", bdreg->bkup_mode_enabled ? "on" : "off");
}
static ssize_t backup_mode_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct bd9571mwv_reg *bdreg = dev_get_drvdata(dev);
unsigned int mode;
int ret;
if (!count)
return 0;
ret = kstrtobool(buf, &bdreg->bkup_mode_enabled);
if (ret)
return ret;
if (!bdreg->rstbmode_level)
return count;
/*
* Configure DDR Backup Mode, to change the role of the accessory power
* switch from a power switch to a wake-up switch, or vice versa
*/
ret = bd9571mwv_bkup_mode_read(bdreg->bd, &mode);
if (ret)
return ret;
mode &= ~BD9571MWV_BKUP_MODE_CNT_KEEPON_MASK;
if (bdreg->bkup_mode_enabled)
mode |= bdreg->bkup_mode_cnt_keepon;
ret = bd9571mwv_bkup_mode_write(bdreg->bd, mode);
if (ret)
return ret;
return count;
}
static DEVICE_ATTR_RW(backup_mode);
static int bd9571mwv_suspend(struct device *dev)
{
struct bd9571mwv_reg *bdreg = dev_get_drvdata(dev);
unsigned int mode;
int ret;
if (!device_may_wakeup(dev))
if (!bdreg->bkup_mode_enabled)
return 0;
/* Save DDR Backup Mode */
......@@ -204,7 +252,7 @@ static int bd9571mwv_resume(struct device *dev)
{
struct bd9571mwv_reg *bdreg = dev_get_drvdata(dev);
if (!device_may_wakeup(dev))
if (!bdreg->bkup_mode_enabled)
return 0;
/* Restore DDR Backup Mode */
......@@ -215,9 +263,15 @@ static const struct dev_pm_ops bd9571mwv_pm = {
SET_SYSTEM_SLEEP_PM_OPS(bd9571mwv_suspend, bd9571mwv_resume)
};
static int bd9571mwv_regulator_remove(struct platform_device *pdev)
{
device_remove_file(&pdev->dev, &dev_attr_backup_mode);
return 0;
}
#define DEV_PM_OPS &bd9571mwv_pm
#else
#define DEV_PM_OPS NULL
#define bd9571mwv_regulator_remove NULL
#endif /* CONFIG_PM_SLEEP */
static int bd9571mwv_regulator_probe(struct platform_device *pdev)
......@@ -270,14 +324,21 @@ static int bd9571mwv_regulator_probe(struct platform_device *pdev)
return -EINVAL;
}
#ifdef CONFIG_PM_SLEEP
if (bdreg->bkup_mode_cnt_keepon) {
device_set_wakeup_capable(&pdev->dev, true);
int ret;
/*
* Wakeup is enabled by default in pulse mode, but needs
* Backup mode is enabled by default in pulse mode, but needs
* explicit user setup in level mode.
*/
device_set_wakeup_enable(&pdev->dev, bdreg->rstbmode_pulse);
bdreg->bkup_mode_enabled = bdreg->rstbmode_pulse;
ret = device_create_file(&pdev->dev, &dev_attr_backup_mode);
if (ret)
return ret;
}
#endif /* CONFIG_PM_SLEEP */
return 0;
}
......@@ -294,6 +355,7 @@ static struct platform_driver bd9571mwv_regulator_driver = {
.pm = DEV_PM_OPS,
},
.probe = bd9571mwv_regulator_probe,
.remove = bd9571mwv_regulator_remove,
.id_table = bd9571mwv_regulator_id_table,
};
module_platform_driver(bd9571mwv_regulator_driver);
......
......@@ -1740,6 +1740,8 @@ struct regulator *_regulator_get(struct device *dev, const char *id,
rdev->use_count = 0;
}
device_link_add(dev, &rdev->dev, DL_FLAG_STATELESS);
return regulator;
}
......@@ -1829,9 +1831,21 @@ static void _regulator_put(struct regulator *regulator)
debugfs_remove_recursive(regulator->debugfs);
/* remove any sysfs entries */
if (regulator->dev)
if (regulator->dev) {
int count = 0;
struct regulator *r;
list_for_each_entry(r, &rdev->consumer_list, list)
if (r->dev == regulator->dev)
count++;
if (count == 1)
device_link_remove(regulator->dev, &rdev->dev);
/* remove any sysfs entries */
sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name);
}
regulator_lock(rdev);
list_del(&regulator->list);
......@@ -4441,7 +4455,7 @@ void regulator_unregister(struct regulator_dev *rdev)
EXPORT_SYMBOL_GPL(regulator_unregister);
#ifdef CONFIG_SUSPEND
static int _regulator_suspend_late(struct device *dev, void *data)
static int _regulator_suspend(struct device *dev, void *data)
{
struct regulator_dev *rdev = dev_to_rdev(dev);
suspend_state_t *state = data;
......@@ -4455,20 +4469,20 @@ static int _regulator_suspend_late(struct device *dev, void *data)
}
/**
* regulator_suspend_late - prepare regulators for system wide suspend
* regulator_suspend - prepare regulators for system wide suspend
* @state: system suspend state
*
* Configure each regulator with it's suspend operating parameters for state.
*/
static int regulator_suspend_late(struct device *dev)
static int regulator_suspend(struct device *dev)
{
suspend_state_t state = pm_suspend_target_state;
return class_for_each_device(&regulator_class, NULL, &state,
_regulator_suspend_late);
_regulator_suspend);
}
static int _regulator_resume_early(struct device *dev, void *data)
static int _regulator_resume(struct device *dev, void *data)
{
int ret = 0;
struct regulator_dev *rdev = dev_to_rdev(dev);
......@@ -4481,35 +4495,35 @@ static int _regulator_resume_early(struct device *dev, void *data)
regulator_lock(rdev);
if (rdev->desc->ops->resume_early &&
if (rdev->desc->ops->resume &&
(rstate->enabled == ENABLE_IN_SUSPEND ||
rstate->enabled == DISABLE_IN_SUSPEND))
ret = rdev->desc->ops->resume_early(rdev);
ret = rdev->desc->ops->resume(rdev);
regulator_unlock(rdev);
return ret;
}
static int regulator_resume_early(struct device *dev)
static int regulator_resume(struct device *dev)
{
suspend_state_t state = pm_suspend_target_state;
return class_for_each_device(&regulator_class, NULL, &state,
_regulator_resume_early);
_regulator_resume);
}
#else /* !CONFIG_SUSPEND */
#define regulator_suspend_late NULL
#define regulator_resume_early NULL
#define regulator_suspend NULL
#define regulator_resume NULL
#endif /* !CONFIG_SUSPEND */
#ifdef CONFIG_PM
static const struct dev_pm_ops __maybe_unused regulator_pm_ops = {
.suspend_late = regulator_suspend_late,
.resume_early = regulator_resume_early,
.suspend = regulator_suspend,
.resume = regulator_resume,
};
#endif
......
......@@ -271,6 +271,29 @@ static struct regulator_ops cpcap_regulator_ops = {
};
static const unsigned int unknown_val_tbl[] = { 0, };
static const unsigned int sw2_sw4_val_tbl[] = { 612500, 625000, 637500,
650000, 662500, 675000,
687500, 700000, 712500,
725000, 737500, 750000,
762500, 775000, 787500,
800000, 812500, 825000,
837500, 850000, 862500,
875000, 887500, 900000,
912500, 925000, 937500,
950000, 962500, 975000,
987500, 1000000, 1012500,
1025000, 1037500, 1050000,
1062500, 1075000, 1087500,
1100000, 1112500, 1125000,
1137500, 1150000, 1162500,
1175000, 1187500, 1200000,
1212500, 1225000, 1237500,
1250000, 1262500, 1275000,
1287500, 1300000, 1312500,
1325000, 1337500, 1350000,
1362500, 1375000, 1387500,
1400000, 1412500, 1425000,
1437500, 1450000, 1462500, };
static const unsigned int sw5_val_tbl[] = { 0, 5050000, };
static const unsigned int vcam_val_tbl[] = { 2600000, 2700000, 2800000,
2900000, };
......@@ -389,6 +412,82 @@ static struct cpcap_regulator omap4_regulators[] = {
{ /* sentinel */ },
};
static struct cpcap_regulator xoom_regulators[] = {
CPCAP_REG(SW1, CPCAP_REG_S1C1, CPCAP_REG_ASSIGN2,
CPCAP_BIT_SW1_SEL, unknown_val_tbl,
0, 0, 0, 0, 0, 0),
CPCAP_REG(SW2, CPCAP_REG_S2C1, CPCAP_REG_ASSIGN2,
CPCAP_BIT_SW2_SEL, sw2_sw4_val_tbl,
0xf00, 0x7f, 0, 0x800, 0, 120),
CPCAP_REG(SW3, CPCAP_REG_S3C, CPCAP_REG_ASSIGN2,
CPCAP_BIT_SW3_SEL, unknown_val_tbl,
0, 0, 0, 0, 0, 0),
CPCAP_REG(SW4, CPCAP_REG_S4C1, CPCAP_REG_ASSIGN2,
CPCAP_BIT_SW4_SEL, sw2_sw4_val_tbl,
0xf00, 0x7f, 0, 0x900, 0, 100),
CPCAP_REG(SW5, CPCAP_REG_S5C, CPCAP_REG_ASSIGN2,
CPCAP_BIT_SW5_SEL, sw5_val_tbl,
0x2a, 0, 0, 0x22, 0, 0),
CPCAP_REG(SW6, CPCAP_REG_S6C, CPCAP_REG_ASSIGN2,
CPCAP_BIT_SW6_SEL, unknown_val_tbl,
0, 0, 0, 0, 0, 0),
CPCAP_REG(VCAM, CPCAP_REG_VCAMC, CPCAP_REG_ASSIGN2,
CPCAP_BIT_VCAM_SEL, vcam_val_tbl,
0x87, 0x30, 4, 0x7, 0, 420),
CPCAP_REG(VCSI, CPCAP_REG_VCSIC, CPCAP_REG_ASSIGN3,
CPCAP_BIT_VCSI_SEL, vcsi_val_tbl,
0x47, 0x10, 4, 0x7, 0, 350),
CPCAP_REG(VDAC, CPCAP_REG_VDACC, CPCAP_REG_ASSIGN3,
CPCAP_BIT_VDAC_SEL, vdac_val_tbl,
0x87, 0x30, 4, 0x3, 0, 420),
CPCAP_REG(VDIG, CPCAP_REG_VDIGC, CPCAP_REG_ASSIGN2,
CPCAP_BIT_VDIG_SEL, vdig_val_tbl,
0x87, 0x30, 4, 0x5, 0, 420),
CPCAP_REG(VFUSE, CPCAP_REG_VFUSEC, CPCAP_REG_ASSIGN3,
CPCAP_BIT_VFUSE_SEL, vfuse_val_tbl,
0x80, 0xf, 0, 0x80, 0, 420),
CPCAP_REG(VHVIO, CPCAP_REG_VHVIOC, CPCAP_REG_ASSIGN3,
CPCAP_BIT_VHVIO_SEL, vhvio_val_tbl,
0x17, 0, 0, 0x2, 0, 0),
CPCAP_REG(VSDIO, CPCAP_REG_VSDIOC, CPCAP_REG_ASSIGN2,
CPCAP_BIT_VSDIO_SEL, vsdio_val_tbl,
0x87, 0x38, 3, 0x2, 0, 420),
CPCAP_REG(VPLL, CPCAP_REG_VPLLC, CPCAP_REG_ASSIGN3,
CPCAP_BIT_VPLL_SEL, vpll_val_tbl,
0x43, 0x18, 3, 0x1, 0, 420),
CPCAP_REG(VRF1, CPCAP_REG_VRF1C, CPCAP_REG_ASSIGN3,
CPCAP_BIT_VRF1_SEL, vrf1_val_tbl,
0xac, 0x2, 1, 0xc, 0, 10),
CPCAP_REG(VRF2, CPCAP_REG_VRF2C, CPCAP_REG_ASSIGN3,
CPCAP_BIT_VRF2_SEL, vrf2_val_tbl,
0x23, 0x8, 3, 0x3, 0, 10),
CPCAP_REG(VRFREF, CPCAP_REG_VRFREFC, CPCAP_REG_ASSIGN3,
CPCAP_BIT_VRFREF_SEL, vrfref_val_tbl,
0x23, 0x8, 3, 0x3, 0, 420),
CPCAP_REG(VWLAN1, CPCAP_REG_VWLAN1C, CPCAP_REG_ASSIGN3,
CPCAP_BIT_VWLAN1_SEL, vwlan1_val_tbl,
0x47, 0x10, 4, 0x5, 0, 420),
CPCAP_REG(VWLAN2, CPCAP_REG_VWLAN2C, CPCAP_REG_ASSIGN3,
CPCAP_BIT_VWLAN2_SEL, vwlan2_val_tbl,
0x20c, 0xc0, 6, 0x8, 0, 420),
CPCAP_REG(VSIM, CPCAP_REG_VSIMC, CPCAP_REG_ASSIGN3,
0xffff, vsim_val_tbl,
0x23, 0x8, 3, 0x3, 0, 420),
CPCAP_REG(VSIMCARD, CPCAP_REG_VSIMC, CPCAP_REG_ASSIGN3,
0xffff, vsimcard_val_tbl,
0x1e80, 0x8, 3, 0x1e00, 0, 420),
CPCAP_REG(VVIB, CPCAP_REG_VVIBC, CPCAP_REG_ASSIGN3,
CPCAP_BIT_VVIB_SEL, vvib_val_tbl,
0x1, 0xc, 2, 0, 0x1, 500),
CPCAP_REG(VUSB, CPCAP_REG_VUSBC, CPCAP_REG_ASSIGN3,
CPCAP_BIT_VUSB_SEL, vusb_val_tbl,
0x11c, 0x40, 6, 0xc, 0, 0),
CPCAP_REG(VAUDIO, CPCAP_REG_VAUDIOC, CPCAP_REG_ASSIGN4,
CPCAP_BIT_VAUDIO_SEL, vaudio_val_tbl,
0x16, 0x1, 0, 0x4, 0, 0),
{ /* sentinel */ },
};
static const struct of_device_id cpcap_regulator_id_table[] = {
{
.compatible = "motorola,cpcap-regulator",
......@@ -397,6 +496,10 @@ static const struct of_device_id cpcap_regulator_id_table[] = {
.compatible = "motorola,mapphone-cpcap-regulator",
.data = omap4_regulators,
},
{
.compatible = "motorola,xoom-cpcap-regulator",
.data = xoom_regulators,
},
{},
};
MODULE_DEVICE_TABLE(of, cpcap_regulator_id_table);
......
/*
* max14577.c - Regulator driver for the Maxim 14577/77836
*
* Copyright (C) 2013,2014 Samsung Electronics
* Krzysztof Kozlowski <krzk@kernel.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
// SPDX-License-Identifier: GPL-2.0+
//
// max14577.c - Regulator driver for the Maxim 14577/77836
//
// Copyright (C) 2013,2014 Samsung Electronics
// Krzysztof Kozlowski <krzk@kernel.org>
#include <linux/module.h>
#include <linux/platform_device.h>
......
/*
* max77686.c - Regulator driver for the Maxim 77686
*
* Copyright (C) 2012 Samsung Electronics
* Chiwoong Byun <woong.byun@samsung.com>
* Jonghwa Lee <jonghwa3.lee@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* This driver is based on max8997.c
*/
// SPDX-License-Identifier: GPL-2.0+
//
// max77686.c - Regulator driver for the Maxim 77686
//
// Copyright (C) 2012 Samsung Electronics
// Chiwoong Byun <woong.byun@samsung.com>
// Jonghwa Lee <jonghwa3.lee@samsung.com>
//
// This driver is based on max8997.c
#include <linux/kernel.h>
#include <linux/bug.h>
......
/*
* max77693.c - Regulator driver for the Maxim 77693 and 77843
*
* Copyright (C) 2013-2015 Samsung Electronics
* Jonghwa Lee <jonghwa3.lee@samsung.com>
* Krzysztof Kozlowski <krzk@kernel.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* This driver is based on max77686.c
*/
// SPDX-License-Identifier: GPL-2.0+
//
// max77693.c - Regulator driver for the Maxim 77693 and 77843
//
// Copyright (C) 2013-2015 Samsung Electronics
// Jonghwa Lee <jonghwa3.lee@samsung.com>
// Krzysztof Kozlowski <krzk@kernel.org>
//
// This driver is based on max77686.c
#include <linux/err.h>
#include <linux/slab.h>
......
/*
* max77802.c - Regulator driver for the Maxim 77802
*
* Copyright (C) 2013-2014 Google, Inc
* Simon Glass <sjg@chromium.org>
*
* Copyright (C) 2012 Samsung Electronics
* Chiwoong Byun <woong.byun@samsung.com>
* Jonghwa Lee <jonghwa3.lee@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This driver is based on max8997.c
*/
// SPDX-License-Identifier: GPL-2.0+
//
// max77802.c - Regulator driver for the Maxim 77802
//
// Copyright (C) 2013-2014 Google, Inc
// Simon Glass <sjg@chromium.org>
//
// Copyright (C) 2012 Samsung Electronics
// Chiwoong Byun <woong.byun@samsung.com>
// Jonghwa Lee <jonghwa3.lee@samsung.com>
//
// This driver is based on max8997.c
#include <linux/kernel.h>
#include <linux/bug.h>
......
/*
* max8997.c - Regulator driver for the Maxim 8997/8966
*
* Copyright (C) 2011 Samsung Electronics
* MyungJoo Ham <myungjoo.ham@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* This driver is based on max8998.c
*/
// SPDX-License-Identifier: GPL-2.0+
//
// max8997.c - Regulator driver for the Maxim 8997/8966
//
// Copyright (C) 2011 Samsung Electronics
// MyungJoo Ham <myungjoo.ham@samsung.com>
//
// This driver is based on max8998.c
#include <linux/bug.h>
#include <linux/err.h>
......@@ -165,8 +151,7 @@ static int max8997_list_voltage(struct regulator_dev *rdev,
int rid = rdev_get_id(rdev);
int val;
if (rid >= ARRAY_SIZE(reg_voltage_map) ||
rid < 0)
if (rid < 0 || rid >= ARRAY_SIZE(reg_voltage_map))
return -EINVAL;
desc = reg_voltage_map[rid];
......
/*
* max8998.c - Voltage regulator driver for the Maxim 8998
*
* Copyright (C) 2009-2010 Samsung Electronics
* Kyungmin Park <kyungmin.park@samsung.com>
* Marek Szyprowski <m.szyprowski@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// SPDX-License-Identifier: GPL-2.0+
//
// max8998.c - Voltage regulator driver for the Maxim 8998
//
// Copyright (C) 2009-2010 Samsung Electronics
// Kyungmin Park <kyungmin.park@samsung.com>
// Marek Szyprowski <m.szyprowski@samsung.com>
#include <linux/module.h>
#include <linux/init.h>
......
......@@ -17,6 +17,8 @@
#include <linux/slab.h>
#include <linux/regmap.h>
#define PFUZE_FLAG_DISABLE_SW BIT(1)
#define PFUZE_NUMREGS 128
#define PFUZE100_VOL_OFFSET 0
#define PFUZE100_STANDBY_OFFSET 1
......@@ -44,16 +46,18 @@
#define PFUZE100_VGEN5VOL 0x70
#define PFUZE100_VGEN6VOL 0x71
enum chips { PFUZE100, PFUZE200, PFUZE3000 = 3 };
enum chips { PFUZE100, PFUZE200, PFUZE3000 = 3, PFUZE3001 = 0x31, };
struct pfuze_regulator {
struct regulator_desc desc;
unsigned char stby_reg;
unsigned char stby_mask;
bool sw_reg;
};
struct pfuze_chip {
int chip_id;
int flags;
struct regmap *regmap;
struct device *dev;
struct pfuze_regulator regulator_descs[PFUZE100_MAX_REGULATOR];
......@@ -92,6 +96,7 @@ static const struct i2c_device_id pfuze_device_id[] = {
{.name = "pfuze100", .driver_data = PFUZE100},
{.name = "pfuze200", .driver_data = PFUZE200},
{.name = "pfuze3000", .driver_data = PFUZE3000},
{.name = "pfuze3001", .driver_data = PFUZE3001},
{ }
};
MODULE_DEVICE_TABLE(i2c, pfuze_device_id);
......@@ -100,6 +105,7 @@ static const struct of_device_id pfuze_dt_ids[] = {
{ .compatible = "fsl,pfuze100", .data = (void *)PFUZE100},
{ .compatible = "fsl,pfuze200", .data = (void *)PFUZE200},
{ .compatible = "fsl,pfuze3000", .data = (void *)PFUZE3000},
{ .compatible = "fsl,pfuze3001", .data = (void *)PFUZE3001},
{ }
};
MODULE_DEVICE_TABLE(of, pfuze_dt_ids);
......@@ -108,10 +114,28 @@ static int pfuze100_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
{
struct pfuze_chip *pfuze100 = rdev_get_drvdata(rdev);
int id = rdev_get_id(rdev);
bool reg_has_ramp_delay;
unsigned int ramp_bits;
int ret;
if (id < PFUZE100_SWBST) {
switch (pfuze100->chip_id) {
case PFUZE3001:
/* no dynamic voltage scaling for PF3001 */
reg_has_ramp_delay = false;
break;
case PFUZE3000:
reg_has_ramp_delay = (id < PFUZE3000_SWBST);
break;
case PFUZE200:
reg_has_ramp_delay = (id < PFUZE200_SWBST);
break;
case PFUZE100:
default:
reg_has_ramp_delay = (id < PFUZE100_SWBST);
break;
}
if (reg_has_ramp_delay) {
ramp_delay = 12500 / ramp_delay;
ramp_bits = (ramp_delay >> 1) - (ramp_delay >> 3);
ret = regmap_update_bits(pfuze100->regmap,
......@@ -119,8 +143,9 @@ static int pfuze100_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
0xc0, ramp_bits << 6);
if (ret < 0)
dev_err(pfuze100->dev, "ramp failed, err %d\n", ret);
} else
} else {
ret = -EACCES;
}
return ret;
}
......@@ -142,6 +167,14 @@ static const struct regulator_ops pfuze100_fixed_regulator_ops = {
};
static const struct regulator_ops pfuze100_sw_regulator_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 = regulator_set_voltage_time_sel,
.set_ramp_delay = pfuze100_set_ramp_delay,
};
static const struct regulator_ops pfuze100_sw_disable_regulator_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
......@@ -192,13 +225,11 @@ static const struct regulator_ops pfuze100_swb_regulator_ops = {
.vsel_reg = (base) + PFUZE100_VOL_OFFSET, \
.vsel_mask = 0x3f, \
.enable_reg = (base) + PFUZE100_MODE_OFFSET, \
.enable_val = 0xc, \
.disable_val = 0x0, \
.enable_mask = 0xf, \
.enable_time = 500, \
}, \
.stby_reg = (base) + PFUZE100_STANDBY_OFFSET, \
.stby_mask = 0x3f, \
.sw_reg = true, \
}
#define PFUZE100_SWB_REG(_chip, _name, base, mask, voltages) \
......@@ -361,6 +392,19 @@ static struct pfuze_regulator pfuze3000_regulators[] = {
PFUZE100_VGEN_REG(PFUZE3000, VLDO4, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
};
static struct pfuze_regulator pfuze3001_regulators[] = {
PFUZE100_SWB_REG(PFUZE3001, SW1, PFUZE100_SW1ABVOL, 0x1f, pfuze3000_sw1a),
PFUZE100_SWB_REG(PFUZE3001, SW2, PFUZE100_SW2VOL, 0x7, pfuze3000_sw2lo),
PFUZE3000_SW3_REG(PFUZE3001, SW3, PFUZE100_SW3AVOL, 900000, 1650000, 50000),
PFUZE100_SWB_REG(PFUZE3001, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs),
PFUZE100_VGEN_REG(PFUZE3001, VLDO1, PFUZE100_VGEN1VOL, 1800000, 3300000, 100000),
PFUZE100_VGEN_REG(PFUZE3001, VLDO2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000),
PFUZE3000_VCC_REG(PFUZE3001, VCCSD, PFUZE100_VGEN3VOL, 2850000, 3300000, 150000),
PFUZE3000_VCC_REG(PFUZE3001, V33, PFUZE100_VGEN4VOL, 2850000, 3300000, 150000),
PFUZE100_VGEN_REG(PFUZE3001, VLDO3, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
PFUZE100_VGEN_REG(PFUZE3001, VLDO4, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
};
#ifdef CONFIG_OF
/* PFUZE100 */
static struct of_regulator_match pfuze100_matches[] = {
......@@ -418,6 +462,21 @@ static struct of_regulator_match pfuze3000_matches[] = {
{ .name = "vldo4", },
};
/* PFUZE3001 */
static struct of_regulator_match pfuze3001_matches[] = {
{ .name = "sw1", },
{ .name = "sw2", },
{ .name = "sw3", },
{ .name = "vsnvs", },
{ .name = "vldo1", },
{ .name = "vldo2", },
{ .name = "vccsd", },
{ .name = "v33", },
{ .name = "vldo3", },
{ .name = "vldo4", },
};
static struct of_regulator_match *pfuze_matches;
static int pfuze_parse_regulators_dt(struct pfuze_chip *chip)
......@@ -430,6 +489,9 @@ static int pfuze_parse_regulators_dt(struct pfuze_chip *chip)
if (!np)
return -EINVAL;
if (of_property_read_bool(np, "fsl,pfuze-support-disable-sw"))
chip->flags |= PFUZE_FLAG_DISABLE_SW;
parent = of_get_child_by_name(np, "regulators");
if (!parent) {
dev_err(dev, "regulators node not found\n");
......@@ -437,6 +499,11 @@ static int pfuze_parse_regulators_dt(struct pfuze_chip *chip)
}
switch (chip->chip_id) {
case PFUZE3001:
pfuze_matches = pfuze3001_matches;
ret = of_regulator_match(dev, parent, pfuze3001_matches,
ARRAY_SIZE(pfuze3001_matches));
break;
case PFUZE3000:
pfuze_matches = pfuze3000_matches;
ret = of_regulator_match(dev, parent, pfuze3000_matches,
......@@ -508,7 +575,8 @@ static int pfuze_identify(struct pfuze_chip *pfuze_chip)
*/
dev_info(pfuze_chip->dev, "Assuming misprogrammed ID=0x8");
} else if ((value & 0x0f) != pfuze_chip->chip_id &&
(value & 0xf0) >> 4 != pfuze_chip->chip_id) {
(value & 0xf0) >> 4 != pfuze_chip->chip_id &&
(value != pfuze_chip->chip_id)) {
/* device id NOT match with your setting */
dev_warn(pfuze_chip->dev, "Illegal ID: %x\n", value);
return -ENODEV;
......@@ -588,6 +656,13 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
/* use the right regulators after identify the right device */
switch (pfuze_chip->chip_id) {
case PFUZE3001:
pfuze_chip->pfuze_regulators = pfuze3001_regulators;
regulator_num = ARRAY_SIZE(pfuze3001_regulators);
sw_check_start = PFUZE3001_SW2;
sw_check_end = PFUZE3001_SW2;
sw_hi = 1 << 3;
break;
case PFUZE3000:
pfuze_chip->pfuze_regulators = pfuze3000_regulators;
regulator_num = ARRAY_SIZE(pfuze3000_regulators);
......@@ -611,7 +686,8 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
}
dev_info(&client->dev, "pfuze%s found.\n",
(pfuze_chip->chip_id == PFUZE100) ? "100" :
((pfuze_chip->chip_id == PFUZE200) ? "200" : "3000"));
(((pfuze_chip->chip_id == PFUZE200) ? "200" :
((pfuze_chip->chip_id == PFUZE3000) ? "3000" : "3001"))));
memcpy(pfuze_chip->regulator_descs, pfuze_chip->pfuze_regulators,
sizeof(pfuze_chip->regulator_descs));
......@@ -636,7 +712,8 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
if (i >= sw_check_start && i <= sw_check_end) {
regmap_read(pfuze_chip->regmap, desc->vsel_reg, &val);
if (val & sw_hi) {
if (pfuze_chip->chip_id == PFUZE3000) {
if (pfuze_chip->chip_id == PFUZE3000 ||
pfuze_chip->chip_id == PFUZE3001) {
desc->volt_table = pfuze3000_sw2hi;
desc->n_voltages = ARRAY_SIZE(pfuze3000_sw2hi);
} else {
......@@ -647,6 +724,21 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
}
}
/*
* Allow SW regulators to turn off. Checking it trough a flag is
* a workaround to keep the backward compatibility with existing
* old dtb's which may relay on the fact that we didn't disable
* the switched regulator till yet.
*/
if (pfuze_chip->flags & PFUZE_FLAG_DISABLE_SW) {
if (pfuze_chip->regulator_descs[i].sw_reg) {
desc->ops = &pfuze100_sw_disable_regulator_ops;
desc->enable_val = 0x8;
desc->disable_val = 0x0;
desc->enable_time = 500;
}
}
config.dev = &client->dev;
config.init_data = init_data;
config.driver_data = pfuze_chip;
......@@ -675,5 +767,5 @@ static struct i2c_driver pfuze_driver = {
module_i2c_driver(pfuze_driver);
MODULE_AUTHOR("Robin Gong <b38343@freescale.com>");
MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100/200/3000 PMIC");
MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100/200/3000/3001 PMIC");
MODULE_LICENSE("GPL v2");
This diff is collapsed.
......@@ -1060,7 +1060,7 @@ static irqreturn_t spmi_regulator_vs_ocp_isr(int irq, void *data)
#define SAW3_AVS_CTL_TGGL_MASK 0x8000000
#define SAW3_AVS_CTL_CLEAR_MASK 0x7efc00
static struct regmap *saw_regmap = NULL;
static struct regmap *saw_regmap;
static void spmi_saw_set_vdd(void *data)
{
......@@ -1728,7 +1728,7 @@ static const struct spmi_regulator_data pmi8994_regulators[] = {
{ "s2", 0x1700, "vdd_s2", },
{ "s3", 0x1a00, "vdd_s3", },
{ "l1", 0x4000, "vdd_l1", },
{ }
{ }
};
static const struct of_device_id qcom_spmi_regulator_match[] = {
......@@ -1752,7 +1752,8 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev)
const char *name;
struct device *dev = &pdev->dev;
struct device_node *node = pdev->dev.of_node;
struct device_node *syscon;
struct device_node *syscon, *reg_node;
struct property *reg_prop;
int ret, lenp;
struct list_head *vreg_list;
......@@ -1774,16 +1775,19 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev)
syscon = of_parse_phandle(node, "qcom,saw-reg", 0);
saw_regmap = syscon_node_to_regmap(syscon);
of_node_put(syscon);
if (IS_ERR(regmap))
if (IS_ERR(saw_regmap))
dev_err(dev, "ERROR reading SAW regmap\n");
}
for (reg = match->data; reg->name; reg++) {
if (saw_regmap && \
of_find_property(of_find_node_by_name(node, reg->name), \
"qcom,saw-slave", &lenp)) {
continue;
if (saw_regmap) {
reg_node = of_get_child_by_name(node, reg->name);
reg_prop = of_find_property(reg_node, "qcom,saw-slave",
&lenp);
of_node_put(reg_node);
if (reg_prop)
continue;
}
vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
......@@ -1816,13 +1820,17 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev)
if (ret)
continue;
if (saw_regmap && \
of_find_property(of_find_node_by_name(node, reg->name), \
"qcom,saw-leader", &lenp)) {
spmi_saw_ops = *(vreg->desc.ops);
spmi_saw_ops.set_voltage_sel = \
spmi_regulator_saw_set_voltage;
vreg->desc.ops = &spmi_saw_ops;
if (saw_regmap) {
reg_node = of_get_child_by_name(node, reg->name);
reg_prop = of_find_property(reg_node, "qcom,saw-leader",
&lenp);
of_node_put(reg_node);
if (reg_prop) {
spmi_saw_ops = *(vreg->desc.ops);
spmi_saw_ops.set_voltage_sel =
spmi_regulator_saw_set_voltage;
vreg->desc.ops = &spmi_saw_ops;
}
}
config.dev = dev;
......
/*
* Copyright (c) 2013 Samsung Electronics Co., Ltd
* http://www.samsung.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
// SPDX-License-Identifier: GPL-2.0+
//
// Copyright (c) 2013 Samsung Electronics Co., Ltd
// http://www.samsung.com
#include <linux/bug.h>
#include <linux/err.h>
......
/*
* s2mps11.c
*
* Copyright (c) 2012-2014 Samsung Electronics Co., Ltd
* http://www.samsung.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
// SPDX-License-Identifier: GPL-2.0+
//
// Copyright (c) 2012-2014 Samsung Electronics Co., Ltd
// http://www.samsung.com
#include <linux/bug.h>
#include <linux/err.h>
......
/*
* s5m8767.c
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd
* http://www.samsung.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
// SPDX-License-Identifier: GPL-2.0+
//
// Copyright (c) 2011 Samsung Electronics Co., Ltd
// http://www.samsung.com
#include <linux/err.h>
#include <linux/of_gpio.h>
......
......@@ -232,6 +232,8 @@ static int tps65217_regulator_probe(struct platform_device *pdev)
tps->strobes = devm_kcalloc(&pdev->dev,
TPS65217_NUM_REGULATOR, sizeof(u8),
GFP_KERNEL);
if (!tps->strobes)
return -ENOMEM;
platform_set_drvdata(pdev, tps);
......
// SPDX-License-Identifier: GPL-2.0
//
// Regulator controller driver for UniPhier SoC
// Copyright 2018 Socionext Inc.
// Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
#include <linux/reset.h>
#define MAX_CLKS 2
#define MAX_RSTS 2
struct uniphier_regulator_soc_data {
int nclks;
const char * const *clock_names;
int nrsts;
const char * const *reset_names;
const struct regulator_desc *desc;
const struct regmap_config *regconf;
};
struct uniphier_regulator_priv {
struct clk_bulk_data clk[MAX_CLKS];
struct reset_control *rst[MAX_RSTS];
const struct uniphier_regulator_soc_data *data;
};
static struct regulator_ops uniphier_regulator_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
};
static int uniphier_regulator_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct uniphier_regulator_priv *priv;
struct regulator_config config = { };
struct regulator_dev *rdev;
struct regmap *regmap;
struct resource *res;
void __iomem *base;
const char *name;
int i, ret, nr;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->data = of_device_get_match_data(dev);
if (WARN_ON(!priv->data))
return -EINVAL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
for (i = 0; i < priv->data->nclks; i++)
priv->clk[i].id = priv->data->clock_names[i];
ret = devm_clk_bulk_get(dev, priv->data->nclks, priv->clk);
if (ret)
return ret;
for (i = 0; i < priv->data->nrsts; i++) {
name = priv->data->reset_names[i];
priv->rst[i] = devm_reset_control_get_shared(dev, name);
if (IS_ERR(priv->rst[i]))
return PTR_ERR(priv->rst[i]);
}
ret = clk_bulk_prepare_enable(priv->data->nclks, priv->clk);
if (ret)
return ret;
for (nr = 0; nr < priv->data->nrsts; nr++) {
ret = reset_control_deassert(priv->rst[nr]);
if (ret)
goto out_rst_assert;
}
regmap = devm_regmap_init_mmio(dev, base, priv->data->regconf);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
config.dev = dev;
config.driver_data = priv;
config.of_node = dev->of_node;
config.regmap = regmap;
config.init_data = of_get_regulator_init_data(dev, dev->of_node,
priv->data->desc);
rdev = devm_regulator_register(dev, priv->data->desc, &config);
if (IS_ERR(rdev)) {
ret = PTR_ERR(rdev);
goto out_rst_assert;
}
platform_set_drvdata(pdev, priv);
return 0;
out_rst_assert:
while (nr--)
reset_control_assert(priv->rst[nr]);
clk_bulk_disable_unprepare(priv->data->nclks, priv->clk);
return ret;
}
static int uniphier_regulator_remove(struct platform_device *pdev)
{
struct uniphier_regulator_priv *priv = platform_get_drvdata(pdev);
int i;
for (i = 0; i < priv->data->nrsts; i++)
reset_control_assert(priv->rst[i]);
clk_bulk_disable_unprepare(priv->data->nclks, priv->clk);
return 0;
}
/* USB3 controller data */
#define USB3VBUS_OFFSET 0x0
#define USB3VBUS_REG BIT(4)
#define USB3VBUS_REG_EN BIT(3)
static const struct regulator_desc uniphier_usb3_regulator_desc = {
.name = "vbus",
.of_match = of_match_ptr("vbus"),
.ops = &uniphier_regulator_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
.enable_reg = USB3VBUS_OFFSET,
.enable_mask = USB3VBUS_REG_EN | USB3VBUS_REG,
.enable_val = USB3VBUS_REG_EN | USB3VBUS_REG,
.disable_val = USB3VBUS_REG_EN,
};
static const struct regmap_config uniphier_usb3_regulator_regconf = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = 1,
};
static const char * const uniphier_pro4_clock_reset_names[] = {
"gio", "link",
};
static const struct uniphier_regulator_soc_data uniphier_pro4_usb3_data = {
.nclks = ARRAY_SIZE(uniphier_pro4_clock_reset_names),
.clock_names = uniphier_pro4_clock_reset_names,
.nrsts = ARRAY_SIZE(uniphier_pro4_clock_reset_names),
.reset_names = uniphier_pro4_clock_reset_names,
.desc = &uniphier_usb3_regulator_desc,
.regconf = &uniphier_usb3_regulator_regconf,
};
static const char * const uniphier_pxs2_clock_reset_names[] = {
"link",
};
static const struct uniphier_regulator_soc_data uniphier_pxs2_usb3_data = {
.nclks = ARRAY_SIZE(uniphier_pxs2_clock_reset_names),
.clock_names = uniphier_pxs2_clock_reset_names,
.nrsts = ARRAY_SIZE(uniphier_pxs2_clock_reset_names),
.reset_names = uniphier_pxs2_clock_reset_names,
.desc = &uniphier_usb3_regulator_desc,
.regconf = &uniphier_usb3_regulator_regconf,
};
static const struct of_device_id uniphier_regulator_match[] = {
/* USB VBUS */
{
.compatible = "socionext,uniphier-pro4-usb3-regulator",
.data = &uniphier_pro4_usb3_data,
},
{
.compatible = "socionext,uniphier-pxs2-usb3-regulator",
.data = &uniphier_pxs2_usb3_data,
},
{
.compatible = "socionext,uniphier-ld20-usb3-regulator",
.data = &uniphier_pxs2_usb3_data,
},
{
.compatible = "socionext,uniphier-pxs3-usb3-regulator",
.data = &uniphier_pxs2_usb3_data,
},
{ /* Sentinel */ },
};
static struct platform_driver uniphier_regulator_driver = {
.probe = uniphier_regulator_probe,
.remove = uniphier_regulator_remove,
.driver = {
.name = "uniphier-regulator",
.of_match_table = uniphier_regulator_match,
},
};
module_platform_driver(uniphier_regulator_driver);
MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
MODULE_DESCRIPTION("UniPhier Regulator Controller Driver");
MODULE_LICENSE("GPL");
......@@ -40,6 +40,23 @@ config QCOM_GSBI
functions for connecting the underlying serial UART, SPI, and I2C
devices to the output pins.
config QCOM_LLCC
tristate "Qualcomm Technologies, Inc. LLCC driver"
depends on ARCH_QCOM
help
Qualcomm Technologies, Inc. platform specific
Last Level Cache Controller(LLCC) driver. This provides interfaces
to clients that use the LLCC. Say yes here to enable LLCC slice
driver.
config QCOM_SDM845_LLCC
tristate "Qualcomm Technologies, Inc. SDM845 LLCC driver"
depends on QCOM_LLCC
help
Say yes here to enable the LLCC driver for SDM845. This provides
data required to configure LLCC so that clients can start using the
LLCC slices.
config QCOM_MDT_LOADER
tristate
select QCOM_SCM
......@@ -75,6 +92,16 @@ config QCOM_RMTFS_MEM
Say y here if you intend to boot the modem remoteproc.
config QCOM_RPMH
bool "Qualcomm RPM-Hardened (RPMH) Communication"
depends on ARCH_QCOM && ARM64 && OF || COMPILE_TEST
help
Support for communication with the hardened-RPM blocks in
Qualcomm Technologies Inc (QTI) SoCs. RPMH communication uses an
internal bus to transmit state requests for shared resources. A set
of hardware components aggregate requests for these resources and
help apply the aggregated state on the resource.
config QCOM_SMEM
tristate "Qualcomm Shared Memory Manager (SMEM)"
depends on ARCH_QCOM
......
# SPDX-License-Identifier: GPL-2.0
CFLAGS_rpmh-rsc.o := -I$(src)
obj-$(CONFIG_QCOM_GENI_SE) += qcom-geni-se.o
obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o
obj-$(CONFIG_QCOM_GLINK_SSR) += glink_ssr.o
......@@ -8,6 +9,9 @@ obj-$(CONFIG_QCOM_PM) += spm.o
obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o
qmi_helpers-y += qmi_encdec.o qmi_interface.o
obj-$(CONFIG_QCOM_RMTFS_MEM) += rmtfs_mem.o
obj-$(CONFIG_QCOM_RPMH) += qcom_rpmh.o
qcom_rpmh-y += rpmh-rsc.o
qcom_rpmh-y += rpmh.o
obj-$(CONFIG_QCOM_SMD_RPM) += smd-rpm.o
obj-$(CONFIG_QCOM_SMEM) += smem.o
obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o
......@@ -15,3 +19,5 @@ obj-$(CONFIG_QCOM_SMP2P) += smp2p.o
obj-$(CONFIG_QCOM_SMSM) += smsm.o
obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
obj-$(CONFIG_QCOM_APR) += apr.o
obj-$(CONFIG_QCOM_LLCC) += llcc-slice.o
obj-$(CONFIG_QCOM_SDM845_LLCC) += llcc-sdm845.o
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/soc/qcom/llcc-qcom.h>
/*
* SCT(System Cache Table) entry contains of the following members:
* usecase_id: Unique id for the client's use case
* slice_id: llcc slice id for each client
* max_cap: The maximum capacity of the cache slice provided in KB
* priority: Priority of the client used to select victim line for replacement
* fixed_size: Boolean indicating if the slice has a fixed capacity
* bonus_ways: Bonus ways are additional ways to be used for any slice,
* if client ends up using more than reserved cache ways. Bonus
* ways are allocated only if they are not reserved for some
* other client.
* res_ways: Reserved ways for the cache slice, the reserved ways cannot
* be used by any other client than the one its assigned to.
* cache_mode: Each slice operates as a cache, this controls the mode of the
* slice: normal or TCM(Tightly Coupled Memory)
* probe_target_ways: Determines what ways to probe for access hit. When
* configured to 1 only bonus and reserved ways are probed.
* When configured to 0 all ways in llcc are probed.
* dis_cap_alloc: Disable capacity based allocation for a client
* retain_on_pc: If this bit is set and client has maintained active vote
* then the ways assigned to this client are not flushed on power
* collapse.
* activate_on_init: Activate the slice immediately after the SCT is programmed
*/
#define SCT_ENTRY(uid, sid, mc, p, fs, bway, rway, cmod, ptw, dca, rp, a) \
{ \
.usecase_id = uid, \
.slice_id = sid, \
.max_cap = mc, \
.priority = p, \
.fixed_size = fs, \
.bonus_ways = bway, \
.res_ways = rway, \
.cache_mode = cmod, \
.probe_target_ways = ptw, \
.dis_cap_alloc = dca, \
.retain_on_pc = rp, \
.activate_on_init = a, \
}
static struct llcc_slice_config sdm845_data[] = {
SCT_ENTRY(LLCC_CPUSS, 1, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 1),
SCT_ENTRY(LLCC_VIDSC0, 2, 512, 2, 1, 0x0, 0x0f0, 0, 0, 1, 1, 0),
SCT_ENTRY(LLCC_VIDSC1, 3, 512, 2, 1, 0x0, 0x0f0, 0, 0, 1, 1, 0),
SCT_ENTRY(LLCC_ROTATOR, 4, 563, 2, 1, 0x0, 0x00e, 2, 0, 1, 1, 0),
SCT_ENTRY(LLCC_VOICE, 5, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0),
SCT_ENTRY(LLCC_AUDIO, 6, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0),
SCT_ENTRY(LLCC_MDMHPGRW, 7, 1024, 2, 0, 0xfc, 0xf00, 0, 0, 1, 1, 0),
SCT_ENTRY(LLCC_MDM, 8, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0),
SCT_ENTRY(LLCC_CMPT, 10, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0),
SCT_ENTRY(LLCC_GPUHTW, 11, 512, 1, 1, 0xc, 0x0, 0, 0, 1, 1, 0),
SCT_ENTRY(LLCC_GPU, 12, 2304, 1, 0, 0xff0, 0x2, 0, 0, 1, 1, 0),
SCT_ENTRY(LLCC_MMUHWT, 13, 256, 2, 0, 0x0, 0x1, 0, 0, 1, 0, 1),
SCT_ENTRY(LLCC_CMPTDMA, 15, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0),
SCT_ENTRY(LLCC_DISP, 16, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0),
SCT_ENTRY(LLCC_VIDFW, 17, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0),
SCT_ENTRY(LLCC_MDMHPFX, 20, 1024, 2, 1, 0x0, 0xf00, 0, 0, 1, 1, 0),
SCT_ENTRY(LLCC_MDMPNG, 21, 1024, 0, 1, 0x1e, 0x0, 0, 0, 1, 1, 0),
SCT_ENTRY(LLCC_AUDHW, 22, 1024, 1, 1, 0xffc, 0x2, 0, 0, 1, 1, 0),
};
static int sdm845_qcom_llcc_probe(struct platform_device *pdev)
{
return qcom_llcc_probe(pdev, sdm845_data, ARRAY_SIZE(sdm845_data));
}
static const struct of_device_id sdm845_qcom_llcc_of_match[] = {
{ .compatible = "qcom,sdm845-llcc", },
{ }
};
static struct platform_driver sdm845_qcom_llcc_driver = {
.driver = {
.name = "sdm845-llcc",
.of_match_table = sdm845_qcom_llcc_of_match,
},
.probe = sdm845_qcom_llcc_probe,
};
module_platform_driver(sdm845_qcom_llcc_driver);
MODULE_DESCRIPTION("QCOM sdm845 LLCC driver");
MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
*
*/
#include <linux/bitmap.h>
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/soc/qcom/llcc-qcom.h>
#define ACTIVATE BIT(0)
#define DEACTIVATE BIT(1)
#define ACT_CTRL_OPCODE_ACTIVATE BIT(0)
#define ACT_CTRL_OPCODE_DEACTIVATE BIT(1)
#define ACT_CTRL_ACT_TRIG BIT(0)
#define ACT_CTRL_OPCODE_SHIFT 0x01
#define ATTR1_PROBE_TARGET_WAYS_SHIFT 0x02
#define ATTR1_FIXED_SIZE_SHIFT 0x03
#define ATTR1_PRIORITY_SHIFT 0x04
#define ATTR1_MAX_CAP_SHIFT 0x10
#define ATTR0_RES_WAYS_MASK GENMASK(11, 0)
#define ATTR0_BONUS_WAYS_MASK GENMASK(27, 16)
#define ATTR0_BONUS_WAYS_SHIFT 0x10
#define LLCC_STATUS_READ_DELAY 100
#define CACHE_LINE_SIZE_SHIFT 6
#define LLCC_COMMON_STATUS0 0x0003000c
#define LLCC_LB_CNT_MASK GENMASK(31, 28)
#define LLCC_LB_CNT_SHIFT 28
#define MAX_CAP_TO_BYTES(n) (n * SZ_1K)
#define LLCC_TRP_ACT_CTRLn(n) (n * SZ_4K)
#define LLCC_TRP_STATUSn(n) (4 + n * SZ_4K)
#define LLCC_TRP_ATTR0_CFGn(n) (0x21000 + SZ_8 * n)
#define LLCC_TRP_ATTR1_CFGn(n) (0x21004 + SZ_8 * n)
#define BANK_OFFSET_STRIDE 0x80000
static struct llcc_drv_data *drv_data;
static const struct regmap_config llcc_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.fast_io = true,
};
/**
* llcc_slice_getd - get llcc slice descriptor
* @uid: usecase_id for the client
*
* A pointer to llcc slice descriptor will be returned on success and
* and error pointer is returned on failure
*/
struct llcc_slice_desc *llcc_slice_getd(u32 uid)
{
const struct llcc_slice_config *cfg;
struct llcc_slice_desc *desc;
u32 sz, count;
cfg = drv_data->cfg;
sz = drv_data->cfg_size;
for (count = 0; cfg && count < sz; count++, cfg++)
if (cfg->usecase_id == uid)
break;
if (count == sz || !cfg)
return ERR_PTR(-ENODEV);
desc = kzalloc(sizeof(*desc), GFP_KERNEL);
if (!desc)
return ERR_PTR(-ENOMEM);
desc->slice_id = cfg->slice_id;
desc->slice_size = cfg->max_cap;
return desc;
}
EXPORT_SYMBOL_GPL(llcc_slice_getd);
/**
* llcc_slice_putd - llcc slice descritpor
* @desc: Pointer to llcc slice descriptor
*/
void llcc_slice_putd(struct llcc_slice_desc *desc)
{
kfree(desc);
}
EXPORT_SYMBOL_GPL(llcc_slice_putd);
static int llcc_update_act_ctrl(u32 sid,
u32 act_ctrl_reg_val, u32 status)
{
u32 act_ctrl_reg;
u32 status_reg;
u32 slice_status;
int ret;
act_ctrl_reg = drv_data->bcast_off + LLCC_TRP_ACT_CTRLn(sid);
status_reg = drv_data->bcast_off + LLCC_TRP_STATUSn(sid);
/* Set the ACTIVE trigger */
act_ctrl_reg_val |= ACT_CTRL_ACT_TRIG;
ret = regmap_write(drv_data->regmap, act_ctrl_reg, act_ctrl_reg_val);
if (ret)
return ret;
/* Clear the ACTIVE trigger */
act_ctrl_reg_val &= ~ACT_CTRL_ACT_TRIG;
ret = regmap_write(drv_data->regmap, act_ctrl_reg, act_ctrl_reg_val);
if (ret)
return ret;
ret = regmap_read_poll_timeout(drv_data->regmap, status_reg,
slice_status, !(slice_status & status),
0, LLCC_STATUS_READ_DELAY);
return ret;
}
/**
* llcc_slice_activate - Activate the llcc slice
* @desc: Pointer to llcc slice descriptor
*
* A value of zero will be returned on success and a negative errno will
* be returned in error cases
*/
int llcc_slice_activate(struct llcc_slice_desc *desc)
{
int ret;
u32 act_ctrl_val;
mutex_lock(&drv_data->lock);
if (test_bit(desc->slice_id, drv_data->bitmap)) {
mutex_unlock(&drv_data->lock);
return 0;
}
act_ctrl_val = ACT_CTRL_OPCODE_ACTIVATE << ACT_CTRL_OPCODE_SHIFT;
ret = llcc_update_act_ctrl(desc->slice_id, act_ctrl_val,
DEACTIVATE);
if (ret) {
mutex_unlock(&drv_data->lock);
return ret;
}
__set_bit(desc->slice_id, drv_data->bitmap);
mutex_unlock(&drv_data->lock);
return ret;
}
EXPORT_SYMBOL_GPL(llcc_slice_activate);
/**
* llcc_slice_deactivate - Deactivate the llcc slice
* @desc: Pointer to llcc slice descriptor
*
* A value of zero will be returned on success and a negative errno will
* be returned in error cases
*/
int llcc_slice_deactivate(struct llcc_slice_desc *desc)
{
u32 act_ctrl_val;
int ret;
mutex_lock(&drv_data->lock);
if (!test_bit(desc->slice_id, drv_data->bitmap)) {
mutex_unlock(&drv_data->lock);
return 0;
}
act_ctrl_val = ACT_CTRL_OPCODE_DEACTIVATE << ACT_CTRL_OPCODE_SHIFT;
ret = llcc_update_act_ctrl(desc->slice_id, act_ctrl_val,
ACTIVATE);
if (ret) {
mutex_unlock(&drv_data->lock);
return ret;
}
__clear_bit(desc->slice_id, drv_data->bitmap);
mutex_unlock(&drv_data->lock);
return ret;
}
EXPORT_SYMBOL_GPL(llcc_slice_deactivate);
/**
* llcc_get_slice_id - return the slice id
* @desc: Pointer to llcc slice descriptor
*/
int llcc_get_slice_id(struct llcc_slice_desc *desc)
{
return desc->slice_id;
}
EXPORT_SYMBOL_GPL(llcc_get_slice_id);
/**
* llcc_get_slice_size - return the slice id
* @desc: Pointer to llcc slice descriptor
*/
size_t llcc_get_slice_size(struct llcc_slice_desc *desc)
{
return desc->slice_size;
}
EXPORT_SYMBOL_GPL(llcc_get_slice_size);
static int qcom_llcc_cfg_program(struct platform_device *pdev)
{
int i;
u32 attr1_cfg;
u32 attr0_cfg;
u32 attr1_val;
u32 attr0_val;
u32 max_cap_cacheline;
u32 sz;
int ret;
const struct llcc_slice_config *llcc_table;
struct llcc_slice_desc desc;
u32 bcast_off = drv_data->bcast_off;
sz = drv_data->cfg_size;
llcc_table = drv_data->cfg;
for (i = 0; i < sz; i++) {
attr1_cfg = bcast_off +
LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id);
attr0_cfg = bcast_off +
LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id);
attr1_val = llcc_table[i].cache_mode;
attr1_val |= llcc_table[i].probe_target_ways <<
ATTR1_PROBE_TARGET_WAYS_SHIFT;
attr1_val |= llcc_table[i].fixed_size <<
ATTR1_FIXED_SIZE_SHIFT;
attr1_val |= llcc_table[i].priority <<
ATTR1_PRIORITY_SHIFT;
max_cap_cacheline = MAX_CAP_TO_BYTES(llcc_table[i].max_cap);
/* LLCC instances can vary for each target.
* The SW writes to broadcast register which gets propagated
* to each llcc instace (llcc0,.. llccN).
* Since the size of the memory is divided equally amongst the
* llcc instances, we need to configure the max cap accordingly.
*/
max_cap_cacheline = max_cap_cacheline / drv_data->num_banks;
max_cap_cacheline >>= CACHE_LINE_SIZE_SHIFT;
attr1_val |= max_cap_cacheline << ATTR1_MAX_CAP_SHIFT;
attr0_val = llcc_table[i].res_ways & ATTR0_RES_WAYS_MASK;
attr0_val |= llcc_table[i].bonus_ways << ATTR0_BONUS_WAYS_SHIFT;
ret = regmap_write(drv_data->regmap, attr1_cfg, attr1_val);
if (ret)
return ret;
ret = regmap_write(drv_data->regmap, attr0_cfg, attr0_val);
if (ret)
return ret;
if (llcc_table[i].activate_on_init) {
desc.slice_id = llcc_table[i].slice_id;
ret = llcc_slice_activate(&desc);
}
}
return ret;
}
int qcom_llcc_probe(struct platform_device *pdev,
const struct llcc_slice_config *llcc_cfg, u32 sz)
{
u32 num_banks;
struct device *dev = &pdev->dev;
struct resource *res;
void __iomem *base;
int ret, i;
drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL);
if (!drv_data)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
drv_data->regmap = devm_regmap_init_mmio(dev, base,
&llcc_regmap_config);
if (IS_ERR(drv_data->regmap))
return PTR_ERR(drv_data->regmap);
ret = regmap_read(drv_data->regmap, LLCC_COMMON_STATUS0,
&num_banks);
if (ret)
return ret;
num_banks &= LLCC_LB_CNT_MASK;
num_banks >>= LLCC_LB_CNT_SHIFT;
drv_data->num_banks = num_banks;
for (i = 0; i < sz; i++)
if (llcc_cfg[i].slice_id > drv_data->max_slices)
drv_data->max_slices = llcc_cfg[i].slice_id;
drv_data->offsets = devm_kcalloc(dev, num_banks, sizeof(u32),
GFP_KERNEL);
if (!drv_data->offsets)
return -ENOMEM;
for (i = 0; i < num_banks; i++)
drv_data->offsets[i] = i * BANK_OFFSET_STRIDE;
drv_data->bcast_off = num_banks * BANK_OFFSET_STRIDE;
drv_data->bitmap = devm_kcalloc(dev,
BITS_TO_LONGS(drv_data->max_slices), sizeof(unsigned long),
GFP_KERNEL);
if (!drv_data->bitmap)
return -ENOMEM;
drv_data->cfg = llcc_cfg;
drv_data->cfg_size = sz;
mutex_init(&drv_data->lock);
platform_set_drvdata(pdev, drv_data);
return qcom_llcc_cfg_program(pdev);
}
EXPORT_SYMBOL_GPL(qcom_llcc_probe);
MODULE_LICENSE("GPL v2");
......@@ -184,6 +184,7 @@ static int qcom_rmtfs_mem_probe(struct platform_device *pdev)
device_initialize(&rmtfs_mem->dev);
rmtfs_mem->dev.parent = &pdev->dev;
rmtfs_mem->dev.groups = qcom_rmtfs_mem_groups;
rmtfs_mem->dev.release = qcom_rmtfs_mem_release_device;
rmtfs_mem->base = devm_memremap(&rmtfs_mem->dev, rmtfs_mem->addr,
rmtfs_mem->size, MEMREMAP_WC);
......@@ -206,8 +207,6 @@ static int qcom_rmtfs_mem_probe(struct platform_device *pdev)
goto put_device;
}
rmtfs_mem->dev.release = qcom_rmtfs_mem_release_device;
ret = of_property_read_u32(node, "qcom,vmid", &vmid);
if (ret < 0 && ret != -EINVAL) {
dev_err(&pdev->dev, "failed to parse qcom,vmid\n");
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
*/
#ifndef __RPM_INTERNAL_H__
#define __RPM_INTERNAL_H__
#include <linux/bitmap.h>
#include <soc/qcom/tcs.h>
#define TCS_TYPE_NR 4
#define MAX_CMDS_PER_TCS 16
#define MAX_TCS_PER_TYPE 3
#define MAX_TCS_NR (MAX_TCS_PER_TYPE * TCS_TYPE_NR)
#define MAX_TCS_SLOTS (MAX_CMDS_PER_TCS * MAX_TCS_PER_TYPE)
struct rsc_drv;
/**
* struct tcs_group: group of Trigger Command Sets (TCS) to send state requests
* to the controller
*
* @drv: the controller
* @type: type of the TCS in this group - active, sleep, wake
* @mask: mask of the TCSes relative to all the TCSes in the RSC
* @offset: start of the TCS group relative to the TCSes in the RSC
* @num_tcs: number of TCSes in this type
* @ncpt: number of commands in each TCS
* @lock: lock for synchronizing this TCS writes
* @req: requests that are sent from the TCS
* @cmd_cache: flattened cache of cmds in sleep/wake TCS
* @slots: indicates which of @cmd_addr are occupied
*/
struct tcs_group {
struct rsc_drv *drv;
int type;
u32 mask;
u32 offset;
int num_tcs;
int ncpt;
spinlock_t lock;
const struct tcs_request *req[MAX_TCS_PER_TYPE];
u32 *cmd_cache;
DECLARE_BITMAP(slots, MAX_TCS_SLOTS);
};
/**
* struct rpmh_request: the message to be sent to rpmh-rsc
*
* @msg: the request
* @cmd: the payload that will be part of the @msg
* @completion: triggered when request is done
* @dev: the device making the request
* @err: err return from the controller
* @needs_free: check to free dynamically allocated request object
*/
struct rpmh_request {
struct tcs_request msg;
struct tcs_cmd cmd[MAX_RPMH_PAYLOAD];
struct completion *completion;
const struct device *dev;
int err;
bool needs_free;
};
/**
* struct rpmh_ctrlr: our representation of the controller
*
* @cache: the list of cached requests
* @cache_lock: synchronize access to the cache data
* @dirty: was the cache updated since flush
* @batch_cache: Cache sleep and wake requests sent as batch
*/
struct rpmh_ctrlr {
struct list_head cache;
spinlock_t cache_lock;
bool dirty;
struct list_head batch_cache;
};
/**
* struct rsc_drv: the Direct Resource Voter (DRV) of the
* Resource State Coordinator controller (RSC)
*
* @name: controller identifier
* @tcs_base: start address of the TCS registers in this controller
* @id: instance id in the controller (Direct Resource Voter)
* @num_tcs: number of TCSes in this DRV
* @tcs: TCS groups
* @tcs_in_use: s/w state of the TCS
* @lock: synchronize state of the controller
* @client: handle to the DRV's client.
*/
struct rsc_drv {
const char *name;
void __iomem *tcs_base;
int id;
int num_tcs;
struct tcs_group tcs[TCS_TYPE_NR];
DECLARE_BITMAP(tcs_in_use, MAX_TCS_NR);
spinlock_t lock;
struct rpmh_ctrlr client;
};
int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg);
int rpmh_rsc_write_ctrl_data(struct rsc_drv *drv,
const struct tcs_request *msg);
int rpmh_rsc_invalidate(struct rsc_drv *drv);
void rpmh_tx_done(const struct tcs_request *msg, int r);
#endif /* __RPM_INTERNAL_H__ */
This diff is collapsed.
This diff is collapsed.
......@@ -364,11 +364,6 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem,
end = phdr_to_last_uncached_entry(phdr);
cached = phdr_to_last_cached_entry(phdr);
if (smem->global_partition) {
dev_err(smem->dev, "Already found the global partition\n");
return -EINVAL;
}
while (hdr < end) {
if (hdr->canary != SMEM_PRIVATE_CANARY)
goto bad_canary;
......@@ -736,6 +731,11 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem)
bool found = false;
int i;
if (smem->global_partition) {
dev_err(smem->dev, "Already found the global partition\n");
return -EINVAL;
}
ptable = qcom_smem_get_ptable(smem);
if (IS_ERR(ptable))
return PTR_ERR(ptable);
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
*/
#if !defined(_TRACE_RPMH_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_RPMH_H
#undef TRACE_SYSTEM
#define TRACE_SYSTEM rpmh
#include <linux/tracepoint.h>
#include "rpmh-internal.h"
TRACE_EVENT(rpmh_tx_done,
TP_PROTO(struct rsc_drv *d, int m, const struct tcs_request *r, int e),
TP_ARGS(d, m, r, e),
TP_STRUCT__entry(
__string(name, d->name)
__field(int, m)
__field(u32, addr)
__field(u32, data)
__field(int, err)
),
TP_fast_assign(
__assign_str(name, d->name);
__entry->m = m;
__entry->addr = r->cmds[0].addr;
__entry->data = r->cmds[0].data;
__entry->err = e;
),
TP_printk("%s: ack: tcs-m: %d addr: %#x data: %#x errno: %d",
__get_str(name), __entry->m, __entry->addr, __entry->data,
__entry->err)
);
TRACE_EVENT(rpmh_send_msg,
TP_PROTO(struct rsc_drv *d, int m, int n, u32 h,
const struct tcs_cmd *c),
TP_ARGS(d, m, n, h, c),
TP_STRUCT__entry(
__string(name, d->name)
__field(int, m)
__field(int, n)
__field(u32, hdr)
__field(u32, addr)
__field(u32, data)
__field(bool, wait)
),
TP_fast_assign(
__assign_str(name, d->name);
__entry->m = m;
__entry->n = n;
__entry->hdr = h;
__entry->addr = c->addr;
__entry->data = c->data;
__entry->wait = c->wait;
),
TP_printk("%s: send-msg: tcs(m): %d cmd(n): %d msgid: %#x addr: %#x data: %#x complete: %d",
__get_str(name), __entry->m, __entry->n, __entry->hdr,
__entry->addr, __entry->data, __entry->wait)
);
#endif /* _TRACE_RPMH_H */
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH .
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_FILE trace-rpmh
#include <trace/define_trace.h>
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2014 Google, Inc
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Device Tree binding constants for the Maxim 77802 PMIC regulators
*/
......
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2018, The Linux Foundation. All rights reserved. */
#ifndef __QCOM_RPMH_REGULATOR_H
#define __QCOM_RPMH_REGULATOR_H
/*
* These mode constants may be used to specify modes for various RPMh regulator
* device tree properties (e.g. regulator-initial-mode). Each type of regulator
* supports a subset of the possible modes.
*
* %RPMH_REGULATOR_MODE_RET: Retention mode in which only an extremely small
* load current is allowed. This mode is supported
* by LDO and SMPS type regulators.
* %RPMH_REGULATOR_MODE_LPM: Low power mode in which a small load current is
* allowed. This mode corresponds to PFM for SMPS
* and BOB type regulators. This mode is supported
* by LDO, HFSMPS, BOB, and PMIC4 FTSMPS type
* regulators.
* %RPMH_REGULATOR_MODE_AUTO: Auto mode in which the regulator hardware
* automatically switches between LPM and HPM based
* upon the real-time load current. This mode is
* supported by HFSMPS, BOB, and PMIC4 FTSMPS type
* regulators.
* %RPMH_REGULATOR_MODE_HPM: High power mode in which the full rated current
* of the regulator is allowed. This mode
* corresponds to PWM for SMPS and BOB type
* regulators. This mode is supported by all types
* of regulators.
*/
#define RPMH_REGULATOR_MODE_RET 0
#define RPMH_REGULATOR_MODE_LPM 1
#define RPMH_REGULATOR_MODE_AUTO 2
#define RPMH_REGULATOR_MODE_HPM 3
#endif
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
*/
#ifndef __DT_QCOM_RPMH_RSC_H__
#define __DT_QCOM_RPMH_RSC_H__
#define SLEEP_TCS 0
#define WAKE_TCS 1
#define ACTIVE_TCS 2
#define CONTROL_TCS 3
#endif /* __DT_QCOM_RPMH_RSC_H__ */
......@@ -1316,6 +1316,7 @@ extern const char *dev_driver_string(const struct device *dev);
struct device_link *device_link_add(struct device *consumer,
struct device *supplier, u32 flags);
void device_link_del(struct device_link *link);
void device_link_remove(void *consumer, struct device *supplier);
#ifdef CONFIG_PRINTK
......
......@@ -87,6 +87,10 @@ static inline int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr,
static inline int
qcom_scm_pas_auth_and_reset(u32 peripheral) { return -ENODEV; }
static inline int qcom_scm_pas_shutdown(u32 peripheral) { return -ENODEV; }
static inline int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
unsigned int *src,
struct qcom_scm_vmperm *newvm,
int dest_cnt) { return -ENODEV; }
static inline void qcom_scm_cpu_power_down(u32 flags) {}
static inline u32 qcom_scm_get_version(void) { return 0; }
static inline u32
......
......@@ -46,7 +46,7 @@ enum regulator_status {
/**
* struct regulator_linear_range - specify linear voltage ranges
*
* Specify a range of voltages for regulator_map_linar_range() and
* Specify a range of voltages for regulator_map_linear_range() and
* regulator_list_linear_range().
*
* @min_uV: Lowest voltage in range
......@@ -220,7 +220,7 @@ struct regulator_ops {
/* set regulator suspend operating mode (defined in consumer.h) */
int (*set_suspend_mode) (struct regulator_dev *, unsigned int mode);
int (*resume_early)(struct regulator_dev *rdev);
int (*resume)(struct regulator_dev *rdev);
int (*set_pull_down) (struct regulator_dev *);
};
......
......@@ -64,6 +64,17 @@
#define PFUZE3000_VLDO3 11
#define PFUZE3000_VLDO4 12
#define PFUZE3001_SW1 0
#define PFUZE3001_SW2 1
#define PFUZE3001_SW3 2
#define PFUZE3001_VSNVS 3
#define PFUZE3001_VLDO1 4
#define PFUZE3001_VLDO2 5
#define PFUZE3001_VCCSD 6
#define PFUZE3001_V33 7
#define PFUZE3001_VLDO3 8
#define PFUZE3001_VLDO4 9
struct regulator_init_data;
struct pfuze_regulator_platform_data {
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
*
*/
#include <linux/platform_device.h>
#ifndef __LLCC_QCOM__
#define __LLCC_QCOM__
#define LLCC_CPUSS 1
#define LLCC_VIDSC0 2
#define LLCC_VIDSC1 3
#define LLCC_ROTATOR 4
#define LLCC_VOICE 5
#define LLCC_AUDIO 6
#define LLCC_MDMHPGRW 7
#define LLCC_MDM 8
#define LLCC_CMPT 10
#define LLCC_GPUHTW 11
#define LLCC_GPU 12
#define LLCC_MMUHWT 13
#define LLCC_CMPTDMA 15
#define LLCC_DISP 16
#define LLCC_VIDFW 17
#define LLCC_MDMHPFX 20
#define LLCC_MDMPNG 21
#define LLCC_AUDHW 22
/**
* llcc_slice_desc - Cache slice descriptor
* @slice_id: llcc slice id
* @slice_size: Size allocated for the llcc slice
*/
struct llcc_slice_desc {
u32 slice_id;
size_t slice_size;
};
/**
* llcc_slice_config - Data associated with the llcc slice
* @usecase_id: usecase id for which the llcc slice is used
* @slice_id: llcc slice id assigned to each slice
* @max_cap: maximum capacity of the llcc slice
* @priority: priority of the llcc slice
* @fixed_size: whether the llcc slice can grow beyond its size
* @bonus_ways: bonus ways associated with llcc slice
* @res_ways: reserved ways associated with llcc slice
* @cache_mode: mode of the llcc slice
* @probe_target_ways: Probe only reserved and bonus ways on a cache miss
* @dis_cap_alloc: Disable capacity based allocation
* @retain_on_pc: Retain through power collapse
* @activate_on_init: activate the slice on init
*/
struct llcc_slice_config {
u32 usecase_id;
u32 slice_id;
u32 max_cap;
u32 priority;
bool fixed_size;
u32 bonus_ways;
u32 res_ways;
u32 cache_mode;
u32 probe_target_ways;
bool dis_cap_alloc;
bool retain_on_pc;
bool activate_on_init;
};
/**
* llcc_drv_data - Data associated with the llcc driver
* @regmap: regmap associated with the llcc device
* @cfg: pointer to the data structure for slice configuration
* @lock: mutex associated with each slice
* @cfg_size: size of the config data table
* @max_slices: max slices as read from device tree
* @bcast_off: Offset of the broadcast bank
* @num_banks: Number of llcc banks
* @bitmap: Bit map to track the active slice ids
* @offsets: Pointer to the bank offsets array
*/
struct llcc_drv_data {
struct regmap *regmap;
const struct llcc_slice_config *cfg;
struct mutex lock;
u32 cfg_size;
u32 max_slices;
u32 bcast_off;
u32 num_banks;
unsigned long *bitmap;
u32 *offsets;
};
#if IS_ENABLED(CONFIG_QCOM_LLCC)
/**
* llcc_slice_getd - get llcc slice descriptor
* @uid: usecase_id of the client
*/
struct llcc_slice_desc *llcc_slice_getd(u32 uid);
/**
* llcc_slice_putd - llcc slice descritpor
* @desc: Pointer to llcc slice descriptor
*/
void llcc_slice_putd(struct llcc_slice_desc *desc);
/**
* llcc_get_slice_id - get slice id
* @desc: Pointer to llcc slice descriptor
*/
int llcc_get_slice_id(struct llcc_slice_desc *desc);
/**
* llcc_get_slice_size - llcc slice size
* @desc: Pointer to llcc slice descriptor
*/
size_t llcc_get_slice_size(struct llcc_slice_desc *desc);
/**
* llcc_slice_activate - Activate the llcc slice
* @desc: Pointer to llcc slice descriptor
*/
int llcc_slice_activate(struct llcc_slice_desc *desc);
/**
* llcc_slice_deactivate - Deactivate the llcc slice
* @desc: Pointer to llcc slice descriptor
*/
int llcc_slice_deactivate(struct llcc_slice_desc *desc);
/**
* qcom_llcc_probe - program the sct table
* @pdev: platform device pointer
* @table: soc sct table
* @sz: Size of the config table
*/
int qcom_llcc_probe(struct platform_device *pdev,
const struct llcc_slice_config *table, u32 sz);
#else
static inline struct llcc_slice_desc *llcc_slice_getd(u32 uid)
{
return NULL;
}
static inline void llcc_slice_putd(struct llcc_slice_desc *desc)
{
};
static inline int llcc_get_slice_id(struct llcc_slice_desc *desc)
{
return -EINVAL;
}
static inline size_t llcc_get_slice_size(struct llcc_slice_desc *desc)
{
return 0;
}
static inline int llcc_slice_activate(struct llcc_slice_desc *desc)
{
return -EINVAL;
}
static inline int llcc_slice_deactivate(struct llcc_slice_desc *desc)
{
return -EINVAL;
}
static inline int qcom_llcc_probe(struct platform_device *pdev,
const struct llcc_slice_config *table, u32 sz)
{
return -ENODEV;
}
static inline int qcom_llcc_remove(struct platform_device *pdev)
{
return -ENODEV;
}
#endif
#endif
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
*/
#ifndef __SOC_QCOM_RPMH_H__
#define __SOC_QCOM_RPMH_H__
#include <soc/qcom/tcs.h>
#include <linux/platform_device.h>
#if IS_ENABLED(CONFIG_QCOM_RPMH)
int rpmh_write(const struct device *dev, enum rpmh_state state,
const struct tcs_cmd *cmd, u32 n);
int rpmh_write_async(const struct device *dev, enum rpmh_state state,
const struct tcs_cmd *cmd, u32 n);
int rpmh_write_batch(const struct device *dev, enum rpmh_state state,
const struct tcs_cmd *cmd, u32 *n);
int rpmh_flush(const struct device *dev);
int rpmh_invalidate(const struct device *dev);
#else
static inline int rpmh_write(const struct device *dev, enum rpmh_state state,
const struct tcs_cmd *cmd, u32 n)
{ return -ENODEV; }
static inline int rpmh_write_async(const struct device *dev,
enum rpmh_state state,
const struct tcs_cmd *cmd, u32 n)
{ return -ENODEV; }
static inline int rpmh_write_batch(const struct device *dev,
enum rpmh_state state,
const struct tcs_cmd *cmd, u32 *n)
{ return -ENODEV; }
static inline int rpmh_flush(const struct device *dev)
{ return -ENODEV; }
static inline int rpmh_invalidate(const struct device *dev)
{ return -ENODEV; }
#endif /* CONFIG_QCOM_RPMH */
#endif /* __SOC_QCOM_RPMH_H__ */
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment