2014-06-16 18:46:21

by Bjorn Andersson

[permalink] [raw]
Subject: [PATCH v3 0/3] Qualcomm Resource Power Manager driver

This series adds a regulator driver for the Resource Power Manager found in
Qualcomm 8660, 8960 and 8064 based devices.

The RPM driver exposes resources to its child devices, that can be accessed to
implement drivers for the regulators, clocks and bus frequency control that's
owned by the RPM in these devices.

Changes since v2:
- Fix copy-paste error in dt binding
- Correct incomplete move from mfd to soc
- Correct const mistake in regulator driver

Changes since v1:
- Moved rpm driver to drivers/soc
- Extracted resource table structs from rpm struct, as per Srinivas request
- Dropped mode setting support for the regulators for now. Unsure if we need
it and it requires some rework from the codeaurora solution.
- Using set_voltage_sel instead of rolling my own "snapping", as per Marks
request
- Split regulator ops in mV, uV and swtich versions as per Marks request.
- Added devicetree property to enable pull down.

Bjorn Andersson (3):
soc: devicetree: bindings: Add Qualcomm RPM DT binding
soc: qcom-rpm: Driver for the Qualcomm RPM
regulator: qcom-rpm: Regulator driver for the Qualcomm RPM

.../devicetree/bindings/soc/qcom/qcom,rpm.txt | 261 +++++++
drivers/regulator/Kconfig | 12 +
drivers/regulator/Makefile | 1 +
drivers/regulator/qcom_rpm-regulator.c | 787 +++++++++++++++++++++
drivers/soc/qcom/Kconfig | 14 +
drivers/soc/qcom/Makefile | 1 +
drivers/soc/qcom/qcom_rpm.c | 573 +++++++++++++++
include/dt-bindings/soc/qcom,rpm.h | 142 ++++
include/linux/soc/qcom_rpm.h | 12 +
9 files changed, 1803 insertions(+)
create mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom,rpm.txt
create mode 100644 drivers/regulator/qcom_rpm-regulator.c
create mode 100644 drivers/soc/qcom/qcom_rpm.c
create mode 100644 include/dt-bindings/soc/qcom,rpm.h
create mode 100644 include/linux/soc/qcom_rpm.h

--
1.8.2.2


2014-06-16 18:46:27

by Bjorn Andersson

[permalink] [raw]
Subject: [PATCH v3 2/3] soc: qcom-rpm: Driver for the Qualcomm RPM

Driver for the Resource Power Manager (RPM) found in Qualcomm 8660, 8960
and 8064 based devices. The driver exposes resources that child drivers
can operate on; to implementing regulator, clock and bus frequency
drivers.

Signed-off-by: Bjorn Andersson <[email protected]>
---
drivers/soc/qcom/Kconfig | 14 ++
drivers/soc/qcom/Makefile | 1 +
drivers/soc/qcom/qcom_rpm.c | 573 +++++++++++++++++++++++++++++++++++++++++++
include/linux/soc/qcom_rpm.h | 12 +
4 files changed, 600 insertions(+)
create mode 100644 drivers/soc/qcom/qcom_rpm.c
create mode 100644 include/linux/soc/qcom_rpm.h

diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 7bd2c94..a8c2a96 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -9,3 +9,17 @@ config QCOM_GSBI
functions for connecting the underlying serial UART, SPI, and I2C
devices to the output pins.

+config QCOM_RPM
+ tristate "Qualcomm Resource Power Manager (RPM)"
+ depends on ARCH_QCOM && OF
+ help
+ If you say yes to this option, support will be included for the
+ Resource Power Manager system found in the Qualcomm 8660, 8960 and
+ 8064 based devices.
+
+ This is required to access many regulators, clocks and bus
+ frequencies controlled by the RPM on these devices.
+
+ Say M here if you want to include support for the Qualcomm RPM as a
+ module. This will build a module called "qcom_rpm".
+
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 4389012..e7706e8 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o
+obj-$(CONFIG_QCOM_RPM) += qcom_rpm.o
diff --git a/drivers/soc/qcom/qcom_rpm.c b/drivers/soc/qcom/qcom_rpm.c
new file mode 100644
index 0000000..6fc683a
--- /dev/null
+++ b/drivers/soc/qcom/qcom_rpm.c
@@ -0,0 +1,573 @@
+/*
+ * Copyright (c) 2014, Sony Mobile Communications AB.
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/soc/qcom_rpm.h>
+
+#include <dt-bindings/soc/qcom,rpm.h>
+
+struct qcom_rpm_resource {
+ unsigned target_id;
+ unsigned status_id;
+ unsigned select_id;
+ unsigned size;
+};
+
+struct qcom_rpm_data {
+ u32 version;
+ const struct qcom_rpm_resource *resource_table;
+ unsigned n_resources;
+};
+
+struct qcom_rpm {
+ struct device *dev;
+ struct completion ack;
+ struct mutex lock;
+
+ void __iomem *status_regs;
+ void __iomem *ctrl_regs;
+ void __iomem *req_regs;
+
+ void __iomem *ipc_rpm_reg;
+
+ u32 ack_status;
+
+ const struct qcom_rpm_data *data;
+};
+
+#define RPM_STATUS_REG(rpm, i) ((rpm)->status_regs + (i) * 4)
+#define RPM_CTRL_REG(rpm, i) ((rpm)->ctrl_regs + (i) * 4)
+#define RPM_REQ_REG(rpm, i) ((rpm)->req_regs + (i) * 4)
+
+#define RPM_REQUEST_TIMEOUT (5 * HZ)
+
+#define RPM_REQUEST_CONTEXT 3
+#define RPM_REQ_SELECT 11
+#define RPM_ACK_CONTEXT 15
+#define RPM_ACK_SELECTOR 23
+#define RPM_SELECT_SIZE 7
+
+#define RPM_ACTIVE_STATE BIT(0)
+#define RPM_NOTIFICATION BIT(30)
+#define RPM_REJECTED BIT(31)
+
+#define RPM_SIGNAL BIT(2)
+
+static const struct qcom_rpm_resource apq8064_rpm_resource_table[] = {
+ [QCOM_RPM_CXO_CLK] = { 25, 9, 5, 1 },
+ [QCOM_RPM_PXO_CLK] = { 26, 10, 6, 1 },
+ [QCOM_RPM_APPS_FABRIC_CLK] = { 27, 11, 8, 1 },
+ [QCOM_RPM_SYS_FABRIC_CLK] = { 28, 12, 9, 1 },
+ [QCOM_RPM_MM_FABRIC_CLK] = { 29, 13, 10, 1 },
+ [QCOM_RPM_DAYTONA_FABRIC_CLK] = { 30, 14, 11, 1 },
+ [QCOM_RPM_SFPB_CLK] = { 31, 15, 12, 1 },
+ [QCOM_RPM_CFPB_CLK] = { 32, 16, 13, 1 },
+ [QCOM_RPM_MMFPB_CLK] = { 33, 17, 14, 1 },
+ [QCOM_RPM_EBI1_CLK] = { 34, 18, 16, 1 },
+ [QCOM_RPM_APPS_FABRIC_HALT] = { 35, 19, 18, 1 },
+ [QCOM_RPM_APPS_FABRIC_MODE] = { 37, 20, 19, 1 },
+ [QCOM_RPM_APPS_FABRIC_IOCTL] = { 40, 21, 20, 1 },
+ [QCOM_RPM_APPS_FABRIC_ARB] = { 41, 22, 21, 12 },
+ [QCOM_RPM_SYS_FABRIC_HALT] = { 53, 23, 22, 1 },
+ [QCOM_RPM_SYS_FABRIC_MODE] = { 55, 24, 23, 1 },
+ [QCOM_RPM_SYS_FABRIC_IOCTL] = { 58, 25, 24, 1 },
+ [QCOM_RPM_SYS_FABRIC_ARB] = { 59, 26, 25, 30 },
+ [QCOM_RPM_MM_FABRIC_HALT] = { 89, 27, 26, 1 },
+ [QCOM_RPM_MM_FABRIC_MODE] = { 91, 28, 27, 1 },
+ [QCOM_RPM_MM_FABRIC_IOCTL] = { 94, 29, 28, 1 },
+ [QCOM_RPM_MM_FABRIC_ARB] = { 95, 30, 29, 21 },
+ [QCOM_RPM_PM8921_S1] = { 116, 31, 30, 2 },
+ [QCOM_RPM_PM8921_S2] = { 118, 33, 31, 2 },
+ [QCOM_RPM_PM8921_S3] = { 120, 35, 32, 2 },
+ [QCOM_RPM_PM8921_S4] = { 122, 37, 33, 2 },
+ [QCOM_RPM_PM8921_S5] = { 124, 39, 34, 2 },
+ [QCOM_RPM_PM8921_S6] = { 126, 41, 35, 2 },
+ [QCOM_RPM_PM8921_S7] = { 128, 43, 36, 2 },
+ [QCOM_RPM_PM8921_S8] = { 130, 45, 37, 2 },
+ [QCOM_RPM_PM8921_L1] = { 132, 47, 38, 2 },
+ [QCOM_RPM_PM8921_L2] = { 134, 49, 39, 2 },
+ [QCOM_RPM_PM8921_L3] = { 136, 51, 40, 2 },
+ [QCOM_RPM_PM8921_L4] = { 138, 53, 41, 2 },
+ [QCOM_RPM_PM8921_L5] = { 140, 55, 42, 2 },
+ [QCOM_RPM_PM8921_L6] = { 142, 57, 43, 2 },
+ [QCOM_RPM_PM8921_L7] = { 144, 59, 44, 2 },
+ [QCOM_RPM_PM8921_L8] = { 146, 61, 45, 2 },
+ [QCOM_RPM_PM8921_L9] = { 148, 63, 46, 2 },
+ [QCOM_RPM_PM8921_L10] = { 150, 65, 47, 2 },
+ [QCOM_RPM_PM8921_L11] = { 152, 67, 48, 2 },
+ [QCOM_RPM_PM8921_L12] = { 154, 69, 49, 2 },
+ [QCOM_RPM_PM8921_L13] = { 156, 71, 50, 2 },
+ [QCOM_RPM_PM8921_L14] = { 158, 73, 51, 2 },
+ [QCOM_RPM_PM8921_L15] = { 160, 75, 52, 2 },
+ [QCOM_RPM_PM8921_L16] = { 162, 77, 53, 2 },
+ [QCOM_RPM_PM8921_L17] = { 164, 79, 54, 2 },
+ [QCOM_RPM_PM8921_L18] = { 166, 81, 55, 2 },
+ [QCOM_RPM_PM8921_L19] = { 168, 83, 56, 2 },
+ [QCOM_RPM_PM8921_L20] = { 170, 85, 57, 2 },
+ [QCOM_RPM_PM8921_L21] = { 172, 87, 58, 2 },
+ [QCOM_RPM_PM8921_L22] = { 174, 89, 59, 2 },
+ [QCOM_RPM_PM8921_L23] = { 176, 91, 60, 2 },
+ [QCOM_RPM_PM8921_L24] = { 178, 93, 61, 2 },
+ [QCOM_RPM_PM8921_L25] = { 180, 95, 62, 2 },
+ [QCOM_RPM_PM8921_L26] = { 182, 97, 63, 2 },
+ [QCOM_RPM_PM8921_L27] = { 184, 99, 64, 2 },
+ [QCOM_RPM_PM8921_L28] = { 186, 101, 65, 2 },
+ [QCOM_RPM_PM8921_L29] = { 188, 103, 66, 2 },
+ [QCOM_RPM_PM8921_CLK1] = { 190, 105, 67, 2 },
+ [QCOM_RPM_PM8921_CLK2] = { 192, 107, 68, 2 },
+ [QCOM_RPM_PM8921_LVS1] = { 194, 109, 69, 1 },
+ [QCOM_RPM_PM8921_LVS2] = { 195, 110, 70, 1 },
+ [QCOM_RPM_PM8921_LVS3] = { 196, 111, 71, 1 },
+ [QCOM_RPM_PM8921_LVS4] = { 197, 112, 72, 1 },
+ [QCOM_RPM_PM8921_LVS5] = { 198, 113, 73, 1 },
+ [QCOM_RPM_PM8921_LVS6] = { 199, 114, 74, 1 },
+ [QCOM_RPM_PM8921_LVS7] = { 200, 115, 75, 1 },
+ [QCOM_RPM_PM8821_S1] = { 201, 116, 76, 2 },
+ [QCOM_RPM_PM8821_S2] = { 203, 118, 77, 2 },
+ [QCOM_RPM_PM8821_L1] = { 205, 120, 78, 2 },
+ [QCOM_RPM_PM8921_NCP] = { 207, 122, 80, 2 },
+ [QCOM_RPM_CXO_BUFFERS] = { 209, 124, 81, 1 },
+ [QCOM_RPM_USB_OTG_SWITCH] = { 210, 125, 82, 1 },
+ [QCOM_RPM_HDMI_SWITCH] = { 211, 126, 83, 1 },
+ [QCOM_RPM_DDR_DMM] = { 212, 127, 84, 2 },
+ [QCOM_RPM_VDDMIN_GPIO] = { 215, 131, 89, 1 },
+};
+
+static const struct qcom_rpm_data apq8064_template = {
+ .version = 3,
+ .resource_table = apq8064_rpm_resource_table,
+ .n_resources = ARRAY_SIZE(apq8064_rpm_resource_table),
+};
+
+static const struct qcom_rpm_resource msm8660_rpm_resource_table[] = {
+ [QCOM_RPM_CXO_CLK] = { 32, 12, 5, 1 },
+ [QCOM_RPM_PXO_CLK] = { 33, 13, 6, 1 },
+ [QCOM_RPM_PLL_4] = { 34, 14, 7, 1 },
+ [QCOM_RPM_APPS_FABRIC_CLK] = { 35, 15, 8, 1 },
+ [QCOM_RPM_SYS_FABRIC_CLK] = { 36, 16, 9, 1 },
+ [QCOM_RPM_MM_FABRIC_CLK] = { 37, 17, 10, 1 },
+ [QCOM_RPM_DAYTONA_FABRIC_CLK] = { 38, 18, 11, 1 },
+ [QCOM_RPM_SFPB_CLK] = { 39, 19, 12, 1 },
+ [QCOM_RPM_CFPB_CLK] = { 40, 20, 13, 1 },
+ [QCOM_RPM_MMFPB_CLK] = { 41, 21, 14, 1 },
+ [QCOM_RPM_SMI_CLK] = { 42, 22, 15, 1 },
+ [QCOM_RPM_EBI1_CLK] = { 43, 23, 16, 1 },
+ [QCOM_RPM_APPS_L2_CACHE_CTL] = { 44, 24, 17, 1 },
+ [QCOM_RPM_APPS_FABRIC_HALT] = { 45, 25, 18, 2 },
+ [QCOM_RPM_APPS_FABRIC_MODE] = { 47, 26, 19, 3 },
+ [QCOM_RPM_APPS_FABRIC_ARB] = { 51, 28, 21, 6 },
+ [QCOM_RPM_SYS_FABRIC_HALT] = { 63, 29, 22, 2 },
+ [QCOM_RPM_SYS_FABRIC_MODE] = { 65, 30, 23, 3 },
+ [QCOM_RPM_SYS_FABRIC_ARB] = { 69, 32, 25, 22 },
+ [QCOM_RPM_MM_FABRIC_HALT] = { 105, 33, 26, 2 },
+ [QCOM_RPM_MM_FABRIC_MODE] = { 107, 34, 27, 3 },
+ [QCOM_RPM_MM_FABRIC_ARB] = { 111, 36, 29, 23 },
+ [QCOM_RPM_PM8901_SMPS0] = { 134, 37, 30, 2 },
+ [QCOM_RPM_PM8901_SMPS1] = { 136, 39, 31, 2 },
+ [QCOM_RPM_PM8901_SMPS2] = { 138, 41, 32, 2 },
+ [QCOM_RPM_PM8901_SMPS3] = { 140, 43, 33, 2 },
+ [QCOM_RPM_PM8901_SMPS4] = { 142, 45, 34, 2 },
+ [QCOM_RPM_PM8901_LDO0] = { 144, 47, 35, 2 },
+ [QCOM_RPM_PM8901_LDO1] = { 146, 49, 36, 2 },
+ [QCOM_RPM_PM8901_LDO2] = { 148, 51, 37, 2 },
+ [QCOM_RPM_PM8901_LDO3] = { 150, 53, 38, 2 },
+ [QCOM_RPM_PM8901_LDO4] = { 152, 55, 39, 2 },
+ [QCOM_RPM_PM8901_LDO5] = { 154, 57, 40, 2 },
+ [QCOM_RPM_PM8901_LDO6] = { 156, 59, 41, 2 },
+ [QCOM_RPM_PM8901_LVS0] = { 158, 61, 42, 1 },
+ [QCOM_RPM_PM8901_LVS1] = { 159, 62, 43, 1 },
+ [QCOM_RPM_PM8901_LVS2] = { 160, 63, 44, 1 },
+ [QCOM_RPM_PM8901_LVS3] = { 161, 64, 45, 1 },
+ [QCOM_RPM_PM8901_MVS] = { 162, 65, 46, 1 },
+ [QCOM_RPM_PM8058_SMPS0] = { 163, 66, 47, 2 },
+ [QCOM_RPM_PM8058_SMPS1] = { 165, 68, 48, 2 },
+ [QCOM_RPM_PM8058_SMPS2] = { 167, 70, 49, 2 },
+ [QCOM_RPM_PM8058_SMPS3] = { 169, 72, 50, 2 },
+ [QCOM_RPM_PM8058_SMPS4] = { 171, 74, 51, 2 },
+ [QCOM_RPM_PM8058_LDO0] = { 173, 76, 52, 2 },
+ [QCOM_RPM_PM8058_LDO1] = { 175, 78, 53, 2 },
+ [QCOM_RPM_PM8058_LDO2] = { 177, 80, 54, 2 },
+ [QCOM_RPM_PM8058_LDO3] = { 179, 82, 55, 2 },
+ [QCOM_RPM_PM8058_LDO4] = { 181, 84, 56, 2 },
+ [QCOM_RPM_PM8058_LDO5] = { 183, 86, 57, 2 },
+ [QCOM_RPM_PM8058_LDO6] = { 185, 88, 58, 2 },
+ [QCOM_RPM_PM8058_LDO7] = { 187, 90, 59, 2 },
+ [QCOM_RPM_PM8058_LDO8] = { 189, 92, 60, 2 },
+ [QCOM_RPM_PM8058_LDO9] = { 191, 94, 61, 2 },
+ [QCOM_RPM_PM8058_LDO10] = { 193, 96, 62, 2 },
+ [QCOM_RPM_PM8058_LDO11] = { 195, 98, 63, 2 },
+ [QCOM_RPM_PM8058_LDO12] = { 197, 100, 64, 2 },
+ [QCOM_RPM_PM8058_LDO13] = { 199, 102, 65, 2 },
+ [QCOM_RPM_PM8058_LDO14] = { 201, 104, 66, 2 },
+ [QCOM_RPM_PM8058_LDO15] = { 203, 106, 67, 2 },
+ [QCOM_RPM_PM8058_LDO16] = { 205, 108, 68, 2 },
+ [QCOM_RPM_PM8058_LDO17] = { 207, 110, 69, 2 },
+ [QCOM_RPM_PM8058_LDO18] = { 209, 112, 70, 2 },
+ [QCOM_RPM_PM8058_LDO19] = { 211, 114, 71, 2 },
+ [QCOM_RPM_PM8058_LDO20] = { 213, 116, 72, 2 },
+ [QCOM_RPM_PM8058_LDO21] = { 215, 118, 73, 2 },
+ [QCOM_RPM_PM8058_LDO22] = { 217, 120, 74, 2 },
+ [QCOM_RPM_PM8058_LDO23] = { 219, 122, 75, 2 },
+ [QCOM_RPM_PM8058_LDO24] = { 221, 124, 76, 2 },
+ [QCOM_RPM_PM8058_LDO25] = { 223, 126, 77, 2 },
+ [QCOM_RPM_PM8058_LVS0] = { 225, 128, 78, 1 },
+ [QCOM_RPM_PM8058_LVS1] = { 226, 129, 79, 1 },
+ [QCOM_RPM_PM8058_NCP] = { 227, 130, 80, 2 },
+ [QCOM_RPM_CXO_BUFFERS] = { 229, 132, 81, 1 },
+};
+
+static const struct qcom_rpm_data msm8660_template = {
+ .version = -1,
+ .resource_table = msm8660_rpm_resource_table,
+ .n_resources = ARRAY_SIZE(msm8660_rpm_resource_table),
+};
+
+static const struct qcom_rpm_resource msm8960_rpm_resource_table[] = {
+ [QCOM_RPM_CXO_CLK] = { 25, 9, 5, 1 },
+ [QCOM_RPM_PXO_CLK] = { 26, 10, 6, 1 },
+ [QCOM_RPM_APPS_FABRIC_CLK] = { 27, 11, 8, 1 },
+ [QCOM_RPM_SYS_FABRIC_CLK] = { 28, 12, 9, 1 },
+ [QCOM_RPM_MM_FABRIC_CLK] = { 29, 13, 10, 1 },
+ [QCOM_RPM_DAYTONA_FABRIC_CLK] = { 30, 14, 11, 1 },
+ [QCOM_RPM_SFPB_CLK] = { 31, 15, 12, 1 },
+ [QCOM_RPM_CFPB_CLK] = { 32, 16, 13, 1 },
+ [QCOM_RPM_MMFPB_CLK] = { 33, 17, 14, 1 },
+ [QCOM_RPM_EBI1_CLK] = { 34, 18, 16, 1 },
+ [QCOM_RPM_APPS_FABRIC_HALT] = { 35, 19, 18, 1 },
+ [QCOM_RPM_APPS_FABRIC_MODE] = { 37, 20, 19, 1 },
+ [QCOM_RPM_APPS_FABRIC_IOCTL] = { 40, 21, 20, 1 },
+ [QCOM_RPM_APPS_FABRIC_ARB] = { 41, 22, 21, 12 },
+ [QCOM_RPM_SYS_FABRIC_HALT] = { 53, 23, 22, 1 },
+ [QCOM_RPM_SYS_FABRIC_MODE] = { 55, 24, 23, 1 },
+ [QCOM_RPM_SYS_FABRIC_IOCTL] = { 58, 25, 24, 1 },
+ [QCOM_RPM_SYS_FABRIC_ARB] = { 59, 26, 25, 29 },
+ [QCOM_RPM_MM_FABRIC_HALT] = { 88, 27, 26, 1 },
+ [QCOM_RPM_MM_FABRIC_MODE] = { 90, 28, 27, 1 },
+ [QCOM_RPM_MM_FABRIC_IOCTL] = { 93, 29, 28, 1 },
+ [QCOM_RPM_MM_FABRIC_ARB] = { 94, 30, 29, 23 },
+ [QCOM_RPM_PM8921_S1] = { 117, 31, 30, 2 },
+ [QCOM_RPM_PM8921_S2] = { 119, 33, 31, 2 },
+ [QCOM_RPM_PM8921_S3] = { 121, 35, 32, 2 },
+ [QCOM_RPM_PM8921_S4] = { 123, 37, 33, 2 },
+ [QCOM_RPM_PM8921_S5] = { 125, 39, 34, 2 },
+ [QCOM_RPM_PM8921_S6] = { 127, 41, 35, 2 },
+ [QCOM_RPM_PM8921_S7] = { 129, 43, 36, 2 },
+ [QCOM_RPM_PM8921_S8] = { 131, 45, 37, 2 },
+ [QCOM_RPM_PM8921_L1] = { 133, 47, 38, 2 },
+ [QCOM_RPM_PM8921_L2] = { 135, 49, 39, 2 },
+ [QCOM_RPM_PM8921_L3] = { 137, 51, 40, 2 },
+ [QCOM_RPM_PM8921_L4] = { 139, 53, 41, 2 },
+ [QCOM_RPM_PM8921_L5] = { 141, 55, 42, 2 },
+ [QCOM_RPM_PM8921_L6] = { 143, 57, 43, 2 },
+ [QCOM_RPM_PM8921_L7] = { 145, 59, 44, 2 },
+ [QCOM_RPM_PM8921_L8] = { 147, 61, 45, 2 },
+ [QCOM_RPM_PM8921_L9] = { 149, 63, 46, 2 },
+ [QCOM_RPM_PM8921_L10] = { 151, 65, 47, 2 },
+ [QCOM_RPM_PM8921_L11] = { 153, 67, 48, 2 },
+ [QCOM_RPM_PM8921_L12] = { 155, 69, 49, 2 },
+ [QCOM_RPM_PM8921_L13] = { 157, 71, 50, 2 },
+ [QCOM_RPM_PM8921_L14] = { 159, 73, 51, 2 },
+ [QCOM_RPM_PM8921_L15] = { 161, 75, 52, 2 },
+ [QCOM_RPM_PM8921_L16] = { 163, 77, 53, 2 },
+ [QCOM_RPM_PM8921_L17] = { 165, 79, 54, 2 },
+ [QCOM_RPM_PM8921_L18] = { 167, 81, 55, 2 },
+ [QCOM_RPM_PM8921_L19] = { 169, 83, 56, 2 },
+ [QCOM_RPM_PM8921_L20] = { 171, 85, 57, 2 },
+ [QCOM_RPM_PM8921_L21] = { 173, 87, 58, 2 },
+ [QCOM_RPM_PM8921_L22] = { 175, 89, 59, 2 },
+ [QCOM_RPM_PM8921_L23] = { 177, 91, 60, 2 },
+ [QCOM_RPM_PM8921_L24] = { 179, 93, 61, 2 },
+ [QCOM_RPM_PM8921_L25] = { 181, 95, 62, 2 },
+ [QCOM_RPM_PM8921_L26] = { 183, 97, 63, 2 },
+ [QCOM_RPM_PM8921_L27] = { 185, 99, 64, 2 },
+ [QCOM_RPM_PM8921_L28] = { 187, 101, 65, 2 },
+ [QCOM_RPM_PM8921_L29] = { 189, 103, 66, 2 },
+ [QCOM_RPM_PM8921_CLK1] = { 191, 105, 67, 2 },
+ [QCOM_RPM_PM8921_CLK2] = { 193, 107, 68, 2 },
+ [QCOM_RPM_PM8921_LVS1] = { 195, 109, 69, 1 },
+ [QCOM_RPM_PM8921_LVS2] = { 196, 110, 70, 1 },
+ [QCOM_RPM_PM8921_LVS3] = { 197, 111, 71, 1 },
+ [QCOM_RPM_PM8921_LVS4] = { 198, 112, 72, 1 },
+ [QCOM_RPM_PM8921_LVS5] = { 199, 113, 73, 1 },
+ [QCOM_RPM_PM8921_LVS6] = { 200, 114, 74, 1 },
+ [QCOM_RPM_PM8921_LVS7] = { 201, 115, 75, 1 },
+ [QCOM_RPM_PM8921_NCP] = { 202, 116, 80, 2 },
+ [QCOM_RPM_CXO_BUFFERS] = { 204, 118, 81, 1 },
+ [QCOM_RPM_USB_OTG_SWITCH] = { 205, 119, 82, 1 },
+ [QCOM_RPM_HDMI_SWITCH] = { 206, 120, 83, 1 },
+ [QCOM_RPM_DDR_DMM] = { 207, 121, 84, 2 },
+};
+
+static const struct qcom_rpm_data msm8960_template = {
+ .version = 3,
+ .resource_table = msm8960_rpm_resource_table,
+ .n_resources = ARRAY_SIZE(msm8960_rpm_resource_table),
+};
+
+static const struct of_device_id qcom_rpm_of_match[] = {
+ { .compatible = "qcom,rpm-apq8064", .data = &apq8064_template },
+ { .compatible = "qcom,rpm-msm8660", .data = &msm8660_template },
+ { .compatible = "qcom,rpm-msm8960", .data = &msm8960_template },
+ { }
+};
+MODULE_DEVICE_TABLE(of, qcom_rpm_of_match);
+
+struct qcom_rpm *dev_get_qcom_rpm(struct device *dev)
+{
+ return dev_get_drvdata(dev);
+}
+EXPORT_SYMBOL(dev_get_qcom_rpm);
+
+int qcom_rpm_write(struct qcom_rpm *rpm, int resource, u32 *buf, size_t count)
+{
+ const struct qcom_rpm_resource *res;
+ const struct qcom_rpm_data *data = rpm->data;
+ u32 sel_mask[RPM_SELECT_SIZE] = { 0 };
+ int left;
+ int ret = 0;
+ int i;
+
+ if (WARN_ON(resource < 0 || resource >= data->n_resources))
+ return -EINVAL;
+
+ res = &data->resource_table[resource];
+ if (WARN_ON(res->size != count))
+ return -EINVAL;
+
+ mutex_lock(&rpm->lock);
+
+ for (i = 0; i < res->size; i++)
+ writel_relaxed(buf[i], RPM_REQ_REG(rpm, res->target_id + i));
+
+ bitmap_set((unsigned long *)sel_mask, res->select_id, 1);
+ for (i = 0; i < ARRAY_SIZE(sel_mask); i++) {
+ writel_relaxed(sel_mask[i],
+ RPM_CTRL_REG(rpm, RPM_REQ_SELECT + i));
+ }
+
+ writel_relaxed(RPM_ACTIVE_STATE,
+ RPM_CTRL_REG(rpm, RPM_REQUEST_CONTEXT));
+
+ reinit_completion(&rpm->ack);
+ writel(RPM_SIGNAL, rpm->ipc_rpm_reg);
+
+ left = wait_for_completion_timeout(&rpm->ack, RPM_REQUEST_TIMEOUT);
+ if (!left)
+ ret = -ETIMEDOUT;
+ else if (rpm->ack_status & RPM_REJECTED)
+ ret = -EIO;
+
+ mutex_unlock(&rpm->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(qcom_rpm_write);
+
+static irqreturn_t qcom_rpm_ack_interrupt(int irq, void *dev)
+{
+ struct qcom_rpm *rpm = dev;
+ u32 ack;
+ int i;
+
+ ack = readl_relaxed(RPM_CTRL_REG(rpm, RPM_ACK_CONTEXT));
+ for (i = 0; i < RPM_SELECT_SIZE; i++)
+ writel_relaxed(0, RPM_CTRL_REG(rpm, RPM_ACK_SELECTOR + i));
+ writel(0, RPM_CTRL_REG(rpm, RPM_ACK_CONTEXT));
+
+ if (ack & RPM_NOTIFICATION) {
+ dev_warn(rpm->dev, "ignoring notification!\n");
+ } else {
+ rpm->ack_status = ack;
+ complete(&rpm->ack);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t qcom_rpm_err_interrupt(int irq, void *dev)
+{
+ struct qcom_rpm *rpm = dev;
+
+ writel(0x1, rpm->ipc_rpm_reg);
+
+ dev_err(rpm->dev, "RPM triggered fatal error\n");
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t qcom_rpm_wakeup_interrupt(int irq, void *dev)
+{
+ return IRQ_HANDLED;
+}
+
+static int qcom_rpm_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ struct resource *res;
+ struct qcom_rpm *rpm;
+ u32 fw_version[3];
+ int irq_wakeup;
+ int irq_ack;
+ int irq_err;
+ int ret;
+
+ rpm = devm_kzalloc(&pdev->dev, sizeof(*rpm), GFP_KERNEL);
+ if (!rpm) {
+ dev_err(&pdev->dev, "Can't allocate qcom_rpm\n");
+ return -ENOMEM;
+ }
+ rpm->dev = &pdev->dev;
+ mutex_init(&rpm->lock);
+ init_completion(&rpm->ack);
+
+ irq_ack = platform_get_irq_byname(pdev, "ack");
+ if (irq_ack < 0) {
+ dev_err(&pdev->dev, "required ack interrupt missing\n");
+ return irq_ack;
+ }
+
+ irq_err = platform_get_irq_byname(pdev, "err");
+ if (irq_err < 0) {
+ dev_err(&pdev->dev, "required err interrupt missing\n");
+ return irq_err;
+ }
+
+ irq_wakeup = platform_get_irq_byname(pdev, "wakeup");
+ if (irq_wakeup < 0) {
+ dev_err(&pdev->dev, "required wakeup interrupt missing\n");
+ return irq_wakeup;
+ }
+
+ match = of_match_device(qcom_rpm_of_match, &pdev->dev);
+ rpm->data = match->data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ rpm->status_regs = devm_ioremap_resource(&pdev->dev, res);
+ rpm->ctrl_regs = rpm->status_regs + 0x400;
+ rpm->req_regs = rpm->status_regs + 0x600;
+ if (IS_ERR(rpm->status_regs))
+ return PTR_ERR(rpm->status_regs);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ rpm->ipc_rpm_reg = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(rpm->ipc_rpm_reg))
+ return PTR_ERR(rpm->ipc_rpm_reg);
+
+ dev_set_drvdata(&pdev->dev, rpm);
+
+ fw_version[0] = readl(RPM_STATUS_REG(rpm, 0));
+ fw_version[1] = readl(RPM_STATUS_REG(rpm, 1));
+ fw_version[2] = readl(RPM_STATUS_REG(rpm, 2));
+ if (fw_version[0] != rpm->data->version) {
+ dev_err(&pdev->dev,
+ "RPM version %u.%u.%u incompatible with driver version %u",
+ fw_version[0],
+ fw_version[1],
+ fw_version[2],
+ rpm->data->version);
+ return -EFAULT;
+ }
+
+ dev_info(&pdev->dev, "RPM firmware %u.%u.%u\n", fw_version[0],
+ fw_version[1],
+ fw_version[2]);
+
+ writel(fw_version[0], RPM_CTRL_REG(rpm, 0));
+ writel(fw_version[1], RPM_CTRL_REG(rpm, 1));
+ writel(fw_version[2], RPM_CTRL_REG(rpm, 2));
+
+ ret = devm_request_irq(&pdev->dev,
+ irq_ack,
+ qcom_rpm_ack_interrupt,
+ IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND,
+ "qcom_rpm_ack",
+ rpm);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request ack interrupt\n");
+ return ret;
+ }
+
+ ret = irq_set_irq_wake(irq_ack, 1);
+ if (ret)
+ dev_warn(&pdev->dev, "failed to mark ack irq as wakeup\n");
+
+ ret = devm_request_irq(&pdev->dev,
+ irq_err,
+ qcom_rpm_err_interrupt,
+ IRQF_TRIGGER_RISING,
+ "qcom_rpm_err",
+ rpm);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request err interrupt\n");
+ return ret;
+ }
+
+ ret = devm_request_irq(&pdev->dev,
+ irq_wakeup,
+ qcom_rpm_wakeup_interrupt,
+ IRQF_TRIGGER_RISING,
+ "qcom_rpm_wakeup",
+ rpm);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request wakeup interrupt\n");
+ return ret;
+ }
+
+ ret = irq_set_irq_wake(irq_wakeup, 1);
+ if (ret)
+ dev_warn(&pdev->dev, "failed to mark wakeup irq as wakeup\n");
+
+ return of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+}
+
+static int qcom_rpm_remove_child(struct device *dev, void *unused)
+{
+ platform_device_unregister(to_platform_device(dev));
+ return 0;
+}
+
+static int qcom_rpm_remove(struct platform_device *pdev)
+{
+ device_for_each_child(&pdev->dev, NULL, qcom_rpm_remove_child);
+ return 0;
+}
+
+static struct platform_driver qcom_rpm_driver = {
+ .probe = qcom_rpm_probe,
+ .remove = qcom_rpm_remove,
+ .driver = {
+ .name = "qcom_rpm",
+ .owner = THIS_MODULE,
+ .of_match_table = qcom_rpm_of_match,
+ },
+};
+
+static int __init qcom_rpm_init(void)
+{
+ return platform_driver_register(&qcom_rpm_driver);
+}
+arch_initcall(qcom_rpm_init);
+
+static void __exit qcom_rpm_exit(void)
+{
+ platform_driver_unregister(&qcom_rpm_driver);
+}
+module_exit(qcom_rpm_exit)
+
+MODULE_DESCRIPTION("Qualcomm Resource Power Manager driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/soc/qcom_rpm.h b/include/linux/soc/qcom_rpm.h
new file mode 100644
index 0000000..a52bc37
--- /dev/null
+++ b/include/linux/soc/qcom_rpm.h
@@ -0,0 +1,12 @@
+#ifndef __QCOM_RPM_H__
+#define __QCOM_RPM_H__
+
+#include <linux/types.h>
+
+struct device;
+struct qcom_rpm;
+
+struct qcom_rpm *dev_get_qcom_rpm(struct device *dev);
+int qcom_rpm_write(struct qcom_rpm *rpm, int resource, u32 *buf, size_t count);
+
+#endif
--
1.8.2.2

2014-06-16 18:46:24

by Bjorn Andersson

[permalink] [raw]
Subject: [PATCH v3 1/3] soc: devicetree: bindings: Add Qualcomm RPM DT binding

Add binding for the Qualcomm Resource Power Manager (RPM) found in 8660,
8960 and 8064 based devices. The binding currently describes the rpm
itself and the regulator subnodes.

Signed-off-by: Bjorn Andersson <[email protected]>
---
.../devicetree/bindings/soc/qcom/qcom,rpm.txt | 260 +++++++++++++++++++++
include/dt-bindings/soc/qcom,rpm.h | 142 +++++++++++
2 files changed, 402 insertions(+)
create mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom,rpm.txt
create mode 100644 include/dt-bindings/soc/qcom,rpm.h

diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,rpm.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,rpm.txt
new file mode 100644
index 0000000..0366533
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/qcom/qcom,rpm.txt
@@ -0,0 +1,260 @@
+Qualcomm Resource Power Manager (RPM)
+
+This driver is used to interface with the Resource Power Manager (RPM) found in
+various Qualcomm platforms. The RPM allows each component in the system to vote
+for state of the system resources, such as clocks, regulators and bus
+frequencies.
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be one of:
+ "qcom,rpm-apq8064"
+ "qcom,rpm-msm8660"
+ "qcom,rpm-msm8960"
+
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: two entries specifying the RPM's message ram and ipc register
+
+- reg-names:
+ Usage: required
+ Value type: <string-array>
+ Definition: must contain the following, in order:
+ "msg_ram"
+ "ipc"
+
+- interrupts:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: three entries specifying the RPM's:
+ 1. acknowledgement interrupt
+ 2. error interrupt
+ 3. wakeup interrupt
+
+- interrupt-names:
+ Usage: required
+ Value type: <string-array>
+ Definition: must be the three strings "ack", "err" and "wakeup", in order
+
+- #address-cells:
+ Usage: required
+ Value type: <u32>
+ Definition: must be 1
+
+- #size-cells:
+ Usage: required
+ Value type: <u32>
+ Definition: must be 0
+
+
+= SUBDEVICES
+
+The RPM exposes resources to its subnodes. The below bindings specify the set
+of valid subnodes that can operate on these resources.
+
+== Switch-mode Power Supply regulator
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be one of:
+ "qcom,rpm-pm8058-smps"
+ "qcom,rpm-pm8901-ftsmps"
+ "qcom,rpm-pm8921-smps"
+ "qcom,rpm-pm8921-ftsmps"
+
+- reg:
+ Usage: required
+ Value type: <u32>
+ Definition: resource as defined in <dt-bindings/soc/qcom,rpm.h>
+
+- bias-pull-down:
+ Usage: optional
+ Value type: <empty>
+ Definition: enable pull down of the regulator when inactive
+
+- qcom,switch-mode-frequency:
+ Usage: required
+ Value type: <u32>
+ Definition: Frequency (Hz) of the switch-mode power supply;
+ must be one of:
+ 19200000, 9600000, 6400000, 4800000, 3840000, 3200000,
+ 2740000, 2400000, 2130000, 1920000, 1750000, 1600000,
+ 1480000, 1370000, 1280000, 1200000
+
+- qcom,force-mode-none:
+ Usage: optional (default if no other qcom,force-mode is specified)
+ Value type: <empty>
+ Defintion: indicates that the regulator should not be forced to any
+ particular mode
+
+- qcom,force-mode-lpm:
+ Usage: optional
+ Value type: <empty>
+ Definition: indicates that the regulator should be forced to operate in
+ low-power-mode
+
+- qcom,force-mode-auto:
+ Usage: optional (only available for 8960/8064)
+ Value type: <empty>
+ Definition: indicates that the regulator should be automatically pick
+ operating mode
+
+- qcom,force-mode-hpm:
+ Usage: optional (only available for 8960/8064)
+ Value type: <empty>
+ Definition: indicates that the regulator should be forced to operate in
+ high-power-mode
+
+- qcom,force-mode-bypass: (only for 8960/8064)
+ Usage: optional (only available for 8960/8064)
+ Value type: <empty>
+ Definition: indicates that the regulator should be forced to operate in
+ bypass mode
+
+- qcom,power-mode-hysteretic:
+ Usage: optional
+ Value type: <empty>
+ Definition: indicates that the power supply should operate in hysteretic
+ mode (defaults to qcom,power-mode-pwm if not specified)
+
+- qcom,power-mode-pwm:
+ Usage: optional
+ Value type: <empty>
+ Definition: indicates that the power supply should operate in pwm mode
+
+Standard regulator bindings are used inside switch mode power supply subnodes.
+Check Documentation/devicetree/bindings/regulator/regulator.txt for more
+details.
+
+== Low-dropout regulator
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be one of:
+ "qcom,rpm-pm8058-pldo"
+ "qcom,rpm-pm8058-nldo"
+ "qcom,rpm-pm8901-pldo"
+ "qcom,rpm-pm8901-nldo"
+ "qcom,rpm-pm8921-pldo"
+ "qcom,rpm-pm8921-nldo"
+ "qcom,rpm-pm8921-nldo1200"
+
+- reg:
+ Usage: required
+ Value type: <u32>
+ Definition: resource as defined in <dt-bindings/soc/qcom,rpm.h>
+
+- bias-pull-down:
+ Usage: optional
+ Value type: <empty>
+ Definition: enable pull down of the regulator when inactive
+
+- qcom,force-mode-none:
+ Usage: optional (default if no other qcom,force-mode is specified)
+ Value type: <empty>
+ Defintion: indicates that the regulator should not be forced to any
+ particular mode
+
+- qcom,force-mode-lpm:
+ Usage: optional
+ Value type: <empty>
+ Definition: indicates that the regulator should be forced to operate in
+ low-power-mode
+
+- qcom,force-mode-auto:
+ Usage: optional (only available for 8960/8064)
+ Value type: <empty>
+ Definition: indicates that the regulator should be automatically pick
+ operating mode
+
+- qcom,force-mode-hpm:
+ Usage: optional (only available for 8960/8064)
+ Value type: <empty>
+ Definition: indicates that the regulator should be forced to operate in
+ high-power-mode
+
+- qcom,force-mode-bypass: (only for 8960/8064)
+ Usage: optional (only available for 8960/8064)
+ Value type: <empty>
+ Definition: indicates that the regulator should be forced to operate in
+ bypass mode
+
+Standard regulator bindings are used inside switch low-dropout regulator
+subnodes. Check Documentation/devicetree/bindings/regulator/regulator.txt for
+more details.
+
+== Negative Charge Pump
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be one of:
+ "qcom,rpm-pm8058-ncp"
+ "qcom,rpm-pm8921-ncp"
+
+- reg:
+ Usage: required
+ Value type: <u32>
+ Definition: resource as defined in <dt-bindings/soc/qcom,rpm.h>
+
+- qcom,switch-mode-frequency:
+ Usage: required
+ Value type: <u32>
+ Definition: Frequency (Hz) of the swith mode power supply;
+ must be one of:
+ 19200000, 9600000, 6400000, 4800000, 3840000, 3200000,
+ 2740000, 2400000, 2130000, 1920000, 1750000, 1600000,
+ 1480000, 1370000, 1280000, 1200000
+
+Standard regulator bindings are used inside negative charge pump regulator
+subnodes. Check Documentation/devicetree/bindings/regulator/regulator.txt for
+more details.
+
+== Switch
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be one of:
+ "qcom,rpm-pm8058-switch"
+ "qcom,rpm-pm8901-switch"
+ "qcom,rpm-pm8921-switch"
+
+- reg:
+ Usage: required
+ Value type: <u32>
+ Definition: resource as defined in <dt-bindings/soc/qcom/qcom,rpm.h>
+
+
+= EXAMPLE
+
+ #include <dt-bindings/soc/qcom,rpm.h>
+
+ rpm@108000 {
+ compatible = "qcom,rpm-msm8960";
+ reg = <0x108000 0x1000 0x2011008 0x4>;
+
+ interrupts = <0 19 0>, <0 21 0>, <0 22 0>;
+ interrupt-names = "ack", "err", "wakeup";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pm8921_s1: pm8921-s1 {
+ compatible = "qcom,rpm-pm8921-smps";
+ reg = <QCOM_RPM_PM8921_S1>;
+
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ regulator-always-on;
+
+ bias-pull-down;
+
+ qcom,switch-mode-frequency = <3200000>;
+ };
+ };
+
diff --git a/include/dt-bindings/soc/qcom,rpm.h b/include/dt-bindings/soc/qcom,rpm.h
new file mode 100644
index 0000000..d9d840b
--- /dev/null
+++ b/include/dt-bindings/soc/qcom,rpm.h
@@ -0,0 +1,142 @@
+/*
+ * This header provides constants for the Qualcomm RPM bindings.
+ */
+
+#ifndef _DT_BINDINGS_SOC_QCOM_RPM_H
+#define _DT_BINDINGS_SOC_QCOM_RPM_H
+
+#define QCOM_RPM_APPS_FABRIC_ARB 1
+#define QCOM_RPM_APPS_FABRIC_CLK 2
+#define QCOM_RPM_APPS_FABRIC_HALT 3
+#define QCOM_RPM_APPS_FABRIC_IOCTL 4
+#define QCOM_RPM_APPS_FABRIC_MODE 5
+#define QCOM_RPM_APPS_L2_CACHE_CTL 6
+#define QCOM_RPM_CFPB_CLK 7
+#define QCOM_RPM_CXO_BUFFERS 8
+#define QCOM_RPM_CXO_CLK 9
+#define QCOM_RPM_DAYTONA_FABRIC_CLK 10
+#define QCOM_RPM_DDR_DMM 11
+#define QCOM_RPM_EBI1_CLK 12
+#define QCOM_RPM_HDMI_SWITCH 13
+#define QCOM_RPM_MMFPB_CLK 14
+#define QCOM_RPM_MM_FABRIC_ARB 15
+#define QCOM_RPM_MM_FABRIC_CLK 16
+#define QCOM_RPM_MM_FABRIC_HALT 17
+#define QCOM_RPM_MM_FABRIC_IOCTL 18
+#define QCOM_RPM_MM_FABRIC_MODE 19
+#define QCOM_RPM_PLL_4 20
+#define QCOM_RPM_PM8058_LDO0 21
+#define QCOM_RPM_PM8058_LDO1 22
+#define QCOM_RPM_PM8058_LDO2 23
+#define QCOM_RPM_PM8058_LDO3 24
+#define QCOM_RPM_PM8058_LDO4 25
+#define QCOM_RPM_PM8058_LDO5 26
+#define QCOM_RPM_PM8058_LDO6 27
+#define QCOM_RPM_PM8058_LDO7 28
+#define QCOM_RPM_PM8058_LDO8 29
+#define QCOM_RPM_PM8058_LDO9 30
+#define QCOM_RPM_PM8058_LDO10 31
+#define QCOM_RPM_PM8058_LDO11 32
+#define QCOM_RPM_PM8058_LDO12 33
+#define QCOM_RPM_PM8058_LDO13 34
+#define QCOM_RPM_PM8058_LDO14 35
+#define QCOM_RPM_PM8058_LDO15 36
+#define QCOM_RPM_PM8058_LDO16 37
+#define QCOM_RPM_PM8058_LDO17 38
+#define QCOM_RPM_PM8058_LDO18 39
+#define QCOM_RPM_PM8058_LDO19 40
+#define QCOM_RPM_PM8058_LDO20 41
+#define QCOM_RPM_PM8058_LDO21 42
+#define QCOM_RPM_PM8058_LDO22 43
+#define QCOM_RPM_PM8058_LDO23 44
+#define QCOM_RPM_PM8058_LDO24 45
+#define QCOM_RPM_PM8058_LDO25 46
+#define QCOM_RPM_PM8058_LVS0 47
+#define QCOM_RPM_PM8058_LVS1 48
+#define QCOM_RPM_PM8058_NCP 49
+#define QCOM_RPM_PM8058_SMPS0 50
+#define QCOM_RPM_PM8058_SMPS1 51
+#define QCOM_RPM_PM8058_SMPS2 52
+#define QCOM_RPM_PM8058_SMPS3 53
+#define QCOM_RPM_PM8058_SMPS4 54
+#define QCOM_RPM_PM8821_L1 55
+#define QCOM_RPM_PM8821_S1 56
+#define QCOM_RPM_PM8821_S2 57
+#define QCOM_RPM_PM8901_LDO0 58
+#define QCOM_RPM_PM8901_LDO1 59
+#define QCOM_RPM_PM8901_LDO2 60
+#define QCOM_RPM_PM8901_LDO3 61
+#define QCOM_RPM_PM8901_LDO4 62
+#define QCOM_RPM_PM8901_LDO5 63
+#define QCOM_RPM_PM8901_LDO6 64
+#define QCOM_RPM_PM8901_LVS0 65
+#define QCOM_RPM_PM8901_LVS1 66
+#define QCOM_RPM_PM8901_LVS2 67
+#define QCOM_RPM_PM8901_LVS3 68
+#define QCOM_RPM_PM8901_MVS 69
+#define QCOM_RPM_PM8901_SMPS0 70
+#define QCOM_RPM_PM8901_SMPS1 71
+#define QCOM_RPM_PM8901_SMPS2 72
+#define QCOM_RPM_PM8901_SMPS3 73
+#define QCOM_RPM_PM8901_SMPS4 74
+#define QCOM_RPM_PM8921_CLK1 75
+#define QCOM_RPM_PM8921_CLK2 76
+#define QCOM_RPM_PM8921_L1 77
+#define QCOM_RPM_PM8921_L2 78
+#define QCOM_RPM_PM8921_L3 79
+#define QCOM_RPM_PM8921_L4 80
+#define QCOM_RPM_PM8921_L5 81
+#define QCOM_RPM_PM8921_L6 82
+#define QCOM_RPM_PM8921_L7 83
+#define QCOM_RPM_PM8921_L8 84
+#define QCOM_RPM_PM8921_L9 85
+#define QCOM_RPM_PM8921_L10 86
+#define QCOM_RPM_PM8921_L11 87
+#define QCOM_RPM_PM8921_L12 88
+#define QCOM_RPM_PM8921_L13 89
+#define QCOM_RPM_PM8921_L14 90
+#define QCOM_RPM_PM8921_L15 91
+#define QCOM_RPM_PM8921_L16 92
+#define QCOM_RPM_PM8921_L17 93
+#define QCOM_RPM_PM8921_L18 94
+#define QCOM_RPM_PM8921_L19 95
+#define QCOM_RPM_PM8921_L20 96
+#define QCOM_RPM_PM8921_L21 97
+#define QCOM_RPM_PM8921_L22 98
+#define QCOM_RPM_PM8921_L23 99
+#define QCOM_RPM_PM8921_L24 100
+#define QCOM_RPM_PM8921_L25 101
+#define QCOM_RPM_PM8921_L26 102
+#define QCOM_RPM_PM8921_L27 103
+#define QCOM_RPM_PM8921_L28 104
+#define QCOM_RPM_PM8921_L29 105
+#define QCOM_RPM_PM8921_LVS1 106
+#define QCOM_RPM_PM8921_LVS2 107
+#define QCOM_RPM_PM8921_LVS3 108
+#define QCOM_RPM_PM8921_LVS4 109
+#define QCOM_RPM_PM8921_LVS5 110
+#define QCOM_RPM_PM8921_LVS6 111
+#define QCOM_RPM_PM8921_LVS7 112
+#define QCOM_RPM_PM8921_MVS 113
+#define QCOM_RPM_PM8921_NCP 114
+#define QCOM_RPM_PM8921_S1 115
+#define QCOM_RPM_PM8921_S2 116
+#define QCOM_RPM_PM8921_S3 117
+#define QCOM_RPM_PM8921_S4 118
+#define QCOM_RPM_PM8921_S5 119
+#define QCOM_RPM_PM8921_S6 120
+#define QCOM_RPM_PM8921_S7 121
+#define QCOM_RPM_PM8921_S8 122
+#define QCOM_RPM_PXO_CLK 123
+#define QCOM_RPM_QDSS_CLK 124
+#define QCOM_RPM_SFPB_CLK 125
+#define QCOM_RPM_SMI_CLK 126
+#define QCOM_RPM_SYS_FABRIC_ARB 127
+#define QCOM_RPM_SYS_FABRIC_CLK 128
+#define QCOM_RPM_SYS_FABRIC_HALT 129
+#define QCOM_RPM_SYS_FABRIC_IOCTL 130
+#define QCOM_RPM_SYS_FABRIC_MODE 131
+#define QCOM_RPM_USB_OTG_SWITCH 132
+#define QCOM_RPM_VDDMIN_GPIO 133
+
+#endif
--
1.8.2.2

2014-06-16 18:46:32

by Bjorn Andersson

[permalink] [raw]
Subject: [PATCH v3 3/3] regulator: qcom-rpm: Regulator driver for the Qualcomm RPM

Driver for regulators exposed by the Resource Power Manager (RPM) found
in Qualcomm 8660, 8960 and 8064 based devices.

Signed-off-by: Bjorn Andersson <[email protected]>
---
drivers/regulator/Kconfig | 12 +
drivers/regulator/Makefile | 1 +
drivers/regulator/qcom_rpm-regulator.c | 787 +++++++++++++++++++++++++++++++++
3 files changed, 800 insertions(+)
create mode 100644 drivers/regulator/qcom_rpm-regulator.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 903eb37..ea5a405 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -423,6 +423,18 @@ config REGULATOR_PFUZE100
Say y here to support the regulators found on the Freescale
PFUZE100/PFUZE200 PMIC.

+config REGULATOR_QCOM_RPM
+ tristate "Qualcomm RPM regulator driver"
+ depends on QCOM_RPM
+ help
+ If you say yes to this option, support will be included for the
+ regulators exposed by the Resource Power Manager found in Qualcomm
+ 8660, 8960 and 8064 based devices.
+
+ Say M here if you want to include support for the regulators on the
+ Qualcomm RPM as a module. The module will be named
+ "qcom_rpm-regulator".
+
config REGULATOR_RC5T583
tristate "RICOH RC5T583 Power regulators"
depends on MFD_RC5T583
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 12ef277..53b5ce8 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_REGULATOR_MAX77693) += max77693.o
obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o
+obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o
diff --git a/drivers/regulator/qcom_rpm-regulator.c b/drivers/regulator/qcom_rpm-regulator.c
new file mode 100644
index 0000000..f28ccdb
--- /dev/null
+++ b/drivers/regulator/qcom_rpm-regulator.c
@@ -0,0 +1,787 @@
+/*
+ * Copyright (c) 2014, Sony Mobile Communications AB.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/soc/qcom_rpm.h>
+
+#define MAX_REQUEST_LEN 2
+
+struct request_member {
+ int word;
+ unsigned int mask;
+ int shift;
+};
+
+struct rpm_reg_parts {
+ struct request_member mV; /* used if voltage is in mV */
+ struct request_member uV; /* used if voltage is in uV */
+ struct request_member ip; /* peak current in mA */
+ struct request_member pd; /* pull down enable */
+ struct request_member ia; /* average current in mA */
+ struct request_member fm; /* force mode */
+ struct request_member pm; /* power mode */
+ struct request_member pc; /* pin control */
+ struct request_member pf; /* pin function */
+ struct request_member enable_state; /* NCP and switch */
+ struct request_member comp_mode; /* NCP */
+ struct request_member freq; /* frequency: NCP and SMPS */
+ struct request_member freq_clk_src; /* clock source: SMPS */
+ struct request_member hpm; /* switch: control OCP and SS */
+ int request_len;
+};
+
+#define FORCE_MODE_IS_2_BITS(reg) \
+ ((vreg->parts->fm.mask >> vreg->parts->fm.shift) == 3)
+#define FORCE_MODE_IS_3_BITS(reg) \
+ ((vreg->parts->fm.mask >> vreg->parts->fm.shift) == 7)
+
+struct qcom_rpm_reg {
+ struct qcom_rpm *rpm;
+
+ struct mutex lock;
+ struct device *dev;
+ struct regulator_desc desc;
+ const struct rpm_reg_parts *parts;
+
+ int resource;
+ u32 val[MAX_REQUEST_LEN];
+
+ int uV;
+ int is_enabled;
+};
+
+static const struct rpm_reg_parts rpm8660_ldo_parts = {
+ .request_len = 2,
+ .mV = { 0, 0x00000FFF, 0 },
+ .ip = { 0, 0x00FFF000, 12 },
+ .fm = { 0, 0x03000000, 24 },
+ .pc = { 0, 0x3C000000, 26 },
+ .pf = { 0, 0xC0000000, 30 },
+ .pd = { 1, 0x00000001, 0 },
+ .ia = { 1, 0x00001FFE, 1 },
+};
+
+static const struct rpm_reg_parts rpm8660_smps_parts = {
+ .request_len = 2,
+ .mV = { 0, 0x00000FFF, 0 },
+ .ip = { 0, 0x00FFF000, 12 },
+ .fm = { 0, 0x03000000, 24 },
+ .pc = { 0, 0x3C000000, 26 },
+ .pf = { 0, 0xC0000000, 30 },
+ .pd = { 1, 0x00000001, 0 },
+ .ia = { 1, 0x00001FFE, 1 },
+ .freq = { 1, 0x001FE000, 13 },
+ .freq_clk_src = { 1, 0x00600000, 21 },
+};
+
+static const struct rpm_reg_parts rpm8660_switch_parts = {
+ .request_len = 1,
+ .enable_state = { 0, 0x00000001, 0 },
+ .pd = { 0, 0x00000002, 1 },
+ .pc = { 0, 0x0000003C, 2 },
+ .pf = { 0, 0x000000C0, 6 },
+ .hpm = { 0, 0x00000300, 8 },
+};
+
+static const struct rpm_reg_parts rpm8660_ncp_parts = {
+ .request_len = 1,
+ .mV = { 0, 0x00000FFF, 0 },
+ .enable_state = { 0, 0x00001000, 12 },
+ .comp_mode = { 0, 0x00002000, 13 },
+ .freq = { 0, 0x003FC000, 14 },
+};
+
+static const struct rpm_reg_parts rpm8960_ldo_parts = {
+ .request_len = 2,
+ .uV = { 0, 0x007FFFFF, 0 },
+ .pd = { 0, 0x00800000, 23 },
+ .pc = { 0, 0x0F000000, 24 },
+ .pf = { 0, 0xF0000000, 28 },
+ .ip = { 1, 0x000003FF, 0 },
+ .ia = { 1, 0x000FFC00, 10 },
+ .fm = { 1, 0x00700000, 20 },
+};
+
+static const struct rpm_reg_parts rpm8960_smps_parts = {
+ .request_len = 2,
+ .uV = { 0, 0x007FFFFF, 0 },
+ .pd = { 0, 0x00800000, 23 },
+ .pc = { 0, 0x0F000000, 24 },
+ .pf = { 0, 0xF0000000, 28 },
+ .ip = { 1, 0x000003FF, 0 },
+ .ia = { 1, 0x000FFC00, 10 },
+ .fm = { 1, 0x00700000, 20 },
+ .pm = { 1, 0x00800000, 23 },
+ .freq = { 1, 0x1F000000, 24 },
+ .freq_clk_src = { 1, 0x60000000, 29 },
+};
+
+static const struct rpm_reg_parts rpm8960_switch_parts = {
+ .request_len = 1,
+ .enable_state = { 0, 0x00000001, 0 },
+ .pd = { 0, 0x00000002, 1 },
+ .pc = { 0, 0x0000003C, 2 },
+ .pf = { 0, 0x000003C0, 6 },
+ .hpm = { 0, 0x00000C00, 10 },
+};
+
+static const struct rpm_reg_parts rpm8960_ncp_parts = {
+ .request_len = 1,
+ .uV = { 0, 0x007FFFFF, 0 },
+ .enable_state = { 0, 0x00800000, 23 },
+ .comp_mode = { 0, 0x01000000, 24 },
+ .freq = { 0, 0x3E000000, 25 },
+};
+
+/*
+ * Physically available PMIC regulator voltage ranges
+ */
+static const struct regulator_linear_range pldo_ranges[] = {
+ REGULATOR_LINEAR_RANGE( 750000, 0, 59, 12500),
+ REGULATOR_LINEAR_RANGE(1500000, 60, 123, 25000),
+ REGULATOR_LINEAR_RANGE(3100000, 124, 160, 50000),
+};
+
+static const struct regulator_linear_range nldo_ranges[] = {
+ REGULATOR_LINEAR_RANGE( 750000, 0, 63, 12500),
+};
+
+static const struct regulator_linear_range nldo1200_ranges[] = {
+ REGULATOR_LINEAR_RANGE( 375000, 0, 59, 6250),
+ REGULATOR_LINEAR_RANGE( 750000, 60, 123, 12500),
+};
+
+static const struct regulator_linear_range smps_ranges[] = {
+ REGULATOR_LINEAR_RANGE( 375000, 0, 29, 12500),
+ REGULATOR_LINEAR_RANGE( 750000, 30, 89, 12500),
+ REGULATOR_LINEAR_RANGE(1500000, 90, 153, 25000),
+};
+
+static const struct regulator_linear_range ftsmps_ranges[] = {
+ REGULATOR_LINEAR_RANGE( 350000, 0, 6, 50000),
+ REGULATOR_LINEAR_RANGE( 700000, 7, 63, 12500),
+ REGULATOR_LINEAR_RANGE(1500000, 64, 100, 50000),
+};
+
+static const struct regulator_linear_range ncp_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1500000, 0, 31, 50000),
+};
+
+static int rpm_reg_write(struct qcom_rpm_reg *vreg,
+ const struct request_member *req,
+ const int value)
+{
+ if (WARN_ON((value << req->shift) & ~req->mask))
+ return -EINVAL;
+
+ vreg->val[req->word] &= ~req->mask;
+ vreg->val[req->word] |= value << req->shift;
+
+ return qcom_rpm_write(vreg->rpm,
+ vreg->resource,
+ vreg->val,
+ vreg->parts->request_len);
+}
+
+static int rpm_reg_set_mV_sel(struct regulator_dev *rdev,
+ unsigned selector)
+{
+ struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
+ const struct rpm_reg_parts *parts = vreg->parts;
+ const struct request_member *req = &parts->mV;
+ int ret = 0;
+ int uV;
+
+ if (req->mask == 0)
+ return -EINVAL;
+
+ uV = regulator_list_voltage_linear_range(rdev, selector);
+ if (uV < 0)
+ return uV;
+
+ mutex_lock(&vreg->lock);
+ vreg->uV = uV;
+ if (vreg->is_enabled)
+ ret = rpm_reg_write(vreg, req, vreg->uV / 1000);
+ mutex_unlock(&vreg->lock);
+
+ return ret;
+}
+
+static int rpm_reg_set_uV_sel(struct regulator_dev *rdev,
+ unsigned selector)
+{
+ struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
+ const struct rpm_reg_parts *parts = vreg->parts;
+ const struct request_member *req = &parts->uV;
+ int ret = 0;
+ int uV;
+
+ if (req->mask == 0)
+ return -EINVAL;
+
+ uV = regulator_list_voltage_linear_range(rdev, selector);
+ if (uV < 0)
+ return uV;
+
+ mutex_lock(&vreg->lock);
+ vreg->uV = uV;
+ if (vreg->is_enabled)
+ ret = rpm_reg_write(vreg, req, vreg->uV);
+ mutex_unlock(&vreg->lock);
+
+ return ret;
+}
+
+static int rpm_reg_get_voltage(struct regulator_dev *rdev)
+{
+ struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
+
+ return vreg->uV;
+}
+
+static int rpm_reg_mV_enable(struct regulator_dev *rdev)
+{
+ struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
+ const struct rpm_reg_parts *parts = vreg->parts;
+ const struct request_member *req = &parts->mV;
+ int ret;
+
+ if (req->mask == 0)
+ return -EINVAL;
+
+ mutex_lock(&vreg->lock);
+ ret = rpm_reg_write(vreg, req, vreg->uV / 1000);
+ if (!ret)
+ vreg->is_enabled = 1;
+ mutex_unlock(&vreg->lock);
+
+ return ret;
+}
+
+static int rpm_reg_uV_enable(struct regulator_dev *rdev)
+{
+ struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
+ const struct rpm_reg_parts *parts = vreg->parts;
+ const struct request_member *req = &parts->uV;
+ int ret;
+
+ if (req->mask == 0)
+ return -EINVAL;
+
+ mutex_lock(&vreg->lock);
+ ret = rpm_reg_write(vreg, req, vreg->uV);
+ if (!ret)
+ vreg->is_enabled = 1;
+ mutex_unlock(&vreg->lock);
+
+ return ret;
+}
+
+static int rpm_reg_switch_enable(struct regulator_dev *rdev)
+{
+ struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
+ const struct rpm_reg_parts *parts = vreg->parts;
+ const struct request_member *req = &parts->enable_state;
+ int ret;
+
+ if (req->mask == 0)
+ return -EINVAL;
+
+ mutex_lock(&vreg->lock);
+ ret = rpm_reg_write(vreg, req, 1);
+ if (!ret)
+ vreg->is_enabled = 1;
+ mutex_unlock(&vreg->lock);
+
+ return ret;
+}
+
+static int rpm_reg_mV_disable(struct regulator_dev *rdev)
+{
+ struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
+ const struct rpm_reg_parts *parts = vreg->parts;
+ const struct request_member *req = &parts->mV;
+ int ret;
+
+ if (req->mask == 0)
+ return -EINVAL;
+
+ mutex_lock(&vreg->lock);
+ ret = rpm_reg_write(vreg, req, 0);
+ if (!ret)
+ vreg->is_enabled = 0;
+ mutex_unlock(&vreg->lock);
+
+ return ret;
+}
+
+static int rpm_reg_uV_disable(struct regulator_dev *rdev)
+{
+ struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
+ const struct rpm_reg_parts *parts = vreg->parts;
+ const struct request_member *req = &parts->uV;
+ int ret;
+
+ if (req->mask == 0)
+ return -EINVAL;
+
+ mutex_lock(&vreg->lock);
+ ret = rpm_reg_write(vreg, req, 0);
+ if (!ret)
+ vreg->is_enabled = 0;
+ mutex_unlock(&vreg->lock);
+
+ return ret;
+}
+
+static int rpm_reg_switch_disable(struct regulator_dev *rdev)
+{
+ struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
+ const struct rpm_reg_parts *parts = vreg->parts;
+ const struct request_member *req = &parts->enable_state;
+ int ret;
+
+ if (req->mask == 0)
+ return -EINVAL;
+
+ mutex_lock(&vreg->lock);
+ ret = rpm_reg_write(vreg, req, 0);
+ if (!ret)
+ vreg->is_enabled = 0;
+ mutex_unlock(&vreg->lock);
+
+ return ret;
+}
+
+static int rpm_reg_is_enabled(struct regulator_dev *rdev)
+{
+ struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
+
+ return vreg->is_enabled;
+}
+
+static struct regulator_ops uV_ops = {
+ .list_voltage = regulator_list_voltage_linear_range,
+
+ .set_voltage_sel = rpm_reg_set_uV_sel,
+ .get_voltage = rpm_reg_get_voltage,
+
+ .enable = rpm_reg_uV_enable,
+ .disable = rpm_reg_uV_disable,
+ .is_enabled = rpm_reg_is_enabled,
+};
+
+static struct regulator_ops mV_ops = {
+ .list_voltage = regulator_list_voltage_linear_range,
+
+ .set_voltage_sel = rpm_reg_set_mV_sel,
+ .get_voltage = rpm_reg_get_voltage,
+
+ .enable = rpm_reg_mV_enable,
+ .disable = rpm_reg_mV_disable,
+ .is_enabled = rpm_reg_is_enabled,
+};
+
+static struct regulator_ops switch_ops = {
+ .enable = rpm_reg_switch_enable,
+ .disable = rpm_reg_switch_disable,
+ .is_enabled = rpm_reg_is_enabled,
+};
+
+/*
+ * PM8058 regulators
+ */
+static const struct qcom_rpm_reg pm8058_pldo = {
+ .desc.linear_ranges = pldo_ranges,
+ .desc.n_linear_ranges = ARRAY_SIZE(pldo_ranges),
+ .desc.n_voltages = 161,
+ .desc.ops = &mV_ops,
+ .parts = &rpm8660_ldo_parts,
+};
+
+static const struct qcom_rpm_reg pm8058_nldo = {
+ .desc.linear_ranges = nldo_ranges,
+ .desc.n_linear_ranges = ARRAY_SIZE(nldo_ranges),
+ .desc.n_voltages = 64,
+ .desc.ops = &mV_ops,
+ .parts = &rpm8660_ldo_parts,
+};
+
+static const struct qcom_rpm_reg pm8058_smps = {
+ .desc.linear_ranges = smps_ranges,
+ .desc.n_linear_ranges = ARRAY_SIZE(smps_ranges),
+ .desc.n_voltages = 154,
+ .desc.ops = &mV_ops,
+ .parts = &rpm8660_smps_parts,
+};
+
+static const struct qcom_rpm_reg pm8058_ncp = {
+ .desc.linear_ranges = ncp_ranges,
+ .desc.n_linear_ranges = ARRAY_SIZE(ncp_ranges),
+ .desc.n_voltages = 32,
+ .desc.ops = &mV_ops,
+ .parts = &rpm8660_ncp_parts,
+};
+
+static const struct qcom_rpm_reg pm8058_switch = {
+ .desc.ops = &switch_ops,
+ .parts = &rpm8660_switch_parts,
+};
+
+/*
+ * PM8901 regulators
+ */
+static const struct qcom_rpm_reg pm8901_pldo = {
+ .desc.linear_ranges = pldo_ranges,
+ .desc.n_linear_ranges = ARRAY_SIZE(pldo_ranges),
+ .desc.n_voltages = 161,
+ .desc.ops = &mV_ops,
+ .parts = &rpm8660_ldo_parts,
+};
+
+static const struct qcom_rpm_reg pm8901_nldo = {
+ .desc.linear_ranges = nldo_ranges,
+ .desc.n_linear_ranges = ARRAY_SIZE(nldo_ranges),
+ .desc.n_voltages = 64,
+ .desc.ops = &mV_ops,
+ .parts = &rpm8660_ldo_parts,
+};
+
+static const struct qcom_rpm_reg pm8901_ftsmps = {
+ .desc.linear_ranges = ftsmps_ranges,
+ .desc.n_linear_ranges = ARRAY_SIZE(ftsmps_ranges),
+ .desc.n_voltages = 101,
+ .desc.ops = &mV_ops,
+ .parts = &rpm8660_smps_parts,
+};
+
+static const struct qcom_rpm_reg pm8901_switch = {
+ .desc.ops = &switch_ops,
+ .parts = &rpm8660_switch_parts,
+};
+
+/*
+ * PM8921 regulators
+ */
+static const struct qcom_rpm_reg pm8921_pldo = {
+ .desc.linear_ranges = pldo_ranges,
+ .desc.n_linear_ranges = ARRAY_SIZE(pldo_ranges),
+ .desc.n_voltages = 161,
+ .desc.ops = &uV_ops,
+ .parts = &rpm8960_ldo_parts,
+};
+
+static const struct qcom_rpm_reg pm8921_nldo = {
+ .desc.linear_ranges = nldo_ranges,
+ .desc.n_linear_ranges = ARRAY_SIZE(nldo_ranges),
+ .desc.n_voltages = 64,
+ .desc.ops = &uV_ops,
+ .parts = &rpm8960_ldo_parts,
+};
+
+static const struct qcom_rpm_reg pm8921_nldo1200 = {
+ .desc.linear_ranges = nldo1200_ranges,
+ .desc.n_linear_ranges = ARRAY_SIZE(nldo1200_ranges),
+ .desc.n_voltages = 124,
+ .desc.ops = &uV_ops,
+ .parts = &rpm8960_ldo_parts,
+};
+
+static const struct qcom_rpm_reg pm8921_smps = {
+ .desc.linear_ranges = smps_ranges,
+ .desc.n_linear_ranges = ARRAY_SIZE(smps_ranges),
+ .desc.n_voltages = 154,
+ .desc.ops = &uV_ops,
+ .parts = &rpm8960_smps_parts,
+};
+
+static const struct qcom_rpm_reg pm8921_ftsmps = {
+ .desc.linear_ranges = ftsmps_ranges,
+ .desc.n_linear_ranges = ARRAY_SIZE(ftsmps_ranges),
+ .desc.n_voltages = 101,
+ .desc.ops = &uV_ops,
+ .parts = &rpm8960_smps_parts,
+};
+
+static const struct qcom_rpm_reg pm8921_ncp = {
+ .desc.linear_ranges = ncp_ranges,
+ .desc.n_linear_ranges = ARRAY_SIZE(ncp_ranges),
+ .desc.n_voltages = 32,
+ .desc.ops = &uV_ops,
+ .parts = &rpm8960_ncp_parts,
+};
+
+static const struct qcom_rpm_reg pm8921_switch = {
+ .desc.ops = &switch_ops,
+ .parts = &rpm8960_switch_parts,
+};
+
+static const struct of_device_id rpm_of_match[] = {
+ { .compatible = "qcom,rpm-pm8058-pldo", .data = &pm8058_pldo },
+ { .compatible = "qcom,rpm-pm8058-nldo", .data = &pm8058_nldo },
+ { .compatible = "qcom,rpm-pm8058-smps", .data = &pm8058_smps },
+ { .compatible = "qcom,rpm-pm8058-ncp", .data = &pm8058_ncp },
+ { .compatible = "qcom,rpm-pm8058-switch", .data = &pm8058_switch },
+
+ { .compatible = "qcom,rpm-pm8901-pldo", .data = &pm8901_pldo },
+ { .compatible = "qcom,rpm-pm8901-nldo", .data = &pm8901_nldo },
+ { .compatible = "qcom,rpm-pm8901-ftsmps", .data = &pm8901_ftsmps },
+ { .compatible = "qcom,rpm-pm8901-switch", .data = &pm8901_switch },
+
+ { .compatible = "qcom,rpm-pm8921-pldo", .data = &pm8921_pldo },
+ { .compatible = "qcom,rpm-pm8921-nldo", .data = &pm8921_nldo },
+ { .compatible = "qcom,rpm-pm8921-nldo1200", .data = &pm8921_nldo1200 },
+ { .compatible = "qcom,rpm-pm8921-smps", .data = &pm8921_smps },
+ { .compatible = "qcom,rpm-pm8921-ftsmps", .data = &pm8921_ftsmps },
+ { .compatible = "qcom,rpm-pm8921-ncp", .data = &pm8921_ncp },
+ { .compatible = "qcom,rpm-pm8921-switch", .data = &pm8921_switch },
+ { }
+};
+MODULE_DEVICE_TABLE(of, rpm_of_match);
+
+static int rpm_reg_set(struct qcom_rpm_reg *vreg,
+ const struct request_member *req,
+ const int value)
+{
+ if (req->mask == 0 || (value << req->shift) & ~req->mask)
+ return -EINVAL;
+
+ vreg->val[req->word] &= ~req->mask;
+ vreg->val[req->word] |= value << req->shift;
+
+ return 0;
+}
+
+static int rpm_reg_of_parse_freq(struct device *dev, struct qcom_rpm_reg *vreg)
+{
+ static const int freq_table[] = {
+ 19200000, 9600000, 6400000, 4800000, 3840000, 3200000, 2740000,
+ 2400000, 2130000, 1920000, 1750000, 1600000, 1480000, 1370000,
+ 1280000, 1200000,
+
+ };
+ const char *key;
+ u32 freq;
+ int ret;
+ int i;
+
+ key = "qcom,switch-mode-frequency";
+ ret = of_property_read_u32(dev->of_node, key, &freq);
+ if (ret) {
+ dev_err(dev, "regulator requires %s property\n", key);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(freq_table); i++) {
+ if (freq == freq_table[i]) {
+ rpm_reg_set(vreg, &vreg->parts->freq, i + 1);
+ return 0;
+ }
+ }
+
+ dev_err(dev, "invalid frequency %d\n", freq);
+ return -EINVAL;
+}
+
+static int rpm_reg_of_select_one(struct device *dev,
+ const char * const keys[],
+ const int count, int def)
+{
+ int found = -1;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (!of_property_read_bool(dev->of_node, keys[i]))
+ continue;
+
+ if (found >= 0) {
+ dev_err(dev, "%s and %s are mutually exclusive\n",
+ keys[i], keys[found]);
+ return -EINVAL;
+ }
+ found = i;
+ }
+
+ if (found == -1)
+ return def;
+
+ return found;
+}
+
+static int rpm_reg_probe(struct platform_device *pdev)
+{
+ struct regulator_init_data *initdata;
+ const struct qcom_rpm_reg *template;
+ const struct of_device_id *match;
+ struct regulator_config config = { 0 };
+ struct regulator_dev *rdev;
+ struct qcom_rpm_reg *vreg;
+ const char *key;
+ u32 val;
+ int ret;
+
+ match = of_match_device(rpm_of_match, &pdev->dev);
+ template = match->data;
+
+ initdata = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node);
+ if (!initdata)
+ return -EINVAL;
+
+ vreg = devm_kmalloc(&pdev->dev, sizeof(*vreg), GFP_KERNEL);
+ if (!vreg) {
+ dev_err(&pdev->dev, "failed to allocate vreg\n");
+ return -ENOMEM;
+ }
+ memcpy(vreg, template, sizeof(*vreg));
+ mutex_init(&vreg->lock);
+ vreg->dev = &pdev->dev;
+ vreg->desc.id = -1;
+ vreg->desc.owner = THIS_MODULE;
+ vreg->desc.type = REGULATOR_VOLTAGE;
+ vreg->desc.name = pdev->dev.of_node->name;
+
+ vreg->rpm = dev_get_qcom_rpm(pdev->dev.parent);
+ if (!vreg->rpm) {
+ dev_err(&pdev->dev, "unable to retrieve handle to rpm\n");
+ return -ENODEV;
+ }
+
+ key = "reg";
+ ret = of_property_read_u32(pdev->dev.of_node, key, &val);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to read %s\n", key);
+ return ret;
+ }
+ vreg->resource = val;
+
+ if ((vreg->parts->uV.mask || vreg->parts->mV.mask) &&
+ (!initdata->constraints.min_uV || !initdata->constraints.max_uV)) {
+ dev_err(&pdev->dev, "no voltage specified for regulator\n");
+ return -EINVAL;
+ }
+
+ key = "bias-pull-down";
+ if (of_property_read_bool(pdev->dev.of_node, key)) {
+ ret = rpm_reg_set(vreg, &vreg->parts->pd, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "%s is invalid", key);
+ return ret;
+ }
+ }
+
+ if (vreg->parts->freq.mask) {
+ ret = rpm_reg_of_parse_freq(&pdev->dev, vreg);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (vreg->parts->pm.mask) {
+ static const char * const keys[] = {
+ "qcom,power-mode-hysteretic",
+ "qcom,power-mode-pwm",
+ };
+
+ ret = rpm_reg_of_select_one(&pdev->dev,
+ keys, ARRAY_SIZE(keys), 1);
+ if (ret < 0)
+ return ret;
+
+ ret = rpm_reg_set(vreg, &vreg->parts->pm, ret);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to set power mode\n");
+ return ret;
+ }
+ }
+
+ if (FORCE_MODE_IS_2_BITS(vreg)) {
+ static const char * const keys[] = {
+ "qcom,force-mode-none",
+ "qcom,force-mode-lpm",
+ "qcom,force-mode-hpm"
+ };
+
+ ret = rpm_reg_of_select_one(&pdev->dev,
+ keys, ARRAY_SIZE(keys), 0);
+ if (ret < 0)
+ return ret;
+
+ ret = rpm_reg_set(vreg, &vreg->parts->fm, ret);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to set force mode\n");
+ return ret;
+ }
+ } else if (FORCE_MODE_IS_3_BITS(vreg)) {
+ static const char * const keys[] = {
+ "qcom,force-mode-none",
+ "qcom,force-mode-lpm",
+ "qcom,force-mode-auto",
+ "qcom,force-mode-hpm",
+ "qcom,force-mode-bypass",
+ };
+
+ ret = rpm_reg_of_select_one(&pdev->dev,
+ keys, ARRAY_SIZE(keys), 0);
+ if (ret < 0)
+ return ret;
+
+ ret = rpm_reg_set(vreg, &vreg->parts->fm, ret);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to set force mode\n");
+ return ret;
+ }
+ }
+
+ config.dev = &pdev->dev;
+ config.init_data = initdata;
+ config.driver_data = vreg;
+ config.of_node = pdev->dev.of_node;
+ rdev = devm_regulator_register(&pdev->dev, &vreg->desc, &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "can't register regulator\n");
+ return PTR_ERR(rdev);
+ }
+
+ return 0;
+}
+
+static struct platform_driver rpm_reg_driver = {
+ .probe = rpm_reg_probe,
+ .driver = {
+ .name = "qcom_rpm_reg",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(rpm_of_match),
+ },
+};
+
+static int __init rpm_reg_init(void)
+{
+ return platform_driver_register(&rpm_reg_driver);
+}
+subsys_initcall(rpm_reg_init);
+
+static void __exit rpm_reg_exit(void)
+{
+ platform_driver_unregister(&rpm_reg_driver);
+}
+module_exit(rpm_reg_exit)
+
+MODULE_DESCRIPTION("Qualcomm RPM regulator driver");
+MODULE_LICENSE("GPL v2");
--
1.8.2.2

2014-06-17 17:08:04

by Kevin Hilman

[permalink] [raw]
Subject: Re: [PATCH v3 0/3] Qualcomm Resource Power Manager driver

+Paul Walmsley

Bjorn Andersson <[email protected]> writes:

> This series adds a regulator driver for the Resource Power Manager found in
> Qualcomm 8660, 8960 and 8064 based devices.
>
> The RPM driver exposes resources to its child devices, that can be accessed to
> implement drivers for the regulators, clocks and bus frequency control that's
> owned by the RPM in these devices.
>
> Changes since v2:
> - Fix copy-paste error in dt binding
> - Correct incomplete move from mfd to soc
> - Correct const mistake in regulator driver
>
> Changes since v1:
> - Moved rpm driver to drivers/soc

I'm not sure I follow the motivation for having this under drivers/soc?

In fact, my (possibly incorrect) understanding of this Resource Power
Manager is that it's actually to manage communication/control of
resources that are actually handled off the SoC by a microcontroller.

I added Paul W. to Cc so he can correct me, but I think this is a ways
off from the goal of what drivers/soc was for.

Kevin

2014-06-17 17:15:16

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH v3 0/3] Qualcomm Resource Power Manager driver

On Tue, Jun 17, 2014 at 10:07 AM, Kevin Hilman <[email protected]> wrote:
> +Paul Walmsley
>
> Bjorn Andersson <[email protected]> writes:
>
>> This series adds a regulator driver for the Resource Power Manager found in
>> Qualcomm 8660, 8960 and 8064 based devices.
>>
>> The RPM driver exposes resources to its child devices, that can be accessed to
>> implement drivers for the regulators, clocks and bus frequency control that's
>> owned by the RPM in these devices.
>>
>> Changes since v2:
>> - Fix copy-paste error in dt binding
>> - Correct incomplete move from mfd to soc
>> - Correct const mistake in regulator driver
>>
>> Changes since v1:
>> - Moved rpm driver to drivers/soc
>
> I'm not sure I follow the motivation for having this under drivers/soc?
>
Hi Kevin,

I've made the argument that to me this is conceptually a black box
handling regulators, clocks and other stuff; hence similar to a PMIC,
which would fit nicely into drivers/mfd.

I still think this is the case and now that I look back I didn't get
any pushback from Lee Jones so maybe the move was premature?

Regards,
Bjorn

2014-06-17 22:29:26

by Srinivas Kandagatla

[permalink] [raw]
Subject: Re: [PATCH v3 0/3] Qualcomm Resource Power Manager driver

Hi Bjorn,

Thankyou for the patches, these were handy for testing USB on APQ8064.

Tested-by: Srinivas Kandagatla <[email protected]>

--srini

On 16/06/14 19:46, Bjorn Andersson wrote:
> This series adds a regulator driver for the Resource Power Manager found in
> Qualcomm 8660, 8960 and 8064 based devices.
>
> The RPM driver exposes resources to its child devices, that can be accessed to
> implement drivers for the regulators, clocks and bus frequency control that's
> owned by the RPM in these devices.
>
> Changes since v2:
> - Fix copy-paste error in dt binding
> - Correct incomplete move from mfd to soc
> - Correct const mistake in regulator driver
>
> Changes since v1:
> - Moved rpm driver to drivers/soc
> - Extracted resource table structs from rpm struct, as per Srinivas request
> - Dropped mode setting support for the regulators for now. Unsure if we need
> it and it requires some rework from the codeaurora solution.
> - Using set_voltage_sel instead of rolling my own "snapping", as per Marks
> request
> - Split regulator ops in mV, uV and swtich versions as per Marks request.
> - Added devicetree property to enable pull down.
>
> Bjorn Andersson (3):
> soc: devicetree: bindings: Add Qualcomm RPM DT binding
> soc: qcom-rpm: Driver for the Qualcomm RPM
> regulator: qcom-rpm: Regulator driver for the Qualcomm RPM
>
> .../devicetree/bindings/soc/qcom/qcom,rpm.txt | 261 +++++++
> drivers/regulator/Kconfig | 12 +
> drivers/regulator/Makefile | 1 +
> drivers/regulator/qcom_rpm-regulator.c | 787 +++++++++++++++++++++
> drivers/soc/qcom/Kconfig | 14 +
> drivers/soc/qcom/Makefile | 1 +
> drivers/soc/qcom/qcom_rpm.c | 573 +++++++++++++++
> include/dt-bindings/soc/qcom,rpm.h | 142 ++++
> include/linux/soc/qcom_rpm.h | 12 +
> 9 files changed, 1803 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom,rpm.txt
> create mode 100644 drivers/regulator/qcom_rpm-regulator.c
> create mode 100644 drivers/soc/qcom/qcom_rpm.c
> create mode 100644 include/dt-bindings/soc/qcom,rpm.h
> create mode 100644 include/linux/soc/qcom_rpm.h
>

2014-06-17 23:59:17

by Stephen Boyd

[permalink] [raw]
Subject: Re: [PATCH v3 1/3] soc: devicetree: bindings: Add Qualcomm RPM DT binding

On 06/16/14 11:46, Bjorn Andersson wrote:
> diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,rpm.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,rpm.txt
> new file mode 100644
> index 0000000..0366533
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,rpm.txt
> @@ -0,0 +1,260 @@
> +Qualcomm Resource Power Manager (RPM)
> +
[...]
> +
> +- reg:
> + Usage: required
> + Value type: <prop-encoded-array>
> + Definition: two entries specifying the RPM's message ram and ipc register
> +
> +- reg-names:
> + Usage: required
> + Value type: <string-array>
> + Definition: must contain the following, in order:
> + "msg_ram"
> + "ipc"

ipc is concerning....

> + rpm@108000 {
> + compatible = "qcom,rpm-msm8960";
> + reg = <0x108000 0x1000 0x2011008 0x4>;
> +

(reg-names is missing from the example)

because ipc is actually a register inside the Krait complex's global
clock control/distribution hardware block (it's located at 0x2011000).
>From what I can tell, this is the only non-clock/power register inside
there. I plan to send out a driver for this hardware block so that I can
switch the L2 aux source mux over to PLL8 instead of PXO (done with a
single register write to 0x2011028) and this mapping/use here is going
to conflict with that unless I only map the single register like is done
here.

I wonder if we'd be better off making this region a separate node and
having some phandle to it here in the RPM node? That way we have a
driver that provides a clock and some IPC handle the RPM driver can get.
The SMD driver also uses the same register to kick other processors so
having some generic IPC handle may be useful there too.

--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

2014-06-18 05:20:02

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH v3 1/3] soc: devicetree: bindings: Add Qualcomm RPM DT binding

On Tue, Jun 17, 2014 at 4:59 PM, Stephen Boyd <[email protected]> wrote:
[...]
>
> because ipc is actually a register inside the Krait complex's global
> clock control/distribution hardware block (it's located at 0x2011000).
> From what I can tell, this is the only non-clock/power register inside
> there. I plan to send out a driver for this hardware block so that I can
> switch the L2 aux source mux over to PLL8 instead of PXO (done with a
> single register write to 0x2011028) and this mapping/use here is going
> to conflict with that unless I only map the single register like is done
> here.
>
> I wonder if we'd be better off making this region a separate node and
> having some phandle to it here in the RPM node? That way we have a
> driver that provides a clock and some IPC handle the RPM driver can get.
> The SMD driver also uses the same register to kick other processors so
> having some generic IPC handle may be useful there too.

Thanks Stephen,

I never connected the dots here but now that I found the right pieces of
documentation I can only agree with you. This would better be some sort of
reverse interrupt chip.

Another such use case would be the smsm and smp2p, which in the codeaurora tree
are modelled with a custom "state change" api and as gpios respectively. Both
of these seems like they should better just be modelled as incoming virtual
interrupts and then some sort of outgoing "interrupts" or "signals".

Maybe I'm over optimistic regarding the reusability here, but I definitely
agree with you that having a "ipc = <&apcs 0>;" does look like a better
solution.

Regards,
Bjorn

2014-06-18 08:34:20

by Srinivas Kandagatla

[permalink] [raw]
Subject: Re: [PATCH v3 1/3] soc: devicetree: bindings: Add Qualcomm RPM DT binding



On 18/06/14 00:59, Stephen Boyd wrote:
> On 06/16/14 11:46, Bjorn Andersson wrote:
>> diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,rpm.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,rpm.txt
>> new file mode 100644
>> index 0000000..0366533
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,rpm.txt
>> @@ -0,0 +1,260 @@
>> +Qualcomm Resource Power Manager (RPM)
>> +
> [...]
>> +
>> +- reg:
>> + Usage: required
>> + Value type: <prop-encoded-array>
>> + Definition: two entries specifying the RPM's message ram and ipc register
>> +
>> +- reg-names:
>> + Usage: required
>> + Value type: <string-array>
>> + Definition: must contain the following, in order:
>> + "msg_ram"
>> + "ipc"
>
> ipc is concerning....
>
>> + rpm@108000 {
>> + compatible = "qcom,rpm-msm8960";
>> + reg = <0x108000 0x1000 0x2011008 0x4>;
>> +
>
> (reg-names is missing from the example)
>
> because ipc is actually a register inside the Krait complex's global
> clock control/distribution hardware block (it's located at 0x2011000).
> From what I can tell, this is the only non-clock/power register inside
> there. I plan to send out a driver for this hardware block so that I can
> switch the L2 aux source mux over to PLL8 instead of PXO (done with a
> single register write to 0x2011028) and this mapping/use here is going
> to conflict with that unless I only map the single register like is done
> here.
>
> I wonder if we'd be better off making this region a separate node and
> having some phandle to it here in the RPM node? That way we have a

Can't we use syscon based on regmap here? syscon is a better way to
share a common register space across multiple drivers.

> driver that provides a clock and some IPC handle the RPM driver can get.
> The SMD driver also uses the same register to kick other processors so
> having some generic IPC handle may be useful there too.
>

2014-06-18 15:53:45

by Kevin Hilman

[permalink] [raw]
Subject: Re: [PATCH v3 0/3] Qualcomm Resource Power Manager driver

Bjorn Andersson <[email protected]> writes:

> On Tue, Jun 17, 2014 at 10:07 AM, Kevin Hilman <[email protected]> wrote:
>> +Paul Walmsley
>>
>> Bjorn Andersson <[email protected]> writes:
>>
>>> This series adds a regulator driver for the Resource Power Manager found in
>>> Qualcomm 8660, 8960 and 8064 based devices.
>>>
>>> The RPM driver exposes resources to its child devices, that can be accessed to
>>> implement drivers for the regulators, clocks and bus frequency control that's
>>> owned by the RPM in these devices.
>>>
>>> Changes since v2:
>>> - Fix copy-paste error in dt binding
>>> - Correct incomplete move from mfd to soc
>>> - Correct const mistake in regulator driver
>>>
>>> Changes since v1:
>>> - Moved rpm driver to drivers/soc
>>
>> I'm not sure I follow the motivation for having this under drivers/soc?
>>
> Hi Kevin,
>
> I've made the argument that to me this is conceptually a black box
> handling regulators, clocks and other stuff; hence similar to a PMIC,
> which would fit nicely into drivers/mfd.
>
> I still think this is the case and now that I look back I didn't get
> any pushback from Lee Jones so maybe the move was premature?

Yes, IMO, the move was premature, but hopefully the drivers/soc folks
can chime in an clarify the criteria for inclusion there.

Kevin

2014-06-18 16:03:54

by Kumar Gala

[permalink] [raw]
Subject: Re: [PATCH v3 0/3] Qualcomm Resource Power Manager driver


On Jun 18, 2014, at 10:53 AM, Kevin Hilman <[email protected]> wrote:

> Bjorn Andersson <[email protected]> writes:
>
>> On Tue, Jun 17, 2014 at 10:07 AM, Kevin Hilman <[email protected]> wrote:
>>> +Paul Walmsley
>>>
>>> Bjorn Andersson <[email protected]> writes:
>>>
>>>> This series adds a regulator driver for the Resource Power Manager found in
>>>> Qualcomm 8660, 8960 and 8064 based devices.
>>>>
>>>> The RPM driver exposes resources to its child devices, that can be accessed to
>>>> implement drivers for the regulators, clocks and bus frequency control that's
>>>> owned by the RPM in these devices.
>>>>
>>>> Changes since v2:
>>>> - Fix copy-paste error in dt binding
>>>> - Correct incomplete move from mfd to soc
>>>> - Correct const mistake in regulator driver
>>>>
>>>> Changes since v1:
>>>> - Moved rpm driver to drivers/soc
>>>
>>> I'm not sure I follow the motivation for having this under drivers/soc?
>>>
>> Hi Kevin,
>>
>> I've made the argument that to me this is conceptually a black box
>> handling regulators, clocks and other stuff; hence similar to a PMIC,
>> which would fit nicely into drivers/mfd.
>>
>> I still think this is the case and now that I look back I didn't get
>> any pushback from Lee Jones so maybe the move was premature?
>
> Yes, IMO, the move was premature, but hopefully the drivers/soc folks
> can chime in an clarify the criteria for inclusion there.
>
> Kevin

I dont agree, I think having this in drivers/soc means that we can clearly go through drivers/soc in the future and look for patterns across SoCs that should be re-factored. Where MFD seems like its become the new drivers misc.

- k

--
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

2014-06-18 16:44:26

by Kevin Hilman

[permalink] [raw]
Subject: Re: [PATCH v3 0/3] Qualcomm Resource Power Manager driver

Kumar Gala <[email protected]> writes:

> On Jun 18, 2014, at 10:53 AM, Kevin Hilman <[email protected]> wrote:
>
>> Bjorn Andersson <[email protected]> writes:
>>
>>> On Tue, Jun 17, 2014 at 10:07 AM, Kevin Hilman <[email protected]> wrote:
>>>> +Paul Walmsley
>>>>
>>>> Bjorn Andersson <[email protected]> writes:
>>>>
>>>>> This series adds a regulator driver for the Resource Power Manager found in
>>>>> Qualcomm 8660, 8960 and 8064 based devices.
>>>>>
>>>>> The RPM driver exposes resources to its child devices, that can be accessed to
>>>>> implement drivers for the regulators, clocks and bus frequency control that's
>>>>> owned by the RPM in these devices.
>>>>>
>>>>> Changes since v2:
>>>>> - Fix copy-paste error in dt binding
>>>>> - Correct incomplete move from mfd to soc
>>>>> - Correct const mistake in regulator driver
>>>>>
>>>>> Changes since v1:
>>>>> - Moved rpm driver to drivers/soc
>>>>
>>>> I'm not sure I follow the motivation for having this under drivers/soc?
>>>>
>>> Hi Kevin,
>>>
>>> I've made the argument that to me this is conceptually a black box
>>> handling regulators, clocks and other stuff; hence similar to a PMIC,
>>> which would fit nicely into drivers/mfd.
>>>
>>> I still think this is the case and now that I look back I didn't get
>>> any pushback from Lee Jones so maybe the move was premature?
>>
>> Yes, IMO, the move was premature, but hopefully the drivers/soc folks
>> can chime in an clarify the criteria for inclusion there.
>>
>> Kevin
>
> I dont agree, I think having this in drivers/soc means that we can
> clearly go through drivers/soc in the future and look for patterns
> across SoCs that should be re-factored.

I don't believe that was the goal in creating drivers/soc.

> Where MFD seems like its become the new drivers misc.

Well, I don't think that drivers/soc wants to be the new drivers/misc
either. ;)

Thinking more about what this RPM driver actually does, and since you
mentioned patterns across SoCs, it seems to me the RPM driver bascially
just doing the IPC.

So, rather than MFD or drivers/soc, it seems to me that it should be
implmented as a controller in the new common mailbox framwork[1] being
worked on by Jassi Brar (added to Cc.)

IIUC, RPM is actually only doing one-way IPC (it only exposes a write()
interface to clients) so it seems like a rather simple implementation of
a mailbox controller.

I believe Bjorn is already on the list of folks Cc'd on the common
mailbox framework, so it would be good to hear from him why RPM wouldn't
fit under that framework.

Thanks,

Kevin

[1] https://lkml.org/lkml/2014/6/12/470

2014-06-18 16:48:32

by Lee Jones

[permalink] [raw]
Subject: Re: [PATCH v3 0/3] Qualcomm Resource Power Manager driver

On Wed, 18 Jun 2014, Kumar Gala wrote:

>
> On Jun 18, 2014, at 10:53 AM, Kevin Hilman <[email protected]> wrote:
>
> > Bjorn Andersson <[email protected]> writes:
> >
> >> On Tue, Jun 17, 2014 at 10:07 AM, Kevin Hilman <[email protected]> wrote:
> >>> +Paul Walmsley
> >>>
> >>> Bjorn Andersson <[email protected]> writes:
> >>>
> >>>> This series adds a regulator driver for the Resource Power Manager found in
> >>>> Qualcomm 8660, 8960 and 8064 based devices.
> >>>>
> >>>> The RPM driver exposes resources to its child devices, that can be accessed to
> >>>> implement drivers for the regulators, clocks and bus frequency control that's
> >>>> owned by the RPM in these devices.
> >>>>
> >>>> Changes since v2:
> >>>> - Fix copy-paste error in dt binding
> >>>> - Correct incomplete move from mfd to soc
> >>>> - Correct const mistake in regulator driver
> >>>>
> >>>> Changes since v1:
> >>>> - Moved rpm driver to drivers/soc
> >>>
> >>> I'm not sure I follow the motivation for having this under drivers/soc?
> >>>
> >> Hi Kevin,
> >>
> >> I've made the argument that to me this is conceptually a black box
> >> handling regulators, clocks and other stuff; hence similar to a PMIC,
> >> which would fit nicely into drivers/mfd.
> >>
> >> I still think this is the case and now that I look back I didn't get
> >> any pushback from Lee Jones so maybe the move was premature?
> >
> > Yes, IMO, the move was premature, but hopefully the drivers/soc folks
> > can chime in an clarify the criteria for inclusion there.
> >
> > Kevin
>
> I dont agree, I think having this in drivers/soc means that we can
> clearly go through drivers/soc in the future and look for patterns
> across SoCs that should be re-factored.

> Where MFD seems like its become the new drivers misc.

Do you have any grounds for that statement? I only know of one driver
which doesn't fit the bounds of a true MFD. If you know of more, I'd
like to hear about it.

--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

2014-06-18 19:16:22

by Stephen Boyd

[permalink] [raw]
Subject: Re: [PATCH v3 1/3] soc: devicetree: bindings: Add Qualcomm RPM DT binding

On 06/18/14 01:34, Srinivas Kandagatla wrote:
>
>
> On 18/06/14 00:59, Stephen Boyd wrote:
>> On 06/16/14 11:46, Bjorn Andersson wrote:
>>> diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,rpm.txt
>>> b/Documentation/devicetree/bindings/soc/qcom/qcom,rpm.txt
>>> new file mode 100644
>>> index 0000000..0366533
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,rpm.txt
>>> @@ -0,0 +1,260 @@
>>> +Qualcomm Resource Power Manager (RPM)
>>> +
>> [...]
>>> +
>>> +- reg:
>>> + Usage: required
>>> + Value type: <prop-encoded-array>
>>> + Definition: two entries specifying the RPM's message ram and
>>> ipc register
>>> +
>>> +- reg-names:
>>> + Usage: required
>>> + Value type: <string-array>
>>> + Definition: must contain the following, in order:
>>> + "msg_ram"
>>> + "ipc"
>>
>> ipc is concerning....
>>
>>> + rpm@108000 {
>>> + compatible = "qcom,rpm-msm8960";
>>> + reg = <0x108000 0x1000 0x2011008 0x4>;
>>> +
>>
>> (reg-names is missing from the example)
>>
>> because ipc is actually a register inside the Krait complex's global
>> clock control/distribution hardware block (it's located at 0x2011000).
>> From what I can tell, this is the only non-clock/power register inside
>> there. I plan to send out a driver for this hardware block so that I can
>> switch the L2 aux source mux over to PLL8 instead of PXO (done with a
>> single register write to 0x2011028) and this mapping/use here is going
>> to conflict with that unless I only map the single register like is done
>> here.
>>
>> I wonder if we'd be better off making this region a separate node and
>> having some phandle to it here in the RPM node? That way we have a
>
> Can't we use syscon based on regmap here? syscon is a better way to
> share a common register space across multiple drivers.

How would the mux clock be registered? I'd like it to be registered by
the driver associated with this device with something like
devm_clk_register(). From what I can tell syscon wouldn't allow that
unless we extend the syscon driver to handle more specific compatible
strings.

--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

2014-06-19 03:55:50

by Jassi Brar

[permalink] [raw]
Subject: Re: [PATCH v3 0/3] Qualcomm Resource Power Manager driver

On 18 June 2014 22:14, Kevin Hilman <[email protected]> wrote:
> Kumar Gala <[email protected]> writes:
>
>> On Jun 18, 2014, at 10:53 AM, Kevin Hilman <[email protected]> wrote:
>>
>>> Bjorn Andersson <[email protected]> writes:
>>>
>>>> On Tue, Jun 17, 2014 at 10:07 AM, Kevin Hilman <[email protected]> wrote:
>>>>> +Paul Walmsley
>>>>>
>>>>> Bjorn Andersson <[email protected]> writes:
>>>>>
>>>>>> This series adds a regulator driver for the Resource Power Manager found in
>>>>>> Qualcomm 8660, 8960 and 8064 based devices.
>>>>>>
>>>>>> The RPM driver exposes resources to its child devices, that can be accessed to
>>>>>> implement drivers for the regulators, clocks and bus frequency control that's
>>>>>> owned by the RPM in these devices.
>>>>>>
>>>>>> Changes since v2:
>>>>>> - Fix copy-paste error in dt binding
>>>>>> - Correct incomplete move from mfd to soc
>>>>>> - Correct const mistake in regulator driver
>>>>>>
>>>>>> Changes since v1:
>>>>>> - Moved rpm driver to drivers/soc
>>>>>
>>>>> I'm not sure I follow the motivation for having this under drivers/soc?
>>>>>
>>>> Hi Kevin,
>>>>
>>>> I've made the argument that to me this is conceptually a black box
>>>> handling regulators, clocks and other stuff; hence similar to a PMIC,
>>>> which would fit nicely into drivers/mfd.
>>>>
>>>> I still think this is the case and now that I look back I didn't get
>>>> any pushback from Lee Jones so maybe the move was premature?
>>>
>>> Yes, IMO, the move was premature, but hopefully the drivers/soc folks
>>> can chime in an clarify the criteria for inclusion there.
>>>
>>> Kevin
>>
>> I dont agree, I think having this in drivers/soc means that we can
>> clearly go through drivers/soc in the future and look for patterns
>> across SoCs that should be re-factored.
>
> I don't believe that was the goal in creating drivers/soc.
>
>> Where MFD seems like its become the new drivers misc.
>
> Well, I don't think that drivers/soc wants to be the new drivers/misc
> either. ;)
>
> Thinking more about what this RPM driver actually does, and since you
> mentioned patterns across SoCs, it seems to me the RPM driver bascially
> just doing the IPC.
>
> So, rather than MFD or drivers/soc, it seems to me that it should be
> implmented as a controller in the new common mailbox framwork[1] being
> worked on by Jassi Brar (added to Cc.)
>
> IIUC, RPM is actually only doing one-way IPC (it only exposes a write()
> interface to clients) so it seems like a rather simple implementation of
> a mailbox controller.
>
Yup, qcom_rpm.c is exactly what drivers/mailbox/ is meant for.

Agreed the driver is _very_ SoC specific (Qualcomm) but so is any
other mailbox driver in my knowledge. So either we move all to
drivers/mailbox/ or empty that out into drivers/soc/ I tend to lean
towards the first option.

Thanks
-Jassi

2014-06-19 18:22:45

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH v3 0/3] Qualcomm Resource Power Manager driver

On Wed, Jun 18, 2014 at 8:55 PM, Jassi Brar <[email protected]> wrote:
> On 18 June 2014 22:14, Kevin Hilman <[email protected]> wrote:
[...]
>> Thinking more about what this RPM driver actually does, and since you
>> mentioned patterns across SoCs, it seems to me the RPM driver bascially
>> just doing the IPC.
>>
>> So, rather than MFD or drivers/soc, it seems to me that it should be
>> implmented as a controller in the new common mailbox framwork[1] being
>> worked on by Jassi Brar (added to Cc.)
>>
>> IIUC, RPM is actually only doing one-way IPC (it only exposes a write()
>> interface to clients) so it seems like a rather simple implementation of
>> a mailbox controller.
>>
> Yup, qcom_rpm.c is exactly what drivers/mailbox/ is meant for.
>

The RPM provides a register file with 80ish registers of variable size, to
program the hardware you write to these registers. Then you write to a register
selector register and then signal an outgoing interrupt.

That is, the interface exposed to the kernel by the SoC is not an mailbox like
interface.

So I do not share your view that this is "exactly what mailbox is meant for",
because if so then you're just re-inventing regmap - with variable size regs.


The reason why I'm not using a regmap as my abstraction between the rpm and the
clients (e.g. regulator driver) is because it only supports fixed size
registers.


To me the mailbox api is supposed to abstract communication hardware, not to
abstract communication between software components.

Regards,
Bjorn

2014-06-19 20:01:24

by Jassi Brar

[permalink] [raw]
Subject: Re: [PATCH v3 0/3] Qualcomm Resource Power Manager driver

On 19 June 2014 23:52, Bjorn Andersson <[email protected]> wrote:
> On Wed, Jun 18, 2014 at 8:55 PM, Jassi Brar <[email protected]> wrote:
>> On 18 June 2014 22:14, Kevin Hilman <[email protected]> wrote:
> [...]
>>> Thinking more about what this RPM driver actually does, and since you
>>> mentioned patterns across SoCs, it seems to me the RPM driver bascially
>>> just doing the IPC.
>>>
>>> So, rather than MFD or drivers/soc, it seems to me that it should be
>>> implmented as a controller in the new common mailbox framwork[1] being
>>> worked on by Jassi Brar (added to Cc.)
>>>
>>> IIUC, RPM is actually only doing one-way IPC (it only exposes a write()
>>> interface to clients) so it seems like a rather simple implementation of
>>> a mailbox controller.
>>>
>> Yup, qcom_rpm.c is exactly what drivers/mailbox/ is meant for.
>>
>
> The RPM provides a register file with 80ish registers of variable size, to
> program the hardware you write to these registers. Then you write to a register
> selector register and then signal an outgoing interrupt.
>
For mailbox_request_channel(), you have dev_get_qcom_rpm() and
qcom_rpm_write() for mbox_send_message()
Rest all is what you need to fire off a message to remote or register
for interrupts. So nothing new to me.

> That is, the interface exposed to the kernel by the SoC is not an mailbox like
> interface.
>
I don't understand how having to program 80 registers makes it "not
like mailbox"?
I have used mailbox api to pass messages between CPUs (using PPI)
under same instance of Linux and otoh I think it could also support
IPC over gpio (if someone gets that desperate).
Mailbox isn't about how you program the h/w. Do whatever is needed to
send a message across.

BTW I haven't looked closely, but probably you could push the data tables in DT?

Cheers
-Jassi

2014-06-20 04:59:31

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH v3 0/3] Qualcomm Resource Power Manager driver

On Thu, Jun 19, 2014 at 1:01 PM, Jassi Brar <[email protected]> wrote:
[...]
> Mailbox isn't about how you program the h/w. Do whatever is needed to
> send a message across.
>

But there are no messages to get across here, each individual resource
is exposed directly in the address space of the Linux system.

> BTW I haven't looked closely, but probably you could push the data tables in DT?
>

The first RFC for this had all configuration in devicetree; we decided
not to go that path as this gave a cleaner abstraction and is less
error prone.

Regards,
Bjorn

2014-06-20 05:17:43

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH v3 0/3] Qualcomm Resource Power Manager driver

On Wed, Jun 18, 2014 at 9:44 AM, Kevin Hilman <[email protected]> wrote:
[...]
> Thinking more about what this RPM driver actually does, and since you
> mentioned patterns across SoCs, it seems to me the RPM driver bascially
> just doing the IPC.
>

Yes, technically this is IPC. But it's all exposed in memory as if it
was hardware, so there's no messages or packets to be interpreted by
the other side.

> So, rather than MFD or drivers/soc, it seems to me that it should be
> implmented as a controller in the new common mailbox framwork[1] being
> worked on by Jassi Brar (added to Cc.)
>
> IIUC, RPM is actually only doing one-way IPC (it only exposes a write()
> interface to clients) so it seems like a rather simple implementation of
> a mailbox controller.
>

What I think you miss here is the detail of that what the regulator
writes is not what is passed over the IPC, but rather is just an
interface to abstract away how things are spread our in the register
space.

So the only place where we do have a "mailbox" here is the actual
function call between the regulator and the rpm drivers; not between
the rpm driver and the rpm.

> I believe Bjorn is already on the list of folks Cc'd on the common
> mailbox framework, so it would be good to hear from him why RPM wouldn't
> fit under that framework.
>

In a separate group of Qualcomm platforms the communication with the
RPM is done by passing messages over a shared memory channel; as this
requires a completely different implementation of the rpm driver, I
have started to look at Jassi's patch series.

Unfortunately at this point it does not look like the proposed mailbox
framework would reduce the complexity of the implementation nor
provide any additional benefits when it comes to being able to
exchange the underlaying communication methods.

But I will continue to follow the development of the mailbox framework.

Regards,
Bjorn

2014-06-20 13:18:15

by Jassi Brar

[permalink] [raw]
Subject: Re: [PATCH v3 0/3] Qualcomm Resource Power Manager driver

On 20 June 2014 10:47, Bjorn Andersson <[email protected]> wrote:
> On Wed, Jun 18, 2014 at 9:44 AM, Kevin Hilman <[email protected]> wrote:
> [...]
>> Thinking more about what this RPM driver actually does, and since you
>> mentioned patterns across SoCs, it seems to me the RPM driver bascially
>> just doing the IPC.
>>
>
> Yes, technically this is IPC. But it's all exposed in memory as if it
> was hardware, so there's no messages or packets to be interpreted by
> the other side.
>
>> So, rather than MFD or drivers/soc, it seems to me that it should be
>> implmented as a controller in the new common mailbox framwork[1] being
>> worked on by Jassi Brar (added to Cc.)
>>
>> IIUC, RPM is actually only doing one-way IPC (it only exposes a write()
>> interface to clients) so it seems like a rather simple implementation of
>> a mailbox controller.
>>
>
> What I think you miss here is the detail of that what the regulator
> writes is not what is passed over the IPC, but rather is just an
> interface to abstract away how things are spread our in the register
> space.
>
> So the only place where we do have a "mailbox" here is the actual
> function call between the regulator and the rpm drivers; not between
> the rpm driver and the rpm.
>
Is the RPM a firmware running on a separate processor outside the
scope of Linux ?

Is an irq raised to the RPM when you do writel(RPM_SIGNAL, rpm->ipc_rpm_reg) ?

Do you get the qcom_rpm_ack_interrupt() only when the RPM firmware has
taken action on Linux's request (i.e, values filled in 80ish
registers)?

I maybe wrong but I think the answer to all above is Yes, and that is
the reason I think its no different than other mailbox controllers.
For example, look at pl320_ipc_transmit()


>> I believe Bjorn is already on the list of folks Cc'd on the common
>> mailbox framework, so it would be good to hear from him why RPM wouldn't
>> fit under that framework.
>>
>
> In a separate group of Qualcomm platforms the communication with the
> RPM is done by passing messages over a shared memory channel; as this
> requires a completely different implementation of the rpm driver, I
> have started to look at Jassi's patch series.
>
> Unfortunately at this point it does not look like the proposed mailbox
> framework would reduce the complexity of the implementation nor
> provide any additional benefits when it comes to being able to
> exchange the underlaying communication methods.
>
For your simple one-way communication, using mailbox api isn't going
to change lives.

Cheers,
-Jassi

2014-07-04 06:11:36

by Pramod Gurav

[permalink] [raw]
Subject: RE: [PATCH v3 1/3] soc: devicetree: bindings: Add Qualcomm RPM DT binding


Hi Bjorn,

-----Original Message-----
From: "Bjorn Andersson" <[email protected]>
Sent: Tuesday, 17 June, 2014 12:16am
To: "Rob Herring" <[email protected]>, "Mark Rutland" <[email protected]>, "Liam Girdwood" <[email protected]>, "Mark Brown" <[email protected]>, "Kumar Gala" <[email protected]>
Cc: "Lee Jones" <[email protected]>, "Josh Cartwright" <[email protected]>, [email protected], [email protected], [email protected], [email protected]
Subject: [PATCH v3 1/3] soc: devicetree: bindings: Add Qualcomm RPM DT binding

Add binding for the Qualcomm Resource Power Manager (RPM) found in 8660,
8960 and 8064 based devices. The binding currently describes the rpm
itself and the regulator subnodes.

Signed-off-by: Bjorn Andersson <[email protected]>
---
.../devicetree/bindings/soc/qcom/qcom,rpm.txt | 260 +++++++++++++++++++++
include/dt-bindings/soc/qcom,rpm.h | 142 +++++++++++
2 files changed, 402 insertions(+)
create mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom,rpm.txt
create mode 100644 include/dt-bindings/soc/qcom,rpm.h

diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,rpm.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,rpm.txt
new file mode 100644
index 0000000..0366533
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/qcom/qcom,rpm.txt
@@ -0,0 +1,260 @@
+Qualcomm Resource Power Manager (RPM)
+
+This driver is used to interface with the Resource Power Manager (RPM) found in
+various Qualcomm platforms. The RPM allows each component in the system to vote
+for state of the system resources, such as clocks, regulators and bus
+frequencies.
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be one of:
+ "qcom,rpm-apq8064"
+ "qcom,rpm-msm8660"
+ "qcom,rpm-msm8960"
+
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: two entries specifying the RPM's message ram and ipc register
+
+- reg-names:
+ Usage: required
+ Value type: <string-array>
+ Definition: must contain the following, in order:
+ "msg_ram"
+ "ipc"
+
+- interrupts:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: three entries specifying the RPM's:
+ 1. acknowledgement interrupt
+ 2. error interrupt
+ 3. wakeup interrupt
+
+- interrupt-names:
+ Usage: required
+ Value type: <string-array>
+ Definition: must be the three strings "ack", "err" and "wakeup", in order
+
+- #address-cells:
+ Usage: required
+ Value type: <u32>
+ Definition: must be 1
+
+- #size-cells:
+ Usage: required
+ Value type: <u32>
+ Definition: must be 0
+
+
+= SUBDEVICES
+
+The RPM exposes resources to its subnodes. The below bindings specify the set
+of valid subnodes that can operate on these resources.
+
+== Switch-mode Power Supply regulator
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be one of:
+ "qcom,rpm-pm8058-smps"
+ "qcom,rpm-pm8901-ftsmps"
+ "qcom,rpm-pm8921-smps"
+ "qcom,rpm-pm8921-ftsmps"
+
+- reg:
+ Usage: required
+ Value type: <u32>
+ Definition: resource as defined in <dt-bindings/soc/qcom,rpm.h>
+
+- bias-pull-down:
+ Usage: optional
+ Value type: <empty>
+ Definition: enable pull down of the regulator when inactive
+
+- qcom,switch-mode-frequency:
+ Usage: required
+ Value type: <u32>
+ Definition: Frequency (Hz) of the switch-mode power supply;
+ must be one of:
+ 19200000, 9600000, 6400000, 4800000, 3840000, 3200000,
+ 2740000, 2400000, 2130000, 1920000, 1750000, 1600000,
+ 1480000, 1370000, 1280000, 1200000
+
+- qcom,force-mode-none:
+ Usage: optional (default if no other qcom,force-mode is specified)
+ Value type: <empty>
+ Defintion: indicates that the regulator should not be forced to any
+ particular mode
+
+- qcom,force-mode-lpm:
+ Usage: optional
+ Value type: <empty>
+ Definition: indicates that the regulator should be forced to operate in
+ low-power-mode
+
+- qcom,force-mode-auto:
+ Usage: optional (only available for 8960/8064)
+ Value type: <empty>
+ Definition: indicates that the regulator should be automatically pick
+ operating mode
+
+- qcom,force-mode-hpm:
+ Usage: optional (only available for 8960/8064)
+ Value type: <empty>
+ Definition: indicates that the regulator should be forced to operate in
+ high-power-mode
+
+- qcom,force-mode-bypass: (only for 8960/8064)
+ Usage: optional (only available for 8960/8064)
+ Value type: <empty>
+ Definition: indicates that the regulator should be forced to operate in
+ bypass mode
+
+- qcom,power-mode-hysteretic:
+ Usage: optional
+ Value type: <empty>
+ Definition: indicates that the power supply should operate in hysteretic
+ mode (defaults to qcom,power-mode-pwm if not specified)
+
+- qcom,power-mode-pwm:
+ Usage: optional
+ Value type: <empty>
+ Definition: indicates that the power supply should operate in pwm mode
+
+Standard regulator bindings are used inside switch mode power supply subnodes.
+Check Documentation/devicetree/bindings/regulator/regulator.txt for more
+details.
+
+== Low-dropout regulator
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be one of:
+ "qcom,rpm-pm8058-pldo"
+ "qcom,rpm-pm8058-nldo"
+ "qcom,rpm-pm8901-pldo"
+ "qcom,rpm-pm8901-nldo"
+ "qcom,rpm-pm8921-pldo"
+ "qcom,rpm-pm8921-nldo"
+ "qcom,rpm-pm8921-nldo1200"
+
+- reg:
+ Usage: required
+ Value type: <u32>
+ Definition: resource as defined in <dt-bindings/soc/qcom,rpm.h>
+
+- bias-pull-down:
+ Usage: optional
+ Value type: <empty>
+ Definition: enable pull down of the regulator when inactive
+
+- qcom,force-mode-none:
+ Usage: optional (default if no other qcom,force-mode is specified)
+ Value type: <empty>
+ Defintion: indicates that the regulator should not be forced to any
+ particular mode
+
+- qcom,force-mode-lpm:
+ Usage: optional
+ Value type: <empty>
+ Definition: indicates that the regulator should be forced to operate in
+ low-power-mode
+
+- qcom,force-mode-auto:
+ Usage: optional (only available for 8960/8064)
+ Value type: <empty>
+ Definition: indicates that the regulator should be automatically pick
+ operating mode
+
+- qcom,force-mode-hpm:
+ Usage: optional (only available for 8960/8064)
+ Value type: <empty>
+ Definition: indicates that the regulator should be forced to operate in
+ high-power-mode
+
+- qcom,force-mode-bypass: (only for 8960/8064)
+ Usage: optional (only available for 8960/8064)
+ Value type: <empty>
+ Definition: indicates that the regulator should be forced to operate in
+ bypass mode
+
+Standard regulator bindings are used inside switch low-dropout regulator
+subnodes. Check Documentation/devicetree/bindings/regulator/regulator.txt for
+more details.
+
+== Negative Charge Pump
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be one of:
+ "qcom,rpm-pm8058-ncp"
+ "qcom,rpm-pm8921-ncp"
+
+- reg:
+ Usage: required
+ Value type: <u32>
+ Definition: resource as defined in <dt-bindings/soc/qcom,rpm.h>
+
+- qcom,switch-mode-frequency:
+ Usage: required
+ Value type: <u32>
+ Definition: Frequency (Hz) of the swith mode power supply;
+ must be one of:
+ 19200000, 9600000, 6400000, 4800000, 3840000, 3200000,
+ 2740000, 2400000, 2130000, 1920000, 1750000, 1600000,
+ 1480000, 1370000, 1280000, 1200000
+
+Standard regulator bindings are used inside negative charge pump regulator
+subnodes. Check Documentation/devicetree/bindings/regulator/regulator.txt for
+more details.
+
+== Switch
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be one of:
+ "qcom,rpm-pm8058-switch"
+ "qcom,rpm-pm8901-switch"
+ "qcom,rpm-pm8921-switch"
+
+- reg:
+ Usage: required
+ Value type: <u32>
+ Definition: resource as defined in <dt-bindings/soc/qcom/qcom,rpm.h>
+
+
+= EXAMPLE
+
+ #include <dt-bindings/soc/qcom,rpm.h>
+
+ rpm@108000 {
+ compatible = "qcom,rpm-msm8960";
+ reg = <0x108000 0x1000 0x2011008 0x4>;
+
+ interrupts = <0 19 0>, <0 21 0>, <0 22 0>;
+ interrupt-names = "ack", "err", "wakeup";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pm8921_s1: pm8921-s1 {
+ compatible = "qcom,rpm-pm8921-smps";
+ reg = <QCOM_RPM_PM8921_S1>;
+
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ regulator-always-on;
+
+ bias-pull-down;
+
+ qcom,switch-mode-frequency = <3200000>;
+ };
+ };
+

I may be late here to comment, but came across this extra line at EOF when I was applying these patches on my kernel just now.

diff --git a/include/dt-bindings/soc/qcom,rpm.h b/include/dt-bindings/soc/qcom,rpm.h
new file mode 100644
index 0000000..d9d840b
--- /dev/null
+++ b/include/dt-bindings/soc/qcom,rpm.h
@@ -0,0 +1,142 @@
+/*
+ * This header provides constants for the Qualcomm RPM bindings.
+ */
+
+#ifndef _DT_BINDINGS_SOC_QCOM_RPM_H
+#define _DT_BINDINGS_SOC_QCOM_RPM_H
+
+#define QCOM_RPM_APPS_FABRIC_ARB 1
+#define QCOM_RPM_APPS_FABRIC_CLK 2
+#define QCOM_RPM_APPS_FABRIC_HALT 3
+#define QCOM_RPM_APPS_FABRIC_IOCTL 4
+#define QCOM_RPM_APPS_FABRIC_MODE 5
+#define QCOM_RPM_APPS_L2_CACHE_CTL 6
+#define QCOM_RPM_CFPB_CLK 7
+#define QCOM_RPM_CXO_BUFFERS 8
+#define QCOM_RPM_CXO_CLK 9
+#define QCOM_RPM_DAYTONA_FABRIC_CLK 10
+#define QCOM_RPM_DDR_DMM 11
+#define QCOM_RPM_EBI1_CLK 12
+#define QCOM_RPM_HDMI_SWITCH 13
+#define QCOM_RPM_MMFPB_CLK 14
+#define QCOM_RPM_MM_FABRIC_ARB 15
+#define QCOM_RPM_MM_FABRIC_CLK 16
+#define QCOM_RPM_MM_FABRIC_HALT 17
+#define QCOM_RPM_MM_FABRIC_IOCTL 18
+#define QCOM_RPM_MM_FABRIC_MODE 19
+#define QCOM_RPM_PLL_4 20
+#define QCOM_RPM_PM8058_LDO0 21
+#define QCOM_RPM_PM8058_LDO1 22
+#define QCOM_RPM_PM8058_LDO2 23
+#define QCOM_RPM_PM8058_LDO3 24
+#define QCOM_RPM_PM8058_LDO4 25
+#define QCOM_RPM_PM8058_LDO5 26
+#define QCOM_RPM_PM8058_LDO6 27
+#define QCOM_RPM_PM8058_LDO7 28
+#define QCOM_RPM_PM8058_LDO8 29
+#define QCOM_RPM_PM8058_LDO9 30
+#define QCOM_RPM_PM8058_LDO10 31
+#define QCOM_RPM_PM8058_LDO11 32
+#define QCOM_RPM_PM8058_LDO12 33
+#define QCOM_RPM_PM8058_LDO13 34
+#define QCOM_RPM_PM8058_LDO14 35
+#define QCOM_RPM_PM8058_LDO15 36
+#define QCOM_RPM_PM8058_LDO16 37
+#define QCOM_RPM_PM8058_LDO17 38
+#define QCOM_RPM_PM8058_LDO18 39
+#define QCOM_RPM_PM8058_LDO19 40
+#define QCOM_RPM_PM8058_LDO20 41
+#define QCOM_RPM_PM8058_LDO21 42
+#define QCOM_RPM_PM8058_LDO22 43
+#define QCOM_RPM_PM8058_LDO23 44
+#define QCOM_RPM_PM8058_LDO24 45
+#define QCOM_RPM_PM8058_LDO25 46
+#define QCOM_RPM_PM8058_LVS0 47
+#define QCOM_RPM_PM8058_LVS1 48
+#define QCOM_RPM_PM8058_NCP 49
+#define QCOM_RPM_PM8058_SMPS0 50
+#define QCOM_RPM_PM8058_SMPS1 51
+#define QCOM_RPM_PM8058_SMPS2 52
+#define QCOM_RPM_PM8058_SMPS3 53
+#define QCOM_RPM_PM8058_SMPS4 54
+#define QCOM_RPM_PM8821_L1 55
+#define QCOM_RPM_PM8821_S1 56
+#define QCOM_RPM_PM8821_S2 57
+#define QCOM_RPM_PM8901_LDO0 58
+#define QCOM_RPM_PM8901_LDO1 59
+#define QCOM_RPM_PM8901_LDO2 60
+#define QCOM_RPM_PM8901_LDO3 61
+#define QCOM_RPM_PM8901_LDO4 62
+#define QCOM_RPM_PM8901_LDO5 63
+#define QCOM_RPM_PM8901_LDO6 64
+#define QCOM_RPM_PM8901_LVS0 65
+#define QCOM_RPM_PM8901_LVS1 66
+#define QCOM_RPM_PM8901_LVS2 67
+#define QCOM_RPM_PM8901_LVS3 68
+#define QCOM_RPM_PM8901_MVS 69
+#define QCOM_RPM_PM8901_SMPS0 70
+#define QCOM_RPM_PM8901_SMPS1 71
+#define QCOM_RPM_PM8901_SMPS2 72
+#define QCOM_RPM_PM8901_SMPS3 73
+#define QCOM_RPM_PM8901_SMPS4 74
+#define QCOM_RPM_PM8921_CLK1 75
+#define QCOM_RPM_PM8921_CLK2 76
+#define QCOM_RPM_PM8921_L1 77
+#define QCOM_RPM_PM8921_L2 78
+#define QCOM_RPM_PM8921_L3 79
+#define QCOM_RPM_PM8921_L4 80
+#define QCOM_RPM_PM8921_L5 81
+#define QCOM_RPM_PM8921_L6 82
+#define QCOM_RPM_PM8921_L7 83
+#define QCOM_RPM_PM8921_L8 84
+#define QCOM_RPM_PM8921_L9 85
+#define QCOM_RPM_PM8921_L10 86
+#define QCOM_RPM_PM8921_L11 87
+#define QCOM_RPM_PM8921_L12 88
+#define QCOM_RPM_PM8921_L13 89
+#define QCOM_RPM_PM8921_L14 90
+#define QCOM_RPM_PM8921_L15 91
+#define QCOM_RPM_PM8921_L16 92
+#define QCOM_RPM_PM8921_L17 93
+#define QCOM_RPM_PM8921_L18 94
+#define QCOM_RPM_PM8921_L19 95
+#define QCOM_RPM_PM8921_L20 96
+#define QCOM_RPM_PM8921_L21 97
+#define QCOM_RPM_PM8921_L22 98
+#define QCOM_RPM_PM8921_L23 99
+#define QCOM_RPM_PM8921_L24 100
+#define QCOM_RPM_PM8921_L25 101
+#define QCOM_RPM_PM8921_L26 102
+#define QCOM_RPM_PM8921_L27 103
+#define QCOM_RPM_PM8921_L28 104
+#define QCOM_RPM_PM8921_L29 105
+#define QCOM_RPM_PM8921_LVS1 106
+#define QCOM_RPM_PM8921_LVS2 107
+#define QCOM_RPM_PM8921_LVS3 108
+#define QCOM_RPM_PM8921_LVS4 109
+#define QCOM_RPM_PM8921_LVS5 110
+#define QCOM_RPM_PM8921_LVS6 111
+#define QCOM_RPM_PM8921_LVS7 112
+#define QCOM_RPM_PM8921_MVS 113
+#define QCOM_RPM_PM8921_NCP 114
+#define QCOM_RPM_PM8921_S1 115
+#define QCOM_RPM_PM8921_S2 116
+#define QCOM_RPM_PM8921_S3 117
+#define QCOM_RPM_PM8921_S4 118
+#define QCOM_RPM_PM8921_S5 119
+#define QCOM_RPM_PM8921_S6 120
+#define QCOM_RPM_PM8921_S7 121
+#define QCOM_RPM_PM8921_S8 122
+#define QCOM_RPM_PXO_CLK 123
+#define QCOM_RPM_QDSS_CLK 124
+#define QCOM_RPM_SFPB_CLK 125
+#define QCOM_RPM_SMI_CLK 126
+#define QCOM_RPM_SYS_FABRIC_ARB 127
+#define QCOM_RPM_SYS_FABRIC_CLK 128
+#define QCOM_RPM_SYS_FABRIC_HALT 129
+#define QCOM_RPM_SYS_FABRIC_IOCTL 130
+#define QCOM_RPM_SYS_FABRIC_MODE 131
+#define QCOM_RPM_USB_OTG_SWITCH 132
+#define QCOM_RPM_VDDMIN_GPIO 133
+
+#endif
--
1.8.2.2

2014-07-04 06:16:49

by Pramod Gurav

[permalink] [raw]
Subject: Re: [PATCH v3 2/3] soc: qcom-rpm: Driver for the Qualcomm RPM

Hi Bjorn,

On Tue, Jun 17, 2014 at 12:16 AM, Bjorn Andersson
<[email protected]> wrote:
> Driver for the Resource Power Manager (RPM) found in Qualcomm 8660, 8960
> and 8064 based devices. The driver exposes resources that child drivers
> can operate on; to implementing regulator, clock and bus frequency
> drivers.
>
> Signed-off-by: Bjorn Andersson <[email protected]>
> ---
> drivers/soc/qcom/Kconfig | 14 ++
> drivers/soc/qcom/Makefile | 1 +
> drivers/soc/qcom/qcom_rpm.c | 573 +++++++++++++++++++++++++++++++++++++++++++
> include/linux/soc/qcom_rpm.h | 12 +
> 4 files changed, 600 insertions(+)
> create mode 100644 drivers/soc/qcom/qcom_rpm.c
> create mode 100644 include/linux/soc/qcom_rpm.h
>
> diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
> index 7bd2c94..a8c2a96 100644
> --- a/drivers/soc/qcom/Kconfig
> +++ b/drivers/soc/qcom/Kconfig
> @@ -9,3 +9,17 @@ config QCOM_GSBI
> functions for connecting the underlying serial UART, SPI, and I2C
> devices to the output pins.
>
> +config QCOM_RPM
> + tristate "Qualcomm Resource Power Manager (RPM)"
> + depends on ARCH_QCOM && OF
> + help
> + If you say yes to this option, support will be included for the
> + Resource Power Manager system found in the Qualcomm 8660, 8960 and
> + 8064 based devices.
> +
> + This is required to access many regulators, clocks and bus
> + frequencies controlled by the RPM on these devices.
> +
> + Say M here if you want to include support for the Qualcomm RPM as a
> + module. This will build a module called "qcom_rpm".
> +
Adds extra line EOF here.

> diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
> index 4389012..e7706e8 100644
> --- a/drivers/soc/qcom/Makefile


br,
Pramod