Skip to contentSkip to conversation

Add support for the System Power Management Interface (SPMI)

PATCH Superseded Josh Cartwright 9 participants 41 messages Oct 28, 2013 – Oct 30, 2013

Subsystems (8)

v3 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

v3 cover Add support for the System Power Management Interface (SPMI)

The System Power Management Interface (SPMI) is a high-speed, low-latency, bi-directional, two-wire serial bus suitable for real-time control of voltage and frequency scaled multi-core application processors and its power management of auxiliary components. SPMI obsoletes a number of legacy, custom point-to-point interfaces and provides a low pin count, high-speed control bus for up to 4 Master and 16 Slave devices.

SPMI is specified by the MIPI (Mobile Industry Process Interface) Alliance [1].

This patchset is intended both to provide a core implementation of SPMI and also to provide a more-or-less complete example of it's use.
- Patch 1 provides a stubbed implementation of for_each_available_child_of_node() to allow SPMI to build with !CONFIG_OF
- Patches 2-3 implement the SPMI core functionality.
- Patches 4-6 provide an implementation of an SPMI controller, the Qualcomm "PMIC Arbiter", currently used on the 8x74 series SoCs.
- Patch 7 provides an implementation of regmap for SPMI
- Patches 8-9 is an implementation of a client driver for the PM8x41 PMICs paired with the 800 series SoCs.
- Patch 10 reworks the existing pm8xxx-rtc driver to work with the PM8x41 PMIC.

Changes from v2[2]:
- Dropped RFC.
- Add basic regmap support at Mark Brown's suggestion
- Drop debugfs interface. Debugging SPMI accesses can happen via the regmap debugfs interface if necessary.
- Add second address-cell in SPMI generic device tree binding, encoding the address type (suggestion by Stephen Warren)
- Implement interrupt handling functionality within the PMIC Arbiter driver
- Provide basic MFD driver for the PMIC8x41 PMICs, demonstrating SPMI regmap client use
- Adapt existing pm8xxx-rtc driver to work as a child of the PM8x41 mfd device

Changes from v1[3]:
- Adopted patch (1/5) to #define for_each_available_node() shim in the !CONFIG_OF case
- Moved device tree logic out of drivers/of and into spmi.c core (this mirrors what SPI is doing, and what i2c will soon be doing)
- Move of_spmi_add_devices() call into spmi_device_add(), so drivers don't have to call it explicitly
- Unconditionally build in debugfs code (rely on the underlying CONFIG_DEBUG_FS switch to throw unused code away)
- Change pr_* print functions to their dev_* equivalents
- Fix copy_{to,from}_user error handling
- Renamed "board_lock" to "ctrl_idr_lock" to better describe it's purpose
- Rework device object lifetime management
- Rename PMIC arb binding document, add description of PMIC arb
- Add generic SPMI device tree bindings

[1]: http://www.mipi.org/specifications/system-power-management-interface
[2]: http://marc.info/?l=linux-arm-kernel&m=137721241427533&w=2
[3]: http://thread.gmane.org/gmane.linux.ports.arm.msm/4886

Josh Cartwright (7):
spmi: add generic SPMI controller binding documentation
spmi: pmic_arb: add support for interrupt handling
spmi: document the PMIC arbiter SPMI bindings
regmap: add SPMI support
mfd: pm8x41: add support for Qualcomm 8x41 PMICs
mfd: pm8x41: document device tree bindings
rtc: pm8xxx: add support for pm8941

Kenneth Heitke (2):
spmi: Linux driver framework for SPMI
spmi: Add MSM PMIC Arbiter SPMI controller

Sylwester Nawrocki (1):
of: Add empty for_each_available_child_of_node() macro definition

 Documentation/devicetree/bindings/mfd/pm8x41.txt   |  33 +
 .../bindings/spmi/qcom,spmi-pmic-arb.txt           |  42 ++
 Documentation/devicetree/bindings/spmi/spmi.txt    |  41 ++
 drivers/Kconfig                                    |   2 +
 drivers/Makefile                                   |   1 +
 drivers/base/regmap/Kconfig                        |   5 +-
 drivers/base/regmap/Makefile                       |   1 +
 drivers/base/regmap/regmap-spmi.c                  |  90 +++
 drivers/mfd/Kconfig                                |  10 +
 drivers/mfd/Makefile                               |   1 +
 drivers/mfd/pm8x41.c                               |  64 ++
 drivers/rtc/Kconfig                                |   1 -
 drivers/rtc/rtc-pm8xxx.c                           | 229 ++++---
 drivers/spmi/Kconfig                               |  24 +
 drivers/spmi/Makefile                              |   6 +
 drivers/spmi/spmi-pmic-arb.c                       | 758 +++++++++++++++++++++
 drivers/spmi/spmi.c                                | 491 +++++++++++++
 include/dt-bindings/spmi/spmi.h                    |  18 +
 include/linux/mod_devicetable.h                    |   8 +
 include/linux/of.h                                 |   3 +
 include/linux/regmap.h                             |   5 +
 include/linux/spmi.h                               | 342 ++++++++++
 22 files changed, 2087 insertions(+), 88 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mfd/pm8x41.txt
 create mode 100644 Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt
 create mode 100644 Documentation/devicetree/bindings/spmi/spmi.txt
 create mode 100644 drivers/base/regmap/regmap-spmi.c
 create mode 100644 drivers/mfd/pm8x41.c
 create mode 100644 drivers/spmi/Kconfig
 create mode 100644 drivers/spmi/Makefile
 create mode 100644 drivers/spmi/spmi-pmic-arb.c
 create mode 100644 drivers/spmi/spmi.c
 create mode 100644 include/dt-bindings/spmi/spmi.h
 create mode 100644 include/linux/spmi.h
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#1 lore raw

PATCH v3 1/10 of: Add empty for_each_available_child_of_node() macro definition

From: Sylwester Nawrocki <[email protected]>

Add this empty macro definition so users can be compiled without excluding this macro call with preprocessor directives when CONFIG_OF is disabled.

---
 include/linux/of.h | 3 +++
 1 file changed, 3 insertions(+)
include/linux/of.h +3 -0
index f95aee3..908584e 100644
@@ -364,6 +364,9 @@ static inline bool of_have_populated_dt(void)
 #define for_each_child_of_node(parent, child) \
 	while (0)
 
+#define for_each_available_child_of_node(parent, child) \
+	while (0)
+
 static inline struct device_node *of_get_child_by_name(
 					const struct device_node *node,
 					const char *name)
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#2 lore raw

Re: [PATCH v3 01/10] of: Add empty for_each_available_child_of_node() macro definition

Quoted 8 lines · Josh Cartwright

From: Sylwester Nawrocki <[email protected]>

Add this empty macro definition so users can be compiled without excluding this macro call with preprocessor directives when CONFIG_OF is disabled.

I'm assuming the rest of this is not going to make 3.13, so I've applied this for 3.13.

Rob

#3 lore raw

PATCH v3 2/10 spmi: Linux driver framework for SPMI

In reply to Josh Cartwright

From: Kenneth Heitke <[email protected]>

System Power Management Interface (SPMI) is a specification developed by the MIPI (Mobile Industry Process Interface) Alliance optimized for the real time control of Power Management ICs (PMIC).

SPMI is a two-wire serial interface that supports up to 4 master devices and up to 16 logical slaves.

The framework supports message APIs, multiple busses (1 controller per bus) and multiple clients/slave devices per controller.

---
 drivers/Kconfig                 |   2 +
 drivers/Makefile                |   1 +
 drivers/spmi/Kconfig            |   9 +
 drivers/spmi/Makefile           |   4 +
 drivers/spmi/spmi.c             | 491 ++++++++++++++++++++++++++++++++++++++++
 include/dt-bindings/spmi/spmi.h |  18 ++
 include/linux/mod_devicetable.h |   8 +
 include/linux/spmi.h            | 342 ++++++++++++++++++++++++++++
 8 files changed, 875 insertions(+)
 create mode 100644 drivers/spmi/Kconfig
 create mode 100644 drivers/spmi/Makefile
 create mode 100644 drivers/spmi/spmi.c
 create mode 100644 include/dt-bindings/spmi/spmi.h
 create mode 100644 include/linux/spmi.h
drivers/Kconfig +2 -0
index aa43b91..2b35420 100644
@@ -52,6 +52,8 @@ source "drivers/i2c/Kconfig"
 
 source "drivers/spi/Kconfig"
 
+source "drivers/spmi/Kconfig"
+
 source "drivers/hsi/Kconfig"
 
 source "drivers/pps/Kconfig"
drivers/Makefile +1 -0
index ab93de8..5c250df 100644
@@ -64,6 +64,7 @@ obj-$(CONFIG_ATA)		+= ata/
 obj-$(CONFIG_TARGET_CORE)	+= target/
 obj-$(CONFIG_MTD)		+= mtd/
 obj-$(CONFIG_SPI)		+= spi/
+obj-$(CONFIG_SPMI)		+= spmi/
 obj-y				+= hsi/
 obj-y				+= net/
 obj-$(CONFIG_ATM)		+= atm/
drivers/spmi/Kconfig new file +9 -0
new file mode 100644
index 0000000..a03835f
@@ -0,0 +1,9 @@
+#
+# SPMI driver configuration
+#
+menuconfig SPMI
+	bool "SPMI support"
+	help
+	  SPMI (System Power Management Interface) is a two-wire
+	  serial interface between baseband and application processors
+	  and Power Management Integrated Circuits (PMIC).
drivers/spmi/Makefile new file +4 -0
new file mode 100644
index 0000000..1de1acd
@@ -0,0 +1,4 @@
+#
+# Makefile for kernel SPMI framework.
+#
+obj-$(CONFIG_SPMI)	+= spmi.o
drivers/spmi/spmi.c new file +491 -0

491 lines not on this page · raw message

include/dt-bindings/spmi/spmi.h new file +18 -0
new file mode 100644
index 0000000..d11e1e5
@@ -0,0 +1,18 @@
+/* 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.
+ */
+#ifndef __DT_BINDINGS_SPMI_H
+#define __DT_BINDINGS_SPMI_H
+
+#define SPMI_USID	0
+#define SPMI_GSID	1
+
+#endif
include/linux/mod_devicetable.h +8 -0
index 45e9214..677e474 100644
@@ -432,6 +432,14 @@ struct spi_device_id {
 	kernel_ulong_t driver_data;	/* Data private to the driver */
 };
 
+#define SPMI_NAME_SIZE	32
+#define SPMI_MODULE_PREFIX "spmi:"
+
+struct spmi_device_id {
+	char name[SPMI_NAME_SIZE];
+	kernel_ulong_t driver_data;	/* Data private to the driver */
+};
+
 /* dmi */
 enum dmi_field {
 	DMI_NONE,
include/linux/spmi.h new file +342 -0

342 lines not on this page · raw message

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#4 lore raw

Re: [PATCH v3 02/10] spmi: Linux driver framework for SPMI

Hi Josh,

Quoted 31 lines · Josh Cartwright

From: Kenneth Heitke <[email protected]>

System Power Management Interface (SPMI) is a specification developed by the MIPI (Mobile Industry Process Interface) Alliance optimized for the real time control of Power Management ICs (PMIC).

SPMI is a two-wire serial interface that supports up to 4 master devices and up to 16 logical slaves.

The framework supports message APIs, multiple busses (1 controller per bus) and multiple clients/slave devices per controller.

---
 drivers/Kconfig                 |   2 +
 drivers/Makefile                |   1 +
 drivers/spmi/Kconfig            |   9 +
 drivers/spmi/Makefile           |   4 +
 drivers/spmi/spmi.c             | 491 ++++++++++++++++++++++++++++++++++++++++
 include/dt-bindings/spmi/spmi.h |  18 ++
 include/linux/mod_devicetable.h |   8 +
 include/linux/spmi.h            | 342 ++++++++++++++++++++++++++++
 8 files changed, 875 insertions(+)
 create mode 100644 drivers/spmi/Kconfig
 create mode 100644 drivers/spmi/Makefile
 create mode 100644 drivers/spmi/spmi.c
 create mode 100644 include/dt-bindings/spmi/spmi.h
 create mode 100644 include/linux/spmi.h

<snip>

drivers/spmi/spmi.c line 55

Quoted 4 lines
drivers/spmi/spmi.c new file +4 -0
+#ifdef CONFIG_PM_SLEEP
+static int spmi_pm_suspend(struct device *dev)
+{
+	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;

This is what pm_generic_suspend() do. Do we really need this wrapper?

Quoted 31 lines
drivers/spmi/spmi.c new file +31 -0
+
+	if (pm)
+		return pm_generic_suspend(dev);
+	else
+		return 0;
+}
+
+static int spmi_pm_resume(struct device *dev)
+{
+	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+	if (pm)
+		return pm_generic_resume(dev);
+	else
+		return 0;
+}
+#else
+#define spmi_pm_suspend		NULL
+#define spmi_pm_resume		NULL
+#endif
+
+static const struct dev_pm_ops spmi_pm_ops = {
+	.suspend	= spmi_pm_suspend,
+	.resume		= spmi_pm_resume,
+	SET_RUNTIME_PM_OPS(
+		pm_generic_suspend,
+		pm_generic_resume,
+		pm_generic_runtime_idle
+	)
+};
+

<snip>

Quoted 18 lines
drivers/spmi/spmi.c new file +18 -0
+
+static int spmi_drv_probe(struct device *dev)
+{
+	const struct spmi_driver *sdrv = to_spmi_driver(dev->driver);
+	int err = 0;
+
+	if (sdrv->probe)
+		err = sdrv->probe(to_spmi_device(dev));
+
+	return err;
+}
+
+static int spmi_drv_remove(struct device *dev)
+{
+	const struct spmi_driver *sdrv = to_spmi_driver(dev->driver);
+	int err = 0;
+
+	if (sdrv->remove)

drivers/spmi/spmi.c line 287

Quoted 10 lines
drivers/spmi/spmi.c new file +10 -0
+		err = sdrv->remove(to_spmi_device(dev));
+
+	return err;
+}
+
+static void spmi_drv_shutdown(struct device *dev)
+{
+	const struct spmi_driver *sdrv = to_spmi_driver(dev->driver);
+
+	if (sdrv->shutdown)

If driver for device is not loaded this will cause kernel NULL pointer dereference.

Quoted 12 lines
drivers/spmi/spmi.c new file +12 -0
+		sdrv->shutdown(to_spmi_device(dev));
+}
+
+static struct bus_type spmi_bus_type = {
+	.name		= "spmi",
+	.match		= spmi_device_match,
+	.pm		= &spmi_pm_ops,
+	.probe		= spmi_drv_probe,
+	.remove		= spmi_drv_remove,
+	.shutdown	= spmi_drv_shutdown,
+};
+

<snip>

Quoted 15 lines
drivers/spmi/spmi.c new file +15 -0
+
+static int of_spmi_register_devices(struct spmi_controller *ctrl)
+{
+	struct device_node *node;
+	int err;
+
+	dev_dbg(&ctrl->dev, "of_spmi_register_devices\n");
+
+	if (!ctrl->dev.of_node)
+		return -ENODEV;
+
+	dev_dbg(&ctrl->dev, "looping through children\n");
+
+	for_each_available_child_of_node(ctrl->dev.of_node, node) {
+		struct spmi_device *sdev;

drivers/spmi/spmi.c line 381

Quoted 10 lines
drivers/spmi/spmi.c new file +10 -0
+		u32 reg[2];
+
+		dev_dbg(&ctrl->dev, "adding child %s\n", node->full_name);
+
+		err = of_property_read_u32_array(node, "reg", reg, 2);
+		if (err) {
+			dev_err(&ctrl->dev,
+				"node %s does not have 'reg' property\n",
+				node->full_name);
+			continue;

Shouldn't this be a fatal error?

Quoted 41 lines
drivers/spmi/spmi.c new file +41 -0
+		}
+
+		if (reg[1] != SPMI_USID) {
+			dev_err(&ctrl->dev,
+				"node %s contains unsupported 'reg' entry\n",
+				node->full_name);
+			continue;
+		}
+
+		if (reg[0] > 0xF) {
+			dev_err(&ctrl->dev,
+				"invalid usid on node %s\n",
+				node->full_name);
+			continue;
+		}
+
+		dev_dbg(&ctrl->dev, "read usid %02x\n", reg[0]);
+
+		sdev = spmi_device_alloc(ctrl);
+		if (!sdev)
+			continue;
+
+		sdev->dev.of_node = node;
+		sdev->usid = (u8) reg[0];
+
+		err = spmi_device_add(sdev);
+		if (err) {
+			dev_err(&sdev->dev,
+				"failure adding device. status %d\n", err);
+			spmi_device_put(sdev);
+			continue;
+		}
+	}
+
+	return 0;
+}
+
+int spmi_controller_add(struct spmi_controller *ctrl)
+{
+	int ret;
+

drivers/spmi/spmi.c line 432

Quoted 10 lines
drivers/spmi/spmi.c new file +10 -0
+	/* Can't register until after driver model init */
+	if (WARN_ON(!spmi_bus_type.p))
+		return -EAGAIN;
+
+	ret = device_add(&ctrl->dev);
+	if (ret)
+		return ret;
+
+	if (IS_ENABLED(CONFIG_OF))
+		of_spmi_register_devices(ctrl);

Check for error code here?

drivers/spmi/spmi.c line 440

Quoted 8 lines
drivers/spmi/spmi.c new file +8 -0
+
+	dev_dbg(&ctrl->dev, "spmi-%d registered: dev:%p\n",
+		ctrl->nr, &ctrl->dev);
+
+	return 0;
+};
+EXPORT_SYMBOL_GPL(spmi_controller_add);
+

Regards,
Ivan

#5 lore raw

Re: [PATCH v3 02/10] spmi: Linux driver framework for SPMI

Quoted 16 lines · Ivan T. Ivanov
Quoted 15 lines · Josh Cartwright

From: Kenneth Heitke <[email protected]>

System Power Management Interface (SPMI) is a specification developed by the MIPI (Mobile Industry Process Interface) Alliance optimized for the real time control of Power Management ICs (PMIC).

SPMI is a two-wire serial interface that supports up to 4 master devices and up to 16 logical slaves.

The framework supports message APIs, multiple busses (1 controller per bus) and multiple clients/slave devices per controller.

[..]

Quoted 22 lines
Quoted 22 lines
drivers/spmi/spmi.c new file +22 -0
+static int spmi_drv_probe(struct device *dev)
+{
+	const struct spmi_driver *sdrv = to_spmi_driver(dev->driver);
+	int err = 0;
+
+	if (sdrv->probe)
+		err = sdrv->probe(to_spmi_device(dev));
+
+	return err;
+}
+
+static int spmi_drv_remove(struct device *dev)
+{
+	const struct spmi_driver *sdrv = to_spmi_driver(dev->driver);
+	int err = 0;
+
+	if (sdrv->remove)
+		err = sdrv->remove(to_spmi_device(dev));
+
+	return err;
+}
+
Quoted 8 lines

drivers/spmi/spmi.c line 287

Quoted 5 lines
drivers/spmi/spmi.c new file +5 -0
+static void spmi_drv_shutdown(struct device *dev)
+{
+	const struct spmi_driver *sdrv = to_spmi_driver(dev->driver);
+
+	if (sdrv->shutdown)

If driver for device is not loaded this will cause kernel NULL pointer dereference.

Indeed. I'll fix this.

Quoted 18 lines
Quoted 18 lines
drivers/spmi/spmi.c new file +18 -0
+static int of_spmi_register_devices(struct spmi_controller *ctrl)
+{
+	struct device_node *node;
+	int err;
+
+	dev_dbg(&ctrl->dev, "of_spmi_register_devices\n");
+
+	if (!ctrl->dev.of_node)
+		return -ENODEV;
+
+	dev_dbg(&ctrl->dev, "looping through children\n");
+
+	for_each_available_child_of_node(ctrl->dev.of_node, node) {
+		struct spmi_device *sdev;
+		u32 reg[2];
+
+		dev_dbg(&ctrl->dev, "adding child %s\n", node->full_name);
+
Quoted 8 lines

drivers/spmi/spmi.c line 381

Quoted 6 lines
drivers/spmi/spmi.c new file +6 -0
+		err = of_property_read_u32_array(node, "reg", reg, 2);
+		if (err) {
+			dev_err(&ctrl->dev,
+				"node %s does not have 'reg' property\n",
+				node->full_name);
+			continue;

Shouldn't this be a fatal error?

Fatal in what way? It is fatal in the sense that this particular child node is skipped, but other children can still be enumerated. Are you suggesting that we bail completely when we hit a wrongly-described child?

Quoted 45 lines
Quoted 45 lines
drivers/spmi/spmi.c new file +45 -0
+		}
+
+		if (reg[1] != SPMI_USID) {
+			dev_err(&ctrl->dev,
+				"node %s contains unsupported 'reg' entry\n",
+				node->full_name);
+			continue;
+		}
+
+		if (reg[0] > 0xF) {
+			dev_err(&ctrl->dev,
+				"invalid usid on node %s\n",
+				node->full_name);
+			continue;
+		}
+
+		dev_dbg(&ctrl->dev, "read usid %02x\n", reg[0]);
+
+		sdev = spmi_device_alloc(ctrl);
+		if (!sdev)
+			continue;
+
+		sdev->dev.of_node = node;
+		sdev->usid = (u8) reg[0];
+
+		err = spmi_device_add(sdev);
+		if (err) {
+			dev_err(&sdev->dev,
+				"failure adding device. status %d\n", err);
+			spmi_device_put(sdev);
+			continue;
+		}
+	}
+
+	return 0;
+}
+
+int spmi_controller_add(struct spmi_controller *ctrl)
+{
+	int ret;
+
+	/* Can't register until after driver model init */
+	if (WARN_ON(!spmi_bus_type.p))
+		return -EAGAIN;
+
Quoted 8 lines

drivers/spmi/spmi.c line 432

Quoted 6 lines
drivers/spmi/spmi.c new file +6 -0
+	ret = device_add(&ctrl->dev);
+	if (ret)
+		return ret;
+
+	if (IS_ENABLED(CONFIG_OF))
+		of_spmi_register_devices(ctrl);

Check for error code here?

And do what with it? Maybe instead, I should make of_spmi_register_devices() return void.

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#6 lore raw

Re: [PATCH v3 02/10] spmi: Linux driver framework for SPMI

Hi,

Quoted 78 lines · Josh Cartwright
Quoted 16 lines · Ivan T. Ivanov
Quoted 15 lines · Josh Cartwright

From: Kenneth Heitke <[email protected]>

System Power Management Interface (SPMI) is a specification developed by the MIPI (Mobile Industry Process Interface) Alliance optimized for the real time control of Power Management ICs (PMIC).

SPMI is a two-wire serial interface that supports up to 4 master devices and up to 16 logical slaves.

The framework supports message APIs, multiple busses (1 controller per bus) and multiple clients/slave devices per controller.

[..]

Quoted 22 lines
Quoted 22 lines
drivers/spmi/spmi.c new file +22 -0
+static int spmi_drv_probe(struct device *dev)
+{
+	const struct spmi_driver *sdrv = to_spmi_driver(dev->driver);
+	int err = 0;
+
+	if (sdrv->probe)
+		err = sdrv->probe(to_spmi_device(dev));
+
+	return err;
+}
+
+static int spmi_drv_remove(struct device *dev)
+{
+	const struct spmi_driver *sdrv = to_spmi_driver(dev->driver);
+	int err = 0;
+
+	if (sdrv->remove)
+		err = sdrv->remove(to_spmi_device(dev));
+
+	return err;
+}
+
Quoted 8 lines

drivers/spmi/spmi.c line 287

Quoted 5 lines
drivers/spmi/spmi.c new file +5 -0
+static void spmi_drv_shutdown(struct device *dev)
+{
+	const struct spmi_driver *sdrv = to_spmi_driver(dev->driver);
+
+	if (sdrv->shutdown)

If driver for device is not loaded this will cause kernel NULL pointer dereference.

Indeed. I'll fix this.

Quoted 18 lines
Quoted 18 lines
drivers/spmi/spmi.c new file +18 -0
+static int of_spmi_register_devices(struct spmi_controller *ctrl)
+{
+	struct device_node *node;
+	int err;
+
+	dev_dbg(&ctrl->dev, "of_spmi_register_devices\n");
+
+	if (!ctrl->dev.of_node)
+		return -ENODEV;
+
+	dev_dbg(&ctrl->dev, "looping through children\n");
+
+	for_each_available_child_of_node(ctrl->dev.of_node, node) {
+		struct spmi_device *sdev;
+		u32 reg[2];
+
+		dev_dbg(&ctrl->dev, "adding child %s\n", node->full_name);
+
Quoted 8 lines

drivers/spmi/spmi.c line 381

Quoted 6 lines
drivers/spmi/spmi.c new file +6 -0
+		err = of_property_read_u32_array(node, "reg", reg, 2);
+		if (err) {
+			dev_err(&ctrl->dev,
+				"node %s does not have 'reg' property\n",
+				node->full_name);
+			continue;

Shouldn't this be a fatal error?

Quoted 2 lines

Fatal in what way? It is fatal in the sense that this particular child node is skipped, but other children can still be enumerated.

Oh, I have missed this.

Quoted 3 lines

Are you
suggesting that we bail completely when we hit a wrongly-described child?

Please ignore my comment.

Quoted 24 lines
Quoted 24 lines
Quoted 24 lines
drivers/spmi/spmi.c new file +23 -0
+		}
+
+		if (reg[1] != SPMI_USID) {
+			dev_err(&ctrl->dev,
+				"node %s contains unsupported 'reg' entry\n",
+				node->full_name);
+			continue;
+		}
+
+		if (reg[0] > 0xF) {
+			dev_err(&ctrl->dev,
+				"invalid usid on node %s\n",
+				node->full_name);
+			continue;
+		}
+
+		dev_dbg(&ctrl->dev, "read usid %02x\n", reg[0]);
+
+		sdev = spmi_device_alloc(ctrl);
+		if (!sdev)
+			continue;
+
+		sdev->dev.of_node = node;
Quoted 8 lines
Quoted 8 lines

drivers/spmi/spmi.c line 412

Quoted 8 lines
drivers/spmi/spmi.c new file +8 -0
+		sdev->usid = (u8) reg[0];
+
+		err = spmi_device_add(sdev);
+		if (err) {
+			dev_err(&sdev->dev,
+				"failure adding device. status %d\n", err);
+			spmi_device_put(sdev);
+			continue;

There is no need from this 'continue' here.

Quoted 23 lines
Quoted 14 lines
Quoted 14 lines
drivers/spmi/spmi.c new file +14 -0
+		}
+	}
+
+	return 0;
+}
+
+int spmi_controller_add(struct spmi_controller *ctrl)
+{
+	int ret;
+
+	/* Can't register until after driver model init */
+	if (WARN_ON(!spmi_bus_type.p))
+		return -EAGAIN;
+
Quoted 8 lines

drivers/spmi/spmi.c line 432

Quoted 6 lines
drivers/spmi/spmi.c new file +6 -0
+	ret = device_add(&ctrl->dev);
+	if (ret)
+		return ret;
+
+	if (IS_ENABLED(CONFIG_OF))
+		of_spmi_register_devices(ctrl);

Check for error code here?

Quoted 1 line

And do what with it?

This was related to my previous comment, which is not valid.

Quoted 2 lines

Maybe instead, I should make
of_spmi_register_devices() return void.

Sound reasonable to me and will be the same as i2c bus.

Regards,
Ivan

Quoted 1 line
#7 lore raw

Re: [PATCH v3 02/10] spmi: Linux driver framework for SPMI

In reply to Josh Cartwright

Couple of high-level comments on the in-kernel API.

drivers/spmi/spmi.c line 58

Quoted 7 lines · Josh Cartwright
drivers/spmi/spmi.c new file +7 -0
+#ifdef CONFIG_PM_SLEEP
+static int spmi_pm_suspend(struct device *dev)
+{
+	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+	if (pm)
+		return pm_generic_suspend(dev);

pm_generic_suspend() checks both dev->driver and dev->driver->pm and returns 0 if either of them is NULL, so there should be no need to wrap the function.

drivers/spmi/spmi.c line 68

Quoted 10 lines
drivers/spmi/spmi.c new file +10 -0
+	else
+		return 0;
+}
+
+static int spmi_pm_resume(struct device *dev)
+{
+	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+	if (pm)
+		return pm_generic_resume(dev);

Same here

Quoted 7 lines
drivers/spmi/spmi.c new file +7 -0
+	else
+		return 0;
+}
+#else
+#define spmi_pm_suspend		NULL
+#define spmi_pm_resume		NULL
+#endif

[...]

drivers/spmi/spmi.c line 456

Quoted 7 lines
drivers/spmi/spmi.c new file +7 -0
+/**
+ * spmi_controller_remove: Controller tear-down.
+ * @ctrl: controller to be removed.
+ *
+ * Controller added with the above API is torn down using this API.
+ */
+int spmi_controller_remove(struct spmi_controller *ctrl)

The return type should be void. The function can't fail and nobody is going to check the return value anyway.

drivers/spmi/spmi.c line 465

Quoted 9 lines
drivers/spmi/spmi.c new file +9 -0
+{
+	int dummy;
+
+	if (!ctrl)
+		return -EINVAL;
+
+	dummy = device_for_each_child(&ctrl->dev, NULL,
+				      spmi_ctrl_remove_device);
+	device_unregister(&ctrl->dev);

Should be device_del(). device_unregister() will do both device_del() and put_device(). But usually you'd want to do something in between like release resources used by the controller.

Quoted 4 lines
drivers/spmi/spmi.c new file +4 -0
+	return 0;
+}
+EXPORT_SYMBOL_GPL(spmi_controller_remove);
+

[...]

include/linux/spmi.h line 76

Quoted 10 lines
include/linux/spmi.h new file +10 -0
+/**
+ * spmi_controller_alloc: Allocate a new SPMI controller
+ * @ctrl: associated controller
+ *
+ * Caller is responsible for either calling spmi_device_add() to add the
+ * newly allocated controller, or calling spmi_device_put() to discard it.
+ */
+struct spmi_device *spmi_device_alloc(struct spmi_controller *ctrl);
+
+static inline void spmi_device_put(struct spmi_device *sdev)

For symmetry reasons it might make sense to call this spmi_device_free().

Quoted 4 lines
include/linux/spmi.h new file +4 -0
+{
+	if (sdev)
+		put_device(&sdev->dev);
+}

[...]

Quoted 1 line

+#define to_spmi_controller(d) container_of(d, struct spmi_controller, dev)

Should be a inline function for better type safety.

[...]

Quoted 1 line

+static inline void spmi_controller_put(struct spmi_controller *ctrl)

For symmetry reasons it might make sense to call this spmi_controller_free().

Quoted 5 lines
include/linux/spmi.h new file +5 -0
+{
+	if (ctrl)
+		put_device(&ctrl->dev);
+}
+

[....]

include/linux/spmi.h line 171

Quoted 4 lines
include/linux/spmi.h new file +4 -0
+struct spmi_driver {
+	struct device_driver driver;
+	int	(*probe)(struct spmi_device *sdev);
+	int	(*remove)(struct spmi_device *sdev);

The type of the remove function should be found. The Linux device model doesn't really allow for device removal to fail.

include/linux/spmi.h line 174

Quoted 3 lines
include/linux/spmi.h new file +3 -0
+	void	(*shutdown)(struct spmi_device *sdev);
+	int	(*suspend)(struct spmi_device *sdev, pm_message_t pmesg);
+	int	(*resume)(struct spmi_device *sdev);

The framework seems to support dev_pm_ops just fine, there should be no need for legacy suspend/resume callbacks.

include/linux/spmi.h line 176

Quoted 2 lines
include/linux/spmi.h new file +2 -0
+};
+#define to_spmi_driver(d) container_of(d, struct spmi_driver, driver)

Inline function here as well
[...]

#8 lore raw

Re: [PATCH v3 02/10] spmi: Linux driver framework for SPMI

Hey Lars-

Thanks for the feedback. CC'ing Ivan, since he had the same feedback regarding the PM callbacks.

Quoted 14 lines · Lars-Peter Clausen

Couple of high-level comments on the in-kernel API.

drivers/spmi/spmi.c line 58

Quoted 7 lines · Josh Cartwright
drivers/spmi/spmi.c new file +7 -0
+#ifdef CONFIG_PM_SLEEP
+static int spmi_pm_suspend(struct device *dev)
+{
+	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+	if (pm)
+		return pm_generic_suspend(dev);

pm_generic_suspend() checks both dev->driver and dev->driver->pm and returns 0 if either of them is NULL, so there should be no need to wrap the function.

Quoted 12 lines

drivers/spmi/spmi.c line 68

Quoted 10 lines
drivers/spmi/spmi.c new file +10 -0
+	else
+		return 0;
+}
+
+static int spmi_pm_resume(struct device *dev)
+{
+	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+	if (pm)
+		return pm_generic_resume(dev);

Same here

Sounds good. I'll drop these.

Quoted 10 lines

drivers/spmi/spmi.c line 456

Quoted 7 lines
drivers/spmi/spmi.c new file +7 -0
+/**
+ * spmi_controller_remove: Controller tear-down.
+ * @ctrl: controller to be removed.
+ *
+ * Controller added with the above API is torn down using this API.
+ */
+int spmi_controller_remove(struct spmi_controller *ctrl)

The return type should be void. The function can't fail and nobody is going to check the return value anyway.

Alright.

Quoted 5 lines
Quoted 5 lines
drivers/spmi/spmi.c new file +5 -0
+{
+	int dummy;
+
+	if (!ctrl)
+		return -EINVAL;
Quoted 8 lines

drivers/spmi/spmi.c line 465

Quoted 4 lines
drivers/spmi/spmi.c new file +4 -0
+
+	dummy = device_for_each_child(&ctrl->dev, NULL,
+				      spmi_ctrl_remove_device);
+	device_unregister(&ctrl->dev);

Should be device_del(). device_unregister() will do both device_del() and put_device(). But usually you'd want to do something in between like release resources used by the controller.

I'm not sure I understand your suggestion here. If put_device() isn't called here, wouldn't we be leaking the controller? What resources would I want to be releasing here that aren't released as part of the controller's release() function?

Quoted 5 lines
Quoted 4 lines
drivers/spmi/spmi.c new file +4 -0
+	return 0;
+}
+EXPORT_SYMBOL_GPL(spmi_controller_remove);
+

[...]

Quoted 12 lines

include/linux/spmi.h line 76

Quoted 10 lines
include/linux/spmi.h new file +10 -0
+/**
+ * spmi_controller_alloc: Allocate a new SPMI controller
+ * @ctrl: associated controller
+ *
+ * Caller is responsible for either calling spmi_device_add() to add the
+ * newly allocated controller, or calling spmi_device_put() to discard it.
+ */
+struct spmi_device *spmi_device_alloc(struct spmi_controller *ctrl);
+
+static inline void spmi_device_put(struct spmi_device *sdev)

For symmetry reasons it might make sense to call this spmi_device_free().

Except that it doesn't necessarily free() the underlying device, so I find that more confusing.

Quoted 8 lines
Quoted 4 lines
include/linux/spmi.h new file +4 -0
+{
+	if (sdev)
+		put_device(&sdev->dev);
+}

[...]

Quoted 1 line

+#define to_spmi_controller(d) container_of(d, struct spmi_controller, dev)

Should be a inline function for better type safety.

Sounds good. Will change the to_spmi_*() macros.

Quoted 19 lines

[...]

Quoted 1 line

+static inline void spmi_controller_put(struct spmi_controller *ctrl)

For symmetry reasons it might make sense to call this spmi_controller_free().

Quoted 5 lines
include/linux/spmi.h new file +5 -0
+{
+	if (ctrl)
+		put_device(&ctrl->dev);
+}
+

[....]

include/linux/spmi.h line 171

Quoted 4 lines
include/linux/spmi.h new file +4 -0
+struct spmi_driver {
+	struct device_driver driver;
+	int	(*probe)(struct spmi_device *sdev);
+	int	(*remove)(struct spmi_device *sdev);

The type of the remove function should be found. The Linux device model doesn't really allow for device removal to fail.

Quoted 6 lines

include/linux/spmi.h line 174

Quoted 3 lines
include/linux/spmi.h new file +3 -0
+	void	(*shutdown)(struct spmi_device *sdev);
+	int	(*suspend)(struct spmi_device *sdev, pm_message_t pmesg);
+	int	(*resume)(struct spmi_device *sdev);

The framework seems to support dev_pm_ops just fine, there should be no need for legacy suspend/resume callbacks.

Yep. Will drop.

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#9 lore raw

Re: [PATCH v3 02/10] spmi: Linux driver framework for SPMI

Quoted 4 lines · Josh Cartwright
Quoted 3 lines
Quoted 2 lines

+#define to_spmi_controller(d) container_of(d, struct spmi_controller, dev)

Should be a inline function for better type safety.

Sounds good. Will change the to_spmi_*() macros.

I was under the impression that container_of() already does type checking. At least it will ensure that typeof(d) == typeof(dev) in the above example which is about as good as it can get.

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#10 lore raw

Re: [PATCH v3 02/10] spmi: Linux driver framework for SPMI

Quoted 9 lines · Stephen Boyd
Quoted 4 lines · Josh Cartwright
Quoted 3 lines
Quoted 2 lines

+#define to_spmi_controller(d) container_of(d, struct spmi_controller, dev)

Should be a inline function for better type safety.

Sounds good. Will change the to_spmi_*() macros.

I was under the impression that container_of() already does type checking. At least it will ensure that typeof(d) == typeof(dev) in the above example which is about as good as it can get.

Well you'll get a warning, but the quality of the warning message is much better when an inline function is used.

warning: initialization from incompatible pointer type

vs.

warning: Passing argument 1 of to_smpi_controller() from incompatible pointer type. Expected struct device * got struct driver *

- Lars

#11 lore raw

Re: [PATCH v3 02/10] spmi: Linux driver framework for SPMI

In reply to Josh Cartwright
Quoted 14 lines · Josh Cartwright
Quoted 5 lines
Quoted 5 lines
drivers/spmi/spmi.c new file +5 -0
+{
+	int dummy;
+
+	if (!ctrl)
+		return -EINVAL;
Quoted 8 lines

drivers/spmi/spmi.c line 465

Quoted 4 lines
drivers/spmi/spmi.c new file +4 -0
+
+	dummy = device_for_each_child(&ctrl->dev, NULL,
+				      spmi_ctrl_remove_device);
+	device_unregister(&ctrl->dev);

Should be device_del(). device_unregister() will do both device_del() and put_device(). But usually you'd want to do something in between like release resources used by the controller.

Quoted 5 lines

I'm not sure I understand your suggestion here. If put_device() isn't called here, wouldn't we be leaking the controller? What resources would I want to be releasing here that aren't released as part of the controller's release() function?

Resources used by the driver implementing the controller. Usually the driver state struct will be allocated by spmi_controller_alloc() as well. So if you store resources in that struct, e.g. a clk you first want to unregister the spmi controller to make sure that the resources are no longer accessed, then free the resources and finally drop the reference to the controller so the memory can be freed. E.g.

static int foobar_remove(struct platform_device *pdev)

{
	struct spmi_controller *ctrl = platform_get_drvdata(pdev);
	struct foobar *foobar = spmi_controller_get_drvdata(ctrl);

	spmi_controller_remove(ctrl);

	free_irq(foobar->irq)
	clk_put(foobar->clk);
	...

	spmi_controller_put(ctrl);

	return 0;
}
Quoted 18 lines
Quoted 5 lines
Quoted 4 lines
drivers/spmi/spmi.c new file +4 -0
+	return 0;
+}
+EXPORT_SYMBOL_GPL(spmi_controller_remove);
+

[...]

Quoted 12 lines

include/linux/spmi.h line 76

Quoted 10 lines
include/linux/spmi.h new file +10 -0
+/**
+ * spmi_controller_alloc: Allocate a new SPMI controller
+ * @ctrl: associated controller
+ *
+ * Caller is responsible for either calling spmi_device_add() to add the
+ * newly allocated controller, or calling spmi_device_put() to discard it.
+ */
+struct spmi_device *spmi_device_alloc(struct spmi_controller *ctrl);
+
+static inline void spmi_device_put(struct spmi_device *sdev)

For symmetry reasons it might make sense to call this spmi_device_free().

Quoted 2 lines

Except that it doesn't necessarily free() the underlying device, so I find that more confusing.

Well, for all the driver cares the device has been freed.

#12 lore raw

Re: [PATCH v3 02/10] spmi: Linux driver framework for SPMI

In reply to Josh Cartwright

drivers/spmi/Kconfig line 5

Quoted 11 lines · Josh Cartwright
drivers/spmi/Kconfig new file +5 -0
new file mode 100644
index 0000000..a03835f
@@ -0,0 +1,9 @@
+#
+# SPMI driver configuration
+#
+menuconfig SPMI
+	bool "SPMI support"

Can we do tristate?

Quoted 36 lines
drivers/spmi/Kconfig new file +4 -0
+	help
+	  SPMI (System Power Management Interface) is a two-wire
+	  serial interface between baseband and application processors
+	  and Power Management Integrated Circuits (PMIC).
drivers/spmi/spmi.c new file +26 -0
new file mode 100644
index 0000000..0780bd4
@@ -0,0 +1,491 @@
+/* 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/kernel.h>
+#include <linux/errno.h>
+#include <linux/idr.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/spmi.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+
+#include <dt-bindings/spmi/spmi.h>
+
+static DEFINE_MUTEX(ctrl_idr_lock);

drivers/spmi/spmi.c line 36

Quoted 10 lines
drivers/spmi/spmi.c new file +10 -0
+static DEFINE_IDR(ctrl_idr);
+
+static void spmi_dev_release(struct device *dev)
+{
+	struct spmi_device *sdev = to_spmi_device(dev);
+	kfree(sdev);
+}
+
+static struct device_type spmi_dev_type = {
+	.release	= spmi_dev_release,

const?

drivers/spmi/spmi.c line 48

Quoted 12 lines
drivers/spmi/spmi.c new file +12 -0
+};
+
+static void spmi_ctrl_release(struct device *dev)
+{
+	struct spmi_controller *ctrl = to_spmi_controller(dev);
+	mutex_lock(&ctrl_idr_lock);
+	idr_remove(&ctrl_idr, ctrl->nr);
+	mutex_unlock(&ctrl_idr_lock);
+	kfree(ctrl);
+}
+
+static struct device_type spmi_ctrl_type = {

const?

Quoted 3 lines
drivers/spmi/spmi.c new file +3 -0
+	.release	= spmi_ctrl_release,
+};
+

[...]

drivers/spmi/spmi.c line 163

Quoted 11 lines
drivers/spmi/spmi.c new file +11 -0
+
+/*
+ * register read/write: 5-bit address, 1 byte of data
+ * extended register read/write: 8-bit address, up to 16 bytes of data
+ * extended register read/write long: 16-bit address, up to 8 bytes of data
+ */
+
+int spmi_register_read(struct spmi_device *sdev, u8 addr, u8 *buf)
+{
+	/* 5-bit register address */
+	if (addr > 0x1F)

Perhaps 0x1f should be a #define.

Quoted 7 lines
drivers/spmi/spmi.c new file +7 -0
+		return -EINVAL;
+
+	return spmi_read_cmd(sdev->ctrl, SPMI_CMD_READ, sdev->usid, addr, 0,
+			     buf);
+}
+EXPORT_SYMBOL_GPL(spmi_register_read);
+

[...]

Quoted 15 lines
drivers/spmi/spmi.c new file +15 -0
+struct spmi_controller *spmi_controller_alloc(struct device *parent,
+					      size_t size)
+{
+	struct spmi_controller *ctrl;
+	int id;
+
+	if (WARN_ON(!parent))
+		return NULL;
+
+	ctrl = kzalloc(sizeof(*ctrl) + size, GFP_KERNEL);
+	if (!ctrl)
+		return NULL;
+
+	device_initialize(&ctrl->dev);
+	ctrl->dev.type = &spmi_ctrl_type;

drivers/spmi/spmi.c line 341

Quoted 10 lines
drivers/spmi/spmi.c new file +10 -0
+	ctrl->dev.bus = &spmi_bus_type;
+	ctrl->dev.parent = parent;
+	ctrl->dev.of_node = parent->of_node;
+	spmi_controller_set_drvdata(ctrl, &ctrl[1]);
+
+	idr_preload(GFP_KERNEL);
+	mutex_lock(&ctrl_idr_lock);
+	id = idr_alloc(&ctrl_idr, ctrl, 0, 0, GFP_NOWAIT);
+	mutex_unlock(&ctrl_idr_lock);
+	idr_preload_end();

This can just be:

    mutex_lock(&ctrl_idr_lock);
    id = idr_alloc(&ctrl_idr, ctrl, 0, 0, GFP_KERNEL);
    mutex_unlock(&ctrl_idr_lock);
Quoted 12 lines
drivers/spmi/spmi.c new file +12 -0
+
+	if (id < 0) {
+		dev_err(parent,
+			"unable to allocate SPMI controller identifier.\n");
+		spmi_controller_put(ctrl);
+		return NULL;
+	}
+
+	ctrl->nr = id;
+	dev_set_name(&ctrl->dev, "spmi-%d", id);
+
+	dev_dbg(&ctrl->dev, "allocated controller 0x%p id %d\n", ctrl, id);

drivers/spmi/spmi.c line 363

Quoted 10 lines
drivers/spmi/spmi.c new file +10 -0
+	return ctrl;
+}
+EXPORT_SYMBOL_GPL(spmi_controller_alloc);
+
+static int of_spmi_register_devices(struct spmi_controller *ctrl)
+{
+	struct device_node *node;
+	int err;
+
+	dev_dbg(&ctrl->dev, "of_spmi_register_devices\n");

Could be

    dev_dbg(&ctrl->dev, "%s", __func__);

so that function renaming is transparent.

Quoted 18 lines
drivers/spmi/spmi.c new file +18 -0
+
+	if (!ctrl->dev.of_node)
+		return -ENODEV;
+
+	dev_dbg(&ctrl->dev, "looping through children\n");
+
+	for_each_available_child_of_node(ctrl->dev.of_node, node) {
+		struct spmi_device *sdev;
+		u32 reg[2];
+
+		dev_dbg(&ctrl->dev, "adding child %s\n", node->full_name);
+
+		err = of_property_read_u32_array(node, "reg", reg, 2);
+		if (err) {
+			dev_err(&ctrl->dev,
+				"node %s does not have 'reg' property\n",
+				node->full_name);
+				continue;

drivers/spmi/spmi.c line 391

Quoted 10 lines
drivers/spmi/spmi.c new file +10 -0
+		}
+
+		if (reg[1] != SPMI_USID) {
+			dev_err(&ctrl->dev,
+				"node %s contains unsupported 'reg' entry\n",
+				node->full_name);
+			continue;
+		}
+
+		if (reg[0] > 0xF) {

Perhaps call this MAX_USID?

Quoted 6 lines
drivers/spmi/spmi.c new file +6 -0
+			dev_err(&ctrl->dev,
+				"invalid usid on node %s\n",
+				node->full_name);
+			continue;
+		}
+

[...]

Quoted 38 lines
include/linux/spmi.h new file +32 -0
new file mode 100644
index 0000000..29cf0c9
@@ -0,0 +1,342 @@
+/* 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.
+ */
+#ifndef _LINUX_SPMI_H
+#define _LINUX_SPMI_H
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+
+/* Maximum slave identifier */
+#define SPMI_MAX_SLAVE_ID		16
+
+/* SPMI Commands */
+#define SPMI_CMD_EXT_WRITE		0x00
+#define SPMI_CMD_RESET			0x10
+#define SPMI_CMD_SLEEP			0x11
+#define SPMI_CMD_SHUTDOWN		0x12
+#define SPMI_CMD_WAKEUP			0x13
+#define SPMI_CMD_AUTHENTICATE		0x14
+#define SPMI_CMD_MSTR_READ		0x15
+#define SPMI_CMD_MSTR_WRITE		0x16
+#define SPMI_CMD_TRANSFER_BUS_OWNERSHIP	0x1A
+#define SPMI_CMD_DDB_MASTER_READ	0x1B

include/linux/spmi.h line 42

Quoted 10 lines
include/linux/spmi.h new file +10 -0
+#define SPMI_CMD_DDB_SLAVE_READ		0x1C
+#define SPMI_CMD_EXT_READ		0x20
+#define SPMI_CMD_EXT_WRITEL		0x30
+#define SPMI_CMD_EXT_READL		0x38
+#define SPMI_CMD_WRITE			0x40
+#define SPMI_CMD_READ			0x60
+#define SPMI_CMD_ZERO_WRITE		0x80
+
+/**
+ * Client/device handle (struct spmi_device):

This isn't kernel-doc format.

Quoted 16 lines
include/linux/spmi.h new file +16 -0
+ *  This is the client/device handle returned when a SPMI device
+ *  is registered with a controller.
+ *  Pointer to this structure is used by client-driver as a handle.
+ *  @dev: Driver model representation of the device.
+ *  @ctrl: SPMI controller managing the bus hosting this device.
+ *  @usid: Unique Slave IDentifier.
+ */
+struct spmi_device {
+	struct device		dev;
+	struct spmi_controller	*ctrl;
+	u8			usid;
+};
+#define to_spmi_device(d) container_of(d, struct spmi_device, dev)
+
+static inline void *spmi_device_get_drvdata(const struct spmi_device *sdev)
+{

include/linux/spmi.h line 68

Quoted 10 lines
include/linux/spmi.h new file +10 -0
+	return dev_get_drvdata(&sdev->dev);
+}
+
+static inline void spmi_device_set_drvdata(struct spmi_device *sdev, void *data)
+{
+	dev_set_drvdata(&sdev->dev, data);
+}
+
+/**
+ * spmi_controller_alloc: Allocate a new SPMI controller

There should be a dash here instead of colon.

Quoted 13 lines
include/linux/spmi.h new file +13 -0
+ * @ctrl: associated controller
+ *
+ * Caller is responsible for either calling spmi_device_add() to add the
+ * newly allocated controller, or calling spmi_device_put() to discard it.
+ */
+struct spmi_device *spmi_device_alloc(struct spmi_controller *ctrl);
+
+static inline void spmi_device_put(struct spmi_device *sdev)
+{
+	if (sdev)
+		put_device(&sdev->dev);
+}
+

[...]

Quoted 7 lines
include/linux/spmi.h new file +7 -0
+
+/**
+ * spmi_controller_alloc: Allocate a new SPMI controller
+ * @parent: parent device
+ * @size: size of private data
+ *
+ * Caller is responsible for either calling spmi_controller_add() to add the

include/linux/spmi.h line 140

Quoted 10 lines
include/linux/spmi.h new file +10 -0
+ * newly allocated controller, or calling spmi_controller_put() to discard it.
+ */
+struct spmi_controller *spmi_controller_alloc(struct device *parent,
+					      size_t size);
+
+static inline void spmi_controller_put(struct spmi_controller *ctrl)
+{
+	if (ctrl)
+		put_device(&ctrl->dev);
+}

This function is missing documentation.

Quoted 9 lines
include/linux/spmi.h new file +9 -0
+
+/**
+ * spmi_controller_add: Controller bring-up.
+ * @ctrl: controller to be registered.
+ *
+ * Register a controller previously allocated via spmi_controller_alloc() with
+ * the SPMI core
+ */
+int spmi_controller_add(struct spmi_controller *ctrl);

[...]

Quoted 8 lines
include/linux/spmi.h new file +8 -0
+
+/**
+ * spmi_driver_unregister - reverse effect of spmi_driver_register
+ * @sdrv: the driver to unregister
+ * Context: can sleep
+ */
+static inline void spmi_driver_unregister(struct spmi_driver *sdrv)
+{

include/linux/spmi.h line 203

Quoted 10 lines
include/linux/spmi.h new file +10 -0
+	if (sdrv)
+		driver_unregister(&sdrv->driver);
+}
+
+#define module_spmi_driver(__spmi_driver) \
+	module_driver(__spmi_driver, spmi_driver_register, \
+			spmi_driver_unregister)
+
+/**
+ * spmi_register_read() - register read

This is right but then it's not consistent. These functions have () after them but higher up we don't have that.

Usually the prototypes aren't documented because people use tags and such to go to the definition of the function. I would prefer we put the documentation near the implementation so that 1) this file gives a high level overview of the API and 2) I don't have to double jump with tags to figure out what to pass to these functions.

Quoted 8 lines

+ * @sdev: SPMI device
+ * @addr: slave register address (5-bit address).
+ * @buf: buffer to be populated with data from the Slave.
+ *
+ * Reads 1 byte of data from a Slave device register.
+ */

include/linux/spmi.h new file +2 -0
+int spmi_register_read(struct spmi_device *sdev, u8 addr, u8 *buf);
+
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#13 lore raw

Re: [PATCH v3 02/10] spmi: Linux driver framework for SPMI

Quoted 14 lines · Stephen Boyd

drivers/spmi/Kconfig line 5

Quoted 11 lines · Josh Cartwright
drivers/spmi/Kconfig new file +5 -0
new file mode 100644
index 0000000..a03835f
@@ -0,0 +1,9 @@
+#
+# SPMI driver configuration
+#
+menuconfig SPMI
+	bool "SPMI support"

Can we do tristate?

I don't think there is any reason why we can't do tristate here. I do foresee in the future, however, that we'll run into ordering/dependency problems when we get the regulator drivers in place.

I suppose we'll wait until we get there to deal with those.

Quoted 49 lines
Quoted 36 lines
drivers/spmi/Kconfig new file +4 -0
+	help
+	  SPMI (System Power Management Interface) is a two-wire
+	  serial interface between baseband and application processors
+	  and Power Management Integrated Circuits (PMIC).
drivers/spmi/spmi.c new file +26 -0
new file mode 100644
index 0000000..0780bd4
@@ -0,0 +1,491 @@
+/* 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/kernel.h>
+#include <linux/errno.h>
+#include <linux/idr.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/spmi.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+
+#include <dt-bindings/spmi/spmi.h>
+
+static DEFINE_MUTEX(ctrl_idr_lock);

drivers/spmi/spmi.c line 36

Quoted 10 lines
drivers/spmi/spmi.c new file +10 -0
+static DEFINE_IDR(ctrl_idr);
+
+static void spmi_dev_release(struct device *dev)
+{
+	struct spmi_device *sdev = to_spmi_device(dev);
+	kfree(sdev);
+}
+
+static struct device_type spmi_dev_type = {
+	.release	= spmi_dev_release,

const?

[..]

Quoted 4 lines
Quoted 1 line

+static struct device_type spmi_ctrl_type = {

const?

Yep. Thanks.

[..]

Quoted 6 lines

drivers/spmi/spmi.c line 163

Quoted 4 lines
drivers/spmi/spmi.c new file +4 -0
+int spmi_register_read(struct spmi_device *sdev, u8 addr, u8 *buf)
+{
+	/* 5-bit register address */
+	if (addr > 0x1F)

Perhaps 0x1f should be a #define.

Is 0x1F with the comment above it not clear enough?

Quoted 36 lines
Quoted 7 lines
drivers/spmi/spmi.c new file +7 -0
+		return -EINVAL;
+
+	return spmi_read_cmd(sdev->ctrl, SPMI_CMD_READ, sdev->usid, addr, 0,
+			     buf);
+}
+EXPORT_SYMBOL_GPL(spmi_register_read);
+

[...]

Quoted 15 lines
drivers/spmi/spmi.c new file +15 -0
+struct spmi_controller *spmi_controller_alloc(struct device *parent,
+					      size_t size)
+{
+	struct spmi_controller *ctrl;
+	int id;
+
+	if (WARN_ON(!parent))
+		return NULL;
+
+	ctrl = kzalloc(sizeof(*ctrl) + size, GFP_KERNEL);
+	if (!ctrl)
+		return NULL;
+
+	device_initialize(&ctrl->dev);
+	ctrl->dev.type = &spmi_ctrl_type;

drivers/spmi/spmi.c line 341

Quoted 10 lines
drivers/spmi/spmi.c new file +10 -0
+	ctrl->dev.bus = &spmi_bus_type;
+	ctrl->dev.parent = parent;
+	ctrl->dev.of_node = parent->of_node;
+	spmi_controller_set_drvdata(ctrl, &ctrl[1]);
+
+	idr_preload(GFP_KERNEL);
+	mutex_lock(&ctrl_idr_lock);
+	id = idr_alloc(&ctrl_idr, ctrl, 0, 0, GFP_NOWAIT);
+	mutex_unlock(&ctrl_idr_lock);
+	idr_preload_end();

This can just be:

Quoted 3 lines
    mutex_lock(&ctrl_idr_lock);
    id = idr_alloc(&ctrl_idr, ctrl, 0, 0, GFP_KERNEL);
    mutex_unlock(&ctrl_idr_lock);

Actually, I'm wondering if it's just easier to leverage the simpler ida_simple_* APIs instead.

Quoted 25 lines
Quoted 12 lines
drivers/spmi/spmi.c new file +12 -0
+
+	if (id < 0) {
+		dev_err(parent,
+			"unable to allocate SPMI controller identifier.\n");
+		spmi_controller_put(ctrl);
+		return NULL;
+	}
+
+	ctrl->nr = id;
+	dev_set_name(&ctrl->dev, "spmi-%d", id);
+
+	dev_dbg(&ctrl->dev, "allocated controller 0x%p id %d\n", ctrl, id);

drivers/spmi/spmi.c line 363

Quoted 10 lines
drivers/spmi/spmi.c new file +10 -0
+	return ctrl;
+}
+EXPORT_SYMBOL_GPL(spmi_controller_alloc);
+
+static int of_spmi_register_devices(struct spmi_controller *ctrl)
+{
+	struct device_node *node;
+	int err;
+
+	dev_dbg(&ctrl->dev, "of_spmi_register_devices\n");

Could be

Quoted 3 lines
    dev_dbg(&ctrl->dev, "%s", __func__);

so that function renaming is transparent.

Some of these dev_dbg()'s (like this one) can probably be just be removed, especially because we have an additional dev_dbg() right below this one...

Quoted 22 lines
Quoted 22 lines
drivers/spmi/spmi.c new file +22 -0
+
+	if (!ctrl->dev.of_node)
+		return -ENODEV;
+
+	dev_dbg(&ctrl->dev, "looping through children\n");
+
+	for_each_available_child_of_node(ctrl->dev.of_node, node) {
+		struct spmi_device *sdev;
+		u32 reg[2];
+
+		dev_dbg(&ctrl->dev, "adding child %s\n", node->full_name);
+
+		err = of_property_read_u32_array(node, "reg", reg, 2);
+		if (err) {
+			dev_err(&ctrl->dev,
+				"node %s does not have 'reg' property\n",
+				node->full_name);
+				continue;
+		}
+
+		if (reg[1] != SPMI_USID) {
+			dev_err(&ctrl->dev,
Quoted 8 lines

drivers/spmi/spmi.c line 391

Quoted 6 lines
drivers/spmi/spmi.c new file +6 -0
+				"node %s contains unsupported 'reg' entry\n",
+				node->full_name);
+			continue;
+		}
+
+		if (reg[0] > 0xF) {

Perhaps call this MAX_USID?

Sure.

Quoted 57 lines
Quoted 6 lines
drivers/spmi/spmi.c new file +6 -0
+			dev_err(&ctrl->dev,
+				"invalid usid on node %s\n",
+				node->full_name);
+			continue;
+		}
+

[...]

Quoted 38 lines
include/linux/spmi.h new file +32 -0
new file mode 100644
index 0000000..29cf0c9
@@ -0,0 +1,342 @@
+/* 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.
+ */
+#ifndef _LINUX_SPMI_H
+#define _LINUX_SPMI_H
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+
+/* Maximum slave identifier */
+#define SPMI_MAX_SLAVE_ID		16
+
+/* SPMI Commands */
+#define SPMI_CMD_EXT_WRITE		0x00
+#define SPMI_CMD_RESET			0x10
+#define SPMI_CMD_SLEEP			0x11
+#define SPMI_CMD_SHUTDOWN		0x12
+#define SPMI_CMD_WAKEUP			0x13
+#define SPMI_CMD_AUTHENTICATE		0x14
+#define SPMI_CMD_MSTR_READ		0x15
+#define SPMI_CMD_MSTR_WRITE		0x16
+#define SPMI_CMD_TRANSFER_BUS_OWNERSHIP	0x1A
+#define SPMI_CMD_DDB_MASTER_READ	0x1B

include/linux/spmi.h line 42

Quoted 10 lines
include/linux/spmi.h new file +10 -0
+#define SPMI_CMD_DDB_SLAVE_READ		0x1C
+#define SPMI_CMD_EXT_READ		0x20
+#define SPMI_CMD_EXT_WRITEL		0x30
+#define SPMI_CMD_EXT_READL		0x38
+#define SPMI_CMD_WRITE			0x40
+#define SPMI_CMD_READ			0x60
+#define SPMI_CMD_ZERO_WRITE		0x80
+
+/**
+ * Client/device handle (struct spmi_device):

This isn't kernel-doc format.

[..]

Quoted 4 lines
Quoted 1 line

+ * spmi_controller_alloc: Allocate a new SPMI controller

There should be a dash here instead of colon.

[..]

Quoted 8 lines

include/linux/spmi.h line 140

Quoted 5 lines
include/linux/spmi.h new file +5 -0
+static inline void spmi_controller_put(struct spmi_controller *ctrl)
+{
+	if (ctrl)
+		put_device(&ctrl->dev);
+}

This function is missing documentation.

[..]

Quoted 11 lines
Quoted 2 lines

+/**
+ * spmi_register_read() - register read

This is right but then it's not consistent. These functions have () after them but higher up we don't have that.

Usually the prototypes aren't documented because people use tags and such to go to the definition of the function. I would prefer we put the documentation near the implementation so that 1) this file gives a high level overview of the API and 2) I don't have to double jump with tags to figure out what to pass to these functions.

Will move/clean these up, thanks.

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#14 lore raw

Re: [PATCH v3 02/10] spmi: Linux driver framework for SPMI

Quoted 8 lines · Josh Cartwright
Quoted 6 lines · Stephen Boyd

drivers/spmi/spmi.c line 163

Quoted 4 lines · Josh Cartwright
drivers/spmi/spmi.c new file +4 -0
+int spmi_register_read(struct spmi_device *sdev, u8 addr, u8 *buf)
+{
+	/* 5-bit register address */
+	if (addr > 0x1F)

Perhaps 0x1f should be a #define.

Is 0x1F with the comment above it not clear enough?

It triggered my 'magic number used twice' alarm. I'm ok with it either way.

Quoted 27 lines
Quoted 27 lines
Quoted 15 lines
drivers/spmi/spmi.c new file +15 -0
+struct spmi_controller *spmi_controller_alloc(struct device *parent,
+					      size_t size)
+{
+	struct spmi_controller *ctrl;
+	int id;
+
+	if (WARN_ON(!parent))
+		return NULL;
+
+	ctrl = kzalloc(sizeof(*ctrl) + size, GFP_KERNEL);
+	if (!ctrl)
+		return NULL;
+
+	device_initialize(&ctrl->dev);
+	ctrl->dev.type = &spmi_ctrl_type;

drivers/spmi/spmi.c line 341

Quoted 10 lines
drivers/spmi/spmi.c new file +10 -0
+	ctrl->dev.bus = &spmi_bus_type;
+	ctrl->dev.parent = parent;
+	ctrl->dev.of_node = parent->of_node;
+	spmi_controller_set_drvdata(ctrl, &ctrl[1]);
+
+	idr_preload(GFP_KERNEL);
+	mutex_lock(&ctrl_idr_lock);
+	id = idr_alloc(&ctrl_idr, ctrl, 0, 0, GFP_NOWAIT);
+	mutex_unlock(&ctrl_idr_lock);
+	idr_preload_end();

This can just be:

Quoted 5 lines
Quoted 3 lines
    mutex_lock(&ctrl_idr_lock);
    id = idr_alloc(&ctrl_idr, ctrl, 0, 0, GFP_KERNEL);
    mutex_unlock(&ctrl_idr_lock);

Actually, I'm wondering if it's just easier to leverage the simpler ida_simple_* APIs instead.

Yes that also works.

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#15 lore raw

Re: [PATCH v3 02/10] spmi: Linux driver framework for SPMI

In reply to Josh Cartwright
Quoted 11 lines · Josh Cartwright

From: Kenneth Heitke <[email protected]>

System Power Management Interface (SPMI) is a specification developed by the MIPI (Mobile Industry Process Interface) Alliance optimized for the real time control of Power Management ICs (PMIC).

SPMI is a two-wire serial interface that supports up to 4 master devices and up to 16 logical slaves.

The framework supports message APIs, multiple busses (1 controller per bus) and multiple clients/slave devices per controller.

I haven't read this in depth, but... if you want to support runtime PM for your spmi devices, then I suggest that you also include the fragments to setup runtime PM in the bus-level probe handler and clean it up in the bus-level remove handler.

What that means is doing what PCI, AMBA and similar buses do:

	pm_runtime_get_noresume(dev);
	pm_runtime_set_active(dev);
	pm_runtime_enable(dev);

	ret = driver->probe(dev);
	if (ret != 0) {
		pm_runtime_disable(dev);
		pm_runtime_set_suspended(dev);
		pm_runtime_put_noidle(dev);
	}

and:

	pm_runtime_get_sync(dev);
	ret = driver->remove(dev);
	pm_runtime_put_noidle(dev);

	pm_runtime_disable(dev);
	pm_runtime_set_suspended(dev);
	pm_runtime_put_noidle(dev);

What this means is that your devices get runtime enabled by default, but they have to do a pm_runtime_put() or similar in their probe function to benefit from it and a balancing pm_runtime_get() in their remove method.

The set_active() call above may need to be conditional upon whether the device really is in a powered up state at that point or not.

Others have made comments on various other issues so I won't repeat those points here.

#16 lore raw

PATCH v3 3/10 spmi: add generic SPMI controller binding documentation

In reply to Josh Cartwright
---
 Documentation/devicetree/bindings/spmi/spmi.txt | 41 +++++++++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/spmi/spmi.txt
Documentation/devicetree/bindings/spmi/spmi.txt new file +41 -0
new file mode 100644
index 0000000..32a180d
@@ -0,0 +1,41 @@
+System Power Management Interface (SPMI) Controller
+
+This document defines a generic set of bindings for use by SPMI controllers.  A
+controller is modelled in device tree as a node with zero or more child nodes,
+each representing a unique slave on the bus.
+
+Required properties:
+- #address-cells : must be set to 2
+- #size-cells : must be set to 0
+
+Child nodes:
+
+An SPMI controller node can contain zero or more child nodes representing slave
+devices on the bus.  Child 'reg' properties are specified as an address, type
+pair.  The address must be in the range 0-15 (4 bits).  The type must be one of
+SPMI_USID or SPMI_GSID (1) for Unique Slave ID or Group Slave ID respectively.
+These are the identifiers "statically assigned by the system integrator", as
+per the SPMI spec.
+
+Each child node must have one and only one 'reg' entry of type SPMI_USID.
+
+#include <dt-bindings/spmi/spmi.h>
+
+	controller at .. {
+		compatible = "...";
+		reg = <...>;
+
+		#address-cells = <2>;
+		#size-cells <0>;
+
+		child at 0 {
+			compatible = "...";
+			reg = <0 SPMI_USID>;
+		};
+
+		child at 7 {
+			compatible = "...";
+			reg = <7 SPMI_USID
+			       3 SPMI_GSID>;
+		};
+	};
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#17 lore raw

PATCH v3 4/10 spmi: Add MSM PMIC Arbiter SPMI controller

In reply to Josh Cartwright

From: Kenneth Heitke <[email protected]>

Qualcomm's PMIC Arbiter SPMI controller functions as a bus master and is used to communication with one or more PMIC (slave) devices on the SPMI bus. The PMIC Arbiter is actually a hardware wrapper around the SPMI controller that provides concurrent and autonomous PMIC access to various entities that need to communicate with the PMIC.

The SPMI controller hardware handles all of the SPMI bus activity (bus arbitration, sequence start condition, transmission of frames, etc). This software driver uses the PMIC Arbiter register interface to initiate command sequences on the SPMI bus. The status register is read to determine when the command sequence has completed and whether or not it completed successfully.

---
 drivers/spmi/Kconfig         |  15 ++
 drivers/spmi/Makefile        |   2 +
 drivers/spmi/spmi-pmic-arb.c | 403 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 420 insertions(+)
 create mode 100644 drivers/spmi/spmi-pmic-arb.c
drivers/spmi/Kconfig +15 -0
index a03835f..056891d 100644
@@ -7,3 +7,18 @@ menuconfig SPMI
 	  SPMI (System Power Management Interface) is a two-wire
 	  serial interface between baseband and application processors
 	  and Power Management Integrated Circuits (PMIC).
+
+if SPMI
+
+config SPMI_MSM_PMIC_ARB
+	tristate "Qualcomm MSM SPMI Controller (PMIC Arbiter)"
+	depends on ARCH_MSM
+	help
+	  If you say yes to this option, support will be included for the
+	  built-in SPMI PMIC Arbiter interface on Qualcomm MSM family
+	  processors.
+
+	  This is required for communicating with Qualcomm PMICs and
+	  other devices that have the SPMI interface.
+
+endif
drivers/spmi/Makefile +2 -0
index 1de1acd..fc75104 100644
@@ -2,3 +2,5 @@
 # Makefile for kernel SPMI framework.
 #
 obj-$(CONFIG_SPMI)	+= spmi.o
+
+obj-$(CONFIG_SPMI_MSM_PMIC_ARB)	+= spmi-pmic-arb.o
drivers/spmi/spmi-pmic-arb.c new file +403 -0

403 lines not on this page · raw message

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#18 lore raw

Re: [PATCH v3 04/10] spmi: Add MSM PMIC Arbiter SPMI controller

drivers/spmi/spmi-pmic-arb.c line 146

Quoted 6 lines · Josh Cartwright
drivers/spmi/spmi-pmic-arb.c new file +6 -0
+
+/**
+ * pa_write_data: write 1..4 bytes from buf to pmic-arb's register
+ * @bc byte-count -1. range: 0..3
+ * @reg register's address
+ * @buf buffer to write. length must be bc+1

Missing colon between variable and description.

Quoted 9 lines

+ */

drivers/spmi/spmi-pmic-arb.c new file +8 -0
+static void
+pa_write_data(struct spmi_pmic_arb_dev *dev, const u8 *buf, u32 reg, u8 bc)
+{
+	u32 data = 0;
+	memcpy(&data, buf, (bc & 3) + 1);
+	pmic_arb_base_write(dev, reg, data);
+}
+

[...]

drivers/spmi/spmi-pmic-arb.c line 233

Quoted 11 lines
drivers/spmi/spmi-pmic-arb.c new file +11 -0
+static int pmic_arb_read_cmd(struct spmi_controller *ctrl,
+			     u8 opc, u8 sid, u16 addr, u8 bc, u8 *buf)
+{
+	struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl);
+	unsigned long flags;
+	u32 cmd;
+	int rc;
+
+	if (bc >= PMIC_ARB_MAX_TRANS_BYTES) {
+		dev_err(&ctrl->dev,
+			"pmic-arb supports 1..%d bytes per trans, but:%d requested",

Nitpick: Please replace the colon between but and %d with a space.

Review

Quoted 1 line
(quoted diff) +1 -0
+			PMIC_ARB_MAX_TRANS_BYTES, bc+1);

Space around that '+' please.

Quoted 16 lines
drivers/spmi/spmi-pmic-arb.c new file +16 -0
+		return  -EINVAL;
+	}
+	dev_dbg(&ctrl->dev,
+		"op:0x%x sid:%d bc:%d addr:0x%x\n", opc, sid, bc, addr);
+
+	/* Check the opcode */
+	if (opc >= 0x60 && opc <= 0x7F)
+		opc = PMIC_ARB_OP_READ;
+	else if (opc >= 0x20 && opc <= 0x2F)
+		opc = PMIC_ARB_OP_EXT_READ;
+	else if (opc >= 0x38 && opc <= 0x3F)
+		opc = PMIC_ARB_OP_EXT_READL;
+	else
+		return -EINVAL;
+
+	cmd = (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) | (bc & 0x7);

drivers/spmi/spmi-pmic-arb.c line 260

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c new file +10 -0
+
+	spin_lock_irqsave(&pmic_arb->lock, flags);
+	pmic_arb_base_write(pmic_arb, PMIC_ARB_CMD(pmic_arb->channel), cmd);
+	rc = pmic_arb_wait_for_done(ctrl);
+	if (rc)
+		goto done;
+
+	/* Read from FIFO, note 'bc' is actually number of bytes minus 1 */
+	pa_read_data(pmic_arb, buf, PMIC_ARB_RDATA0(pmic_arb->channel)
+							, min_t(u8, bc, 3));

Nitpick: Weird comma starting a line here.

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c new file +10 -0
+
+	if (bc > 3)
+		pa_read_data(pmic_arb, buf + 4,
+				PMIC_ARB_RDATA1(pmic_arb->channel), bc - 4);
+
+done:
+	spin_unlock_irqrestore(&pmic_arb->lock, flags);
+	return rc;
+}
+

[...]

Quoted 34 lines
drivers/spmi/spmi-pmic-arb.c new file +34 -0
+static int spmi_pmic_arb_probe(struct platform_device *pdev)
+{
+	struct spmi_pmic_arb_dev *pa;
+	struct spmi_controller *ctrl;
+	struct resource *res;
+	int err, i;
+
+	ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*pa));
+	if (!ctrl)
+		return -ENOMEM;
+
+	pa = spmi_controller_get_drvdata(ctrl);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
+	pa->base = devm_ioremap_resource(&ctrl->dev, res);
+	if (IS_ERR(pa->base)) {
+		err = PTR_ERR(pa->base);
+		goto err_put_ctrl;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr");
+	pa->intr = devm_ioremap_resource(&ctrl->dev, res);
+	if (IS_ERR(pa->intr)) {
+		err = PTR_ERR(pa->intr);
+		goto err_put_ctrl;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cnfg");
+	pa->cnfg = devm_ioremap_resource(&ctrl->dev, res);
+	if (IS_ERR(pa->cnfg)) {
+		err = PTR_ERR(pa->cnfg);
+		goto err_put_ctrl;
+	}
+

drivers/spmi/spmi-pmic-arb.c line 361

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c new file +10 -0
+	for (i = 0; i < ARRAY_SIZE(pa->mapping_table); ++i)
+		pa->mapping_table[i] = readl_relaxed(
+				pa->cnfg + SPMI_MAPPING_TABLE_REG(i));
+
+	platform_set_drvdata(pdev, ctrl);
+	spin_lock_init(&pa->lock);
+
+	pa->channel = 0;
+	pa->max_apid = 0;
+	pa->min_apid = PMIC_ARB_MAX_PERIPHS - 1;

That looks backwards. Is this right?

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c new file +10 -0
+
+	ctrl->cmd = pmic_arb_cmd;
+	ctrl->read_cmd = pmic_arb_read_cmd;
+	ctrl->write_cmd = pmic_arb_write_cmd;
+
+	err = spmi_controller_add(ctrl);
+	if (err)
+		goto err_put_ctrl;
+
+	dev_dbg(&ctrl->dev, "PMIC Arb Version 0x%x\n",

drivers/spmi/spmi-pmic-arb.c line 381

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c new file +10 -0
+		pmic_arb_base_read(pa, PMIC_ARB_VERSION));
+
+	return 0;
+
+err_put_ctrl:
+	spmi_controller_put(ctrl);
+	return err;
+}
+
+static int __exit spmi_pmic_arb_remove(struct platform_device *pdev)

__exit shouldn't be here. We want this function in modules.

Quoted 5 lines
drivers/spmi/spmi-pmic-arb.c new file +5 -0
+{
+	struct spmi_controller *ctrl = platform_get_drvdata(pdev);
+	spmi_controller_remove(ctrl);
+	return 0;
+}

drivers/spmi/spmi-pmic-arb.c line 396

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c new file +10 -0
+
+static struct of_device_id spmi_pmic_arb_match_table[] = {
+	{	.compatible = "qcom,spmi-pmic-arb", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, spmi_pmic_arb_match_table);
+
+static struct platform_driver spmi_pmic_arb_driver = {
+	.probe		= spmi_pmic_arb_probe,
+	.remove		= __exit_p(spmi_pmic_arb_remove),

Please drop this __exit_p() usage as well.

drivers/spmi/spmi-pmic-arb.c line 403

Quoted 7 lines
drivers/spmi/spmi-pmic-arb.c new file +7 -0
+	.driver		= {
+		.name	= "spmi_pmic_arb",
+		.owner	= THIS_MODULE,
+		.of_match_table = spmi_pmic_arb_match_table,
+	},
+};
+module_platform_driver(spmi_pmic_arb_driver);

MODULE_LICENSE()
MODULE_ALIAS()
?

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#19 lore raw

Re: [PATCH v3 04/10] spmi: Add MSM PMIC Arbiter SPMI controller

Quoted 9 lines · Stephen Boyd

drivers/spmi/spmi-pmic-arb.c line 146

Quoted 6 lines · Josh Cartwright
drivers/spmi/spmi-pmic-arb.c new file +6 -0
+
+/**
+ * pa_write_data: write 1..4 bytes from buf to pmic-arb's register
+ * @bc byte-count -1. range: 0..3
+ * @reg register's address
+ * @buf buffer to write. length must be bc+1

Missing colon between variable and description.

I'll clean the documentation up a bit and push it all to the implementation (as suggested in a previous review).

[..]

Quoted 9 lines

drivers/spmi/spmi-pmic-arb.c line 233

Quoted 3 lines
drivers/spmi/spmi-pmic-arb.c new file +3 -0
+	if (bc >= PMIC_ARB_MAX_TRANS_BYTES) {
+		dev_err(&ctrl->dev,
+			"pmic-arb supports 1..%d bytes per trans, but:%d requested",

Nitpick: Please replace the colon between but and %d with a space.

Review

Quoted 1 line
(quoted diff) +1 -0
+			PMIC_ARB_MAX_TRANS_BYTES, bc+1);

Space around that '+' please.

Sure.

Quoted 20 lines
Quoted 20 lines
drivers/spmi/spmi-pmic-arb.c new file +20 -0
+		return  -EINVAL;
+	}
+	dev_dbg(&ctrl->dev,
+		"op:0x%x sid:%d bc:%d addr:0x%x\n", opc, sid, bc, addr);
+
+	/* Check the opcode */
+	if (opc >= 0x60 && opc <= 0x7F)
+		opc = PMIC_ARB_OP_READ;
+	else if (opc >= 0x20 && opc <= 0x2F)
+		opc = PMIC_ARB_OP_EXT_READ;
+	else if (opc >= 0x38 && opc <= 0x3F)
+		opc = PMIC_ARB_OP_EXT_READL;
+	else
+		return -EINVAL;
+
+	cmd = (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) | (bc & 0x7);
+
+	spin_lock_irqsave(&pmic_arb->lock, flags);
+	pmic_arb_base_write(pmic_arb, PMIC_ARB_CMD(pmic_arb->channel), cmd);
+	rc = pmic_arb_wait_for_done(ctrl);
Quoted 8 lines

drivers/spmi/spmi-pmic-arb.c line 260

Quoted 6 lines
drivers/spmi/spmi-pmic-arb.c new file +6 -0
+	if (rc)
+		goto done;
+
+	/* Read from FIFO, note 'bc' is actually number of bytes minus 1 */
+	pa_read_data(pmic_arb, buf, PMIC_ARB_RDATA0(pmic_arb->channel)
+							, min_t(u8, bc, 3));

Nitpick: Weird comma starting a line here.

Okay.

[..]

Quoted 22 lines
Quoted 1 line

+static int __exit spmi_pmic_arb_remove(struct platform_device *pdev)

__exit shouldn't be here. We want this function in modules.

Quoted 5 lines
drivers/spmi/spmi-pmic-arb.c new file +5 -0
+{
+	struct spmi_controller *ctrl = platform_get_drvdata(pdev);
+	spmi_controller_remove(ctrl);
+	return 0;
+}

drivers/spmi/spmi-pmic-arb.c line 396

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c new file +10 -0
+
+static struct of_device_id spmi_pmic_arb_match_table[] = {
+	{	.compatible = "qcom,spmi-pmic-arb", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, spmi_pmic_arb_match_table);
+
+static struct platform_driver spmi_pmic_arb_driver = {
+	.probe		= spmi_pmic_arb_probe,
+	.remove		= __exit_p(spmi_pmic_arb_remove),

Please drop this __exit_p() usage as well.

Quoted 10 lines

drivers/spmi/spmi-pmic-arb.c line 403

Quoted 7 lines
drivers/spmi/spmi-pmic-arb.c new file +7 -0
+	.driver		= {
+		.name	= "spmi_pmic_arb",
+		.owner	= THIS_MODULE,
+		.of_match_table = spmi_pmic_arb_match_table,
+	},
+};
+module_platform_driver(spmi_pmic_arb_driver);

MODULE_LICENSE()
MODULE_ALIAS()

Yep, will re-add. Not sure why I dropped these...

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#20 lore raw

PATCH v3 5/10 spmi: pmic_arb: add support for interrupt handling

In reply to Josh Cartwright

The Qualcomm PMIC Arbiter, in addition to being a basic SPMI controller, also implements interrupt handling for slave devices. Note, this is outside the scope of SPMI, as SPMI leaves interrupt handling completely unspecified.

Extend the driver to provide a irq_chip implementation and chained irq handling which allows for these interrupts to be used.

---
 drivers/spmi/spmi-pmic-arb.c | 359 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 357 insertions(+), 2 deletions(-)
drivers/spmi/spmi-pmic-arb.c +357 -2
index 92e1416..6926a6b 100644
@@ -13,6 +13,9 @@
 #include <linux/err.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
@@ -108,12 +111,17 @@ struct spmi_pmic_arb_dev {
 	void __iomem		*base;
 	void __iomem		*intr;
 	void __iomem		*cnfg;
+	unsigned int		irq;
 	bool			allow_wakeup;
 	spinlock_t		lock;
 	u8			channel;
 	u8			min_apid;
 	u8			max_apid;
 	u32			mapping_table[SPMI_MAPPING_TABLE_LEN];
+	int			bus_nr;
+	struct irq_domain	*domain;
+	struct spmi_controller	*spmic;
+	u16			apid_to_ppid[256];
 };
 
 static inline u32 pmic_arb_base_read(struct spmi_pmic_arb_dev *dev, u32 offset)
@@ -315,18 +323,340 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl,
 	return rc;
 }
 
+enum qpnpint_regs {
+	QPNPINT_REG_RT_STS		= 0x10,
+	QPNPINT_REG_SET_TYPE		= 0x11,
+	QPNPINT_REG_POLARITY_HIGH	= 0x12,
+	QPNPINT_REG_POLARITY_LOW	= 0x13,
+	QPNPINT_REG_LATCHED_CLR		= 0x14,
+	QPNPINT_REG_EN_SET		= 0x15,
+	QPNPINT_REG_EN_CLR		= 0x16,
+	QPNPINT_REG_LATCHED_STS		= 0x18,
+};
+
+struct spmi_pmic_arb_qpnpint_type {
+	u8 type; /* 1 -> edge */
+	u8 polarity_high;
+	u8 polarity_low;
+} __packed;
+
+/* Simplified accessor functions for irqchip callbacks */
+static void qpnpint_spmi_write(struct irq_data *d, u8 reg, void *buf,
+			       size_t len)
+{
+	struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+	u8 sid = d->hwirq >> 24;
+	u8 per = d->hwirq >> 16;
+
+	if (pmic_arb_write_cmd(pa->spmic, SPMI_CMD_EXT_WRITEL, sid,
+			       (per << 8) + reg, len, buf))
+		dev_err_ratelimited(&pa->spmic->dev,
+				"failed irqchip transaction on %x\n",
+				    d->irq);
+}
+
+static void qpnpint_spmi_read(struct irq_data *d, u8 reg, void *buf, size_t len)
+{
+	struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+	u8 sid = d->hwirq >> 24;
+	u8 per = d->hwirq >> 16;
+
+	if (pmic_arb_read_cmd(pa->spmic, SPMI_CMD_EXT_READL, sid,
+			      (per << 8) + reg, len, buf))
+		dev_err_ratelimited(&pa->spmic->dev,
+				"failed irqchip transaction on %x\n",
+				    d->irq);
+}
+
+static void periph_interrupt(struct spmi_pmic_arb_dev *pa, u8 apid)
+{
+	unsigned int irq;
+	u32 status;
+	int id;
+
+	status = readl_relaxed(pa->intr + SPMI_PIC_IRQ_STATUS(apid));
+	while (status) {
+		id = ffs(status) - 1;
+		status &= ~(1 << id);
+		irq = irq_find_mapping(pa->domain,
+				       pa->apid_to_ppid[apid] << 16
+				     | id << 8
+				     | apid);
+		generic_handle_irq(irq);
+	}
+}
+
+static void pmic_arb_chained_irq(unsigned int irq, struct irq_desc *desc)
+{
+	struct spmi_pmic_arb_dev *pa = irq_get_handler_data(irq);
+	struct irq_chip *chip = irq_get_chip(irq);
+	void __iomem *intr = pa->intr;
+	int first = pa->min_apid >> 5;
+	int last = pa->max_apid >> 5;
+	int i, id;
+	u8 ee = 0; /*pa->owner;*/
+	u32 status;
+
+	chained_irq_enter(chip, desc);
+
+	for (i = first; i <= last; ++i) {
+		status = readl_relaxed(intr + SPMI_PIC_OWNER_ACC_STATUS(ee, i));
+		while (status) {
+			id = ffs(status) - 1;
+			status &= ~(1 << id);
+			periph_interrupt(pa, id + i * 32);
+		}
+	}
+
+	chained_irq_exit(chip, desc);
+}
+
+static void qpnpint_irq_ack(struct irq_data *d)
+{
+	struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+	u8 irq  = d->hwirq >> 8;
+	u8 apid = d->hwirq;
+	unsigned long flags;
+	u8 data;
+
+	dev_dbg(&pa->spmic->dev, "hwirq %lu irq: %d\n", d->hwirq, d->irq);
+
+	spin_lock_irqsave(&pa->lock, flags);
+	writel_relaxed(1 << irq, pa->intr + SPMI_PIC_IRQ_CLEAR(apid));
+	spin_unlock_irqrestore(&pa->lock, flags);
+
+	data = 1 << irq;
+	qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &data, 1);
+}
+
+static void qpnpint_irq_mask(struct irq_data *d)
+{
+	struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+	u8 irq  = d->hwirq >> 8;
+	u8 apid = d->hwirq;
+	unsigned long flags;
+	u32 status;
+	u8 data;
+
+	dev_dbg(&pa->spmic->dev, "hwirq %lu irq: %d\n", d->hwirq, d->irq);
+
+	spin_lock_irqsave(&pa->lock, flags);
+	status = readl_relaxed(pa->intr + SPMI_PIC_ACC_ENABLE(apid));
+	if (status & SPMI_PIC_ACC_ENABLE_BIT) {
+		status = status & ~SPMI_PIC_ACC_ENABLE_BIT;
+		writel_relaxed(status, pa->intr + SPMI_PIC_ACC_ENABLE(apid));
+	}
+	spin_unlock_irqrestore(&pa->lock, flags);
+
+	data = 1 << irq;
+	qpnpint_spmi_write(d, QPNPINT_REG_EN_CLR, &data, 1);
+}
+
+static void qpnpint_irq_unmask(struct irq_data *d)
+{
+	struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+	u8 irq  = d->hwirq >> 8;
+	u8 apid = d->hwirq;
+	unsigned long flags;
+	u32 status;
+	u8 data;
+
+	dev_dbg(&pa->spmic->dev, "hwirq %lu irq: %d, apid = %02x\n", d->hwirq,
+				  d->irq, apid);
+
+	spin_lock_irqsave(&pa->lock, flags);
+	status = readl_relaxed(pa->intr + SPMI_PIC_ACC_ENABLE(apid));
+	if (!(status & SPMI_PIC_ACC_ENABLE_BIT)) {
+		writel_relaxed(status | SPMI_PIC_ACC_ENABLE_BIT,
+				pa->intr + SPMI_PIC_ACC_ENABLE(apid));
+	}
+	spin_unlock_irqrestore(&pa->lock, flags);
+
+	data = 1 << irq;
+	qpnpint_spmi_write(d, QPNPINT_REG_EN_SET, &data, 1);
+}
+
+static void qpnpint_irq_enable(struct irq_data *d)
+{
+	struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+	u8 irq  = d->hwirq >> 8;
+	u8 data;
+
+	dev_dbg(&pa->spmic->dev, "hwirq %lu irq: %d\n", d->hwirq, d->irq);
+
+	qpnpint_irq_unmask(d);
+
+	data = 1 << irq;
+	qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &data, 1);
+}
+
+static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type)
+{
+	struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d);
+	struct spmi_pmic_arb_qpnpint_type type;
+	u8 irq = d->hwirq >> 8;
+
+	dev_dbg(&pa->spmic->dev, "qpnpint_irq_set_type %p, %x\n", d, flow_type);
+
+	qpnpint_spmi_read(d, QPNPINT_REG_SET_TYPE, &type, 3);
+
+	if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
+		type.type |= 1 << irq;
+		if (flow_type & IRQF_TRIGGER_RISING)
+			type.polarity_high |= 1 << irq;
+		if (flow_type & IRQF_TRIGGER_FALLING)
+			type.polarity_low  |= 1 << irq;
+	} else {
+		if ((flow_type & (IRQF_TRIGGER_HIGH)) &&
+		    (flow_type & (IRQF_TRIGGER_LOW)))
+			return -EINVAL;
+
+		type.type &= ~(1 << irq); /* level trig */
+		if (flow_type & IRQF_TRIGGER_HIGH)
+			type.polarity_high |= 1 << irq;
+		else
+			type.polarity_low  |= 1 << irq;
+	}
+
+	qpnpint_spmi_write(d, QPNPINT_REG_SET_TYPE, &type, 3);
+	return 0;
+}
+
+static struct irq_chip pmic_arb_irqchip = {
+	.name		= "pmic_arb",
+	.irq_enable	= qpnpint_irq_enable,
+	.irq_ack	= qpnpint_irq_ack,
+	.irq_mask	= qpnpint_irq_mask,
+	.irq_unmask	= qpnpint_irq_unmask,
+	.irq_set_type	= qpnpint_irq_set_type,
+	.flags		= IRQCHIP_MASK_ON_SUSPEND
+			| IRQCHIP_SKIP_SET_WAKE,
+};
+
+struct spmi_pmic_arb_irq_spec {
+	unsigned slave:4;
+	unsigned per:8;
+	unsigned irq:3;
+};
+
+static int search_mapping_table(struct spmi_pmic_arb_dev *pa,
+				struct spmi_pmic_arb_irq_spec *spec,
+				u8 *apid)
+{
+	u16 ppid = spec->slave << 8 | spec->per;
+	u32 *mapping_table = pa->mapping_table;
+	int index = 0, i;
+	u32 data;
+
+	for (i = 0; i < SPMI_MAPPING_TABLE_TREE_DEPTH; ++i) {
+		data = mapping_table[index];
+
+		if (ppid & (1 << SPMI_MAPPING_BIT_INDEX(data))) {
+			if (SPMI_MAPPING_BIT_IS_1_FLAG(data)) {
+				index = SPMI_MAPPING_BIT_IS_1_RESULT(data);
+			} else {
+				*apid = SPMI_MAPPING_BIT_IS_1_RESULT(data);
+				return 0;
+			}
+		} else {
+			if (SPMI_MAPPING_BIT_IS_0_FLAG(data)) {
+				index = SPMI_MAPPING_BIT_IS_0_RESULT(data);
+			} else {
+				*apid = SPMI_MAPPING_BIT_IS_0_RESULT(data);
+				return 0;
+			}
+		}
+	}
+
+	return -ENODEV;
+}
+
+static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
+					   struct device_node *controller,
+					   const u32 *intspec,
+					   unsigned int intsize,
+					   unsigned long *out_hwirq,
+					   unsigned int *out_type)
+{
+	struct spmi_pmic_arb_dev *pa = d->host_data;
+	struct spmi_pmic_arb_irq_spec spec;
+	int err;
+	u8 apid;
+
+	dev_dbg(&pa->spmic->dev,
+		"intspec[0] 0x%1x intspec[1] 0x%02x intspec[2] 0x%02x\n",
+		intspec[0], intspec[1], intspec[2]);
+
+	if (d->of_node != controller)
+		return -EINVAL;
+	if (intsize != 4)
+		return -EINVAL;
+	if (intspec[0] > 0xF || intspec[1] > 0xFF || intspec[2] > 0x7)
+		return -EINVAL;
+
+	spec.slave = intspec[0];
+	spec.per   = intspec[1];
+	spec.irq   = intspec[2];
+
+	err = search_mapping_table(pa, &spec, &apid);
+	if (err)
+		return err;
+
+	pa->apid_to_ppid[apid] = spec.slave << 8 | spec.per;
+
+	/* Keep track of {max,min}_apid for bounding search during interrupt */
+	if (apid > pa->max_apid)
+		pa->max_apid = apid;
+	if (apid < pa->min_apid)
+		pa->min_apid = apid;
+
+	*out_hwirq = spec.slave << 24
+		   | spec.per   << 16
+		   | spec.irq   << 8
+		   | apid;
+	*out_type  = intspec[3] & IRQ_TYPE_SENSE_MASK;
+
+	dev_dbg(&pa->spmic->dev, "out_hwirq = %lu\n", *out_hwirq);
+
+	return 0;
+}
+
+static int qpnpint_irq_domain_map(struct irq_domain *d,
+				  unsigned int virq,
+				  irq_hw_number_t hwirq)
+{
+	struct spmi_pmic_arb_dev *pa = d->host_data;
+
+	dev_dbg(&pa->spmic->dev, "virq = %u, hwirq = %lu\n", virq, hwirq);
+
+	irq_set_chip_and_handler(virq, &pmic_arb_irqchip, handle_level_irq);
+	irq_set_chip_data(virq, d->host_data);
+#ifdef CONFIG_ARM
+	set_irq_flags(virq, IRQF_VALID);
+#else
+	irq_set_noprobe(virq);
+#endif
+	return 0;
+}
+
+static const struct irq_domain_ops pmic_arb_irq_domain_ops = {
+	.map	= qpnpint_irq_domain_map,
+	.xlate	= qpnpint_irq_domain_dt_translate,
+};
+
 static int spmi_pmic_arb_probe(struct platform_device *pdev)
 {
 	struct spmi_pmic_arb_dev *pa;
 	struct spmi_controller *ctrl;
 	struct resource *res;
-	int err, i;
+	int err = 0, i;
 
 	ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*pa));
 	if (!ctrl)
 		return -ENOMEM;
 
 	pa = spmi_controller_get_drvdata(ctrl);
+	pa->spmic = ctrl;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
 	pa->base = devm_ioremap_resource(&ctrl->dev, res);
@@ -349,6 +679,12 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 		goto err_put_ctrl;
 	}
 
+	pa->irq = platform_get_irq(pdev, 0);
+	if (pa->irq < 0) {
+		err = pa->irq;
+		goto err_put_ctrl;
+	}
+
 	for (i = 0; i < ARRAY_SIZE(pa->mapping_table); ++i)
 		pa->mapping_table[i] = readl_relaxed(
 				pa->cnfg + SPMI_MAPPING_TABLE_REG(i));
@@ -364,15 +700,30 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 	ctrl->read_cmd = pmic_arb_read_cmd;
 	ctrl->write_cmd = pmic_arb_write_cmd;
 
+	dev_dbg(&pdev->dev, "adding irq domain\n");
+	pa->domain = irq_domain_add_tree(pdev->dev.of_node,
+					 &pmic_arb_irq_domain_ops, pa);
+	if (!pa->domain) {
+		dev_err(&pdev->dev, "unable to create irq_domain\n");
+		goto err_put_ctrl;
+	}
+
+	irq_set_handler_data(pa->irq, pa);
+	irq_set_chained_handler(pa->irq, pmic_arb_chained_irq);
+
 	err = spmi_controller_add(ctrl);
 	if (err)
-		goto err_put_ctrl;
+		goto err_domain_remove;
 
 	dev_dbg(&ctrl->dev, "PMIC Arb Version 0x%x\n",
 		pmic_arb_base_read(pa, PMIC_ARB_VERSION));
 
 	return 0;
 
+err_domain_remove:
+	irq_set_chained_handler(pa->irq, NULL);
+	irq_set_handler_data(pa->irq, NULL);
+	irq_domain_remove(pa->domain);
 err_put_ctrl:
 	spmi_controller_put(ctrl);
 	return err;
@@ -381,6 +732,10 @@ err_put_ctrl:
 static int __exit spmi_pmic_arb_remove(struct platform_device *pdev)
 {
 	struct spmi_controller *ctrl = platform_get_drvdata(pdev);
+	struct spmi_pmic_arb_dev *pa = spmi_controller_get_drvdata(ctrl);
+	irq_set_chained_handler(pa->irq, NULL);
+	irq_set_handler_data(pa->irq, NULL);
+	irq_domain_remove(pa->domain);
 	spmi_controller_remove(ctrl);
 	return 0;
 }
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#21 lore raw

Re: [PATCH v3 05/10] spmi: pmic_arb: add support for interrupt handling

drivers/spmi/spmi-pmic-arb.c struct spmi_pmic_arb_dev { · line 121

Quoted 12 lines · Josh Cartwright
drivers/spmi/spmi-pmic-arb.c +2 -0
@@ -108,12 +111,17 @@ struct spmi_pmic_arb_dev {
 	void __iomem		*base;
 	void __iomem		*intr;
 	void __iomem		*cnfg;
+	unsigned int		irq;
 	bool			allow_wakeup;
 	spinlock_t		lock;
 	u8			channel;
 	u8			min_apid;
 	u8			max_apid;
 	u32			mapping_table[SPMI_MAPPING_TABLE_LEN];
+	int			bus_nr;

This looks unused.

Quoted 6 lines
drivers/spmi/spmi-pmic-arb.c +3 -0
+	struct irq_domain	*domain;
+	struct spmi_controller	*spmic;
+	u16			apid_to_ppid[256];
 };
 
 static inline u32 pmic_arb_base_read(struct spmi_pmic_arb_dev *dev, u32 offset)

[...]

drivers/spmi/spmi-pmic-arb.c static int pmic_arb_write_cmd(struct spmi_controller *ctrl, · line 397

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +10 -0
+
+static void pmic_arb_chained_irq(unsigned int irq, struct irq_desc *desc)
+{
+	struct spmi_pmic_arb_dev *pa = irq_get_handler_data(irq);
+	struct irq_chip *chip = irq_get_chip(irq);
+	void __iomem *intr = pa->intr;
+	int first = pa->min_apid >> 5;
+	int last = pa->max_apid >> 5;
+	int i, id;
+	u8 ee = 0; /*pa->owner;*/

TODO?

Quoted 16 lines
drivers/spmi/spmi-pmic-arb.c +16 -0
+	u32 status;
+
+	chained_irq_enter(chip, desc);
+
+	for (i = first; i <= last; ++i) {
+		status = readl_relaxed(intr + SPMI_PIC_OWNER_ACC_STATUS(ee, i));
+		while (status) {
+			id = ffs(status) - 1;
+			status &= ~(1 << id);
+			periph_interrupt(pa, id + i * 32);
+		}
+	}
+
+	chained_irq_exit(chip, desc);
+}
+

[...]

Quoted 28 lines
drivers/spmi/spmi-pmic-arb.c +28 -0
+static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
+					   struct device_node *controller,
+					   const u32 *intspec,
+					   unsigned int intsize,
+					   unsigned long *out_hwirq,
+					   unsigned int *out_type)
+{
+	struct spmi_pmic_arb_dev *pa = d->host_data;
+	struct spmi_pmic_arb_irq_spec spec;
+	int err;
+	u8 apid;
+
+	dev_dbg(&pa->spmic->dev,
+		"intspec[0] 0x%1x intspec[1] 0x%02x intspec[2] 0x%02x\n",
+		intspec[0], intspec[1], intspec[2]);
+
+	if (d->of_node != controller)
+		return -EINVAL;
+	if (intsize != 4)
+		return -EINVAL;
+	if (intspec[0] > 0xF || intspec[1] > 0xFF || intspec[2] > 0x7)
+		return -EINVAL;
+
+	spec.slave = intspec[0];
+	spec.per   = intspec[1];
+	spec.irq   = intspec[2];
+
+	err = search_mapping_table(pa, &spec, &apid);

drivers/spmi/spmi-pmic-arb.c static int pmic_arb_write_cmd(struct spmi_controller *ctrl, · line 611

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +10 -0
+	if (err)
+		return err;
+
+	pa->apid_to_ppid[apid] = spec.slave << 8 | spec.per;
+
+	/* Keep track of {max,min}_apid for bounding search during interrupt */
+	if (apid > pa->max_apid)
+		pa->max_apid = apid;
+	if (apid < pa->min_apid)
+		pa->min_apid = apid;

Ah makes sense now why we set this to the opposite values in probe. Please put a comment in patch 4 and maybe move that setup in patch 4 to this patch.

Quoted 12 lines
drivers/spmi/spmi-pmic-arb.c +12 -0
+
+	*out_hwirq = spec.slave << 24
+		   | spec.per   << 16
+		   | spec.irq   << 8
+		   | apid;
+	*out_type  = intspec[3] & IRQ_TYPE_SENSE_MASK;
+
+	dev_dbg(&pa->spmic->dev, "out_hwirq = %lu\n", *out_hwirq);
+
+	return 0;
+}
+

[...]

Quoted 31 lines

static int spmi_pmic_arb_probe(struct platform_device *pdev) {

drivers/spmi/spmi-pmic-arb.c +8 -1
 	struct spmi_pmic_arb_dev *pa;
 	struct spmi_controller *ctrl;
 	struct resource *res;
-	int err, i;
+	int err = 0, i;
 
 	ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*pa));
 	if (!ctrl)
 		return -ENOMEM;
 
 	pa = spmi_controller_get_drvdata(ctrl);
+	pa->spmic = ctrl;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
 	pa->base = devm_ioremap_resource(&ctrl->dev, res);
@@ -349,6 +679,12 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 		goto err_put_ctrl;
 	}
 
+	pa->irq = platform_get_irq(pdev, 0);
+	if (pa->irq < 0) {
+		err = pa->irq;
+		goto err_put_ctrl;
+	}
+
 	for (i = 0; i < ARRAY_SIZE(pa->mapping_table); ++i)
 		pa->mapping_table[i] = readl_relaxed(
 				pa->cnfg + SPMI_MAPPING_TABLE_REG(i));

drivers/spmi/spmi-pmic-arb.c static int spmi_pmic_arb_probe(struct platform_device *pdev) · line 708

Quoted 9 lines
drivers/spmi/spmi-pmic-arb.c +6 -0
@@ -364,15 +700,30 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 	ctrl->read_cmd = pmic_arb_read_cmd;
 	ctrl->write_cmd = pmic_arb_write_cmd;
 
+	dev_dbg(&pdev->dev, "adding irq domain\n");
+	pa->domain = irq_domain_add_tree(pdev->dev.of_node,
+					 &pmic_arb_irq_domain_ops, pa);
+	if (!pa->domain) {
+		dev_err(&pdev->dev, "unable to create irq_domain\n");
+		goto err_put_ctrl;

Why do we silently ignore the error here? Is the irqchip functionality optional? Setting err here should allow us to skip intializing err to 0 up at the top of this function.

Quoted 22 lines
drivers/spmi/spmi-pmic-arb.c +10 -1
+	}
+
+	irq_set_handler_data(pa->irq, pa);
+	irq_set_chained_handler(pa->irq, pmic_arb_chained_irq);
+
 	err = spmi_controller_add(ctrl);
 	if (err)
-		goto err_put_ctrl;
+		goto err_domain_remove;
 
 	dev_dbg(&ctrl->dev, "PMIC Arb Version 0x%x\n",
 		pmic_arb_base_read(pa, PMIC_ARB_VERSION));
 
 	return 0;
 
+err_domain_remove:
+	irq_set_chained_handler(pa->irq, NULL);
+	irq_set_handler_data(pa->irq, NULL);
+	irq_domain_remove(pa->domain);
 err_put_ctrl:
 	spmi_controller_put(ctrl);
 	return err;
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#22 lore raw

Re: [PATCH v3 05/10] spmi: pmic_arb: add support for interrupt handling

Stephen-

Thanks for all the comments.

Quoted 15 lines · Stephen Boyd

drivers/spmi/spmi-pmic-arb.c struct spmi_pmic_arb_dev { · line 121

Quoted 12 lines · Josh Cartwright
drivers/spmi/spmi-pmic-arb.c +2 -0
@@ -108,12 +111,17 @@ struct spmi_pmic_arb_dev {
 	void __iomem		*base;
 	void __iomem		*intr;
 	void __iomem		*cnfg;
+	unsigned int		irq;
 	bool			allow_wakeup;
 	spinlock_t		lock;
 	u8			channel;
 	u8			min_apid;
 	u8			max_apid;
 	u32			mapping_table[SPMI_MAPPING_TABLE_LEN];
+	int			bus_nr;

This looks unused.

Indeed, will remove (I think this is a holdout from the split qpnpint handling that exists in the vendor tree).

Quoted 7 lines
Quoted 6 lines
drivers/spmi/spmi-pmic-arb.c +3 -0
+	struct irq_domain	*domain;
+	struct spmi_controller	*spmic;
+	u16			apid_to_ppid[256];
 };
 
 static inline u32 pmic_arb_base_read(struct spmi_pmic_arb_dev *dev, u32 offset)

[...]

Quoted 12 lines

drivers/spmi/spmi-pmic-arb.c static int pmic_arb_write_cmd(struct spmi_controller *ctrl, · line 397

Quoted 10 lines
drivers/spmi/spmi-pmic-arb.c +10 -0
+
+static void pmic_arb_chained_irq(unsigned int irq, struct irq_desc *desc)
+{
+	struct spmi_pmic_arb_dev *pa = irq_get_handler_data(irq);
+	struct irq_chip *chip = irq_get_chip(irq);
+	void __iomem *intr = pa->intr;
+	int first = pa->min_apid >> 5;
+	int last = pa->max_apid >> 5;
+	int i, id;
+	u8 ee = 0; /*pa->owner;*/

TODO?

Indeed, I removed this for some reason awhile back, but this really should be put back into place, and the EE should be a required property in the bindings.

[..]

Quoted 34 lines
Quoted 34 lines
drivers/spmi/spmi-pmic-arb.c +34 -0
+static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
+					   struct device_node *controller,
+					   const u32 *intspec,
+					   unsigned int intsize,
+					   unsigned long *out_hwirq,
+					   unsigned int *out_type)
+{
+	struct spmi_pmic_arb_dev *pa = d->host_data;
+	struct spmi_pmic_arb_irq_spec spec;
+	int err;
+	u8 apid;
+
+	dev_dbg(&pa->spmic->dev,
+		"intspec[0] 0x%1x intspec[1] 0x%02x intspec[2] 0x%02x\n",
+		intspec[0], intspec[1], intspec[2]);
+
+	if (d->of_node != controller)
+		return -EINVAL;
+	if (intsize != 4)
+		return -EINVAL;
+	if (intspec[0] > 0xF || intspec[1] > 0xFF || intspec[2] > 0x7)
+		return -EINVAL;
+
+	spec.slave = intspec[0];
+	spec.per   = intspec[1];
+	spec.irq   = intspec[2];
+
+	err = search_mapping_table(pa, &spec, &apid);
+	if (err)
+		return err;
+
+	pa->apid_to_ppid[apid] = spec.slave << 8 | spec.per;
+
+	/* Keep track of {max,min}_apid for bounding search during interrupt */
Quoted 8 lines

drivers/spmi/spmi-pmic-arb.c static int pmic_arb_write_cmd(struct spmi_controller *ctrl, · line 611

Quoted 4 lines
drivers/spmi/spmi-pmic-arb.c +4 -0
+	if (apid > pa->max_apid)
+		pa->max_apid = apid;
+	if (apid < pa->min_apid)
+		pa->min_apid = apid;

Ah makes sense now why we set this to the opposite values in probe. Please put a comment in patch 4 and maybe move that setup in patch 4 to this patch.

Indeed, I'll move it and add a comment at init-time.

Quoted 47 lines
Quoted 12 lines
drivers/spmi/spmi-pmic-arb.c +12 -0
+
+	*out_hwirq = spec.slave << 24
+		   | spec.per   << 16
+		   | spec.irq   << 8
+		   | apid;
+	*out_type  = intspec[3] & IRQ_TYPE_SENSE_MASK;
+
+	dev_dbg(&pa->spmic->dev, "out_hwirq = %lu\n", *out_hwirq);
+
+	return 0;
+}
+

[...]

Quoted 34 lines

static int spmi_pmic_arb_probe(struct platform_device *pdev) {

drivers/spmi/spmi-pmic-arb.c +8 -1
 	struct spmi_pmic_arb_dev *pa;
 	struct spmi_controller *ctrl;
 	struct resource *res;
-	int err, i;
+	int err = 0, i;
 
 	ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*pa));
 	if (!ctrl)
 		return -ENOMEM;
 
 	pa = spmi_controller_get_drvdata(ctrl);
+	pa->spmic = ctrl;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
 	pa->base = devm_ioremap_resource(&ctrl->dev, res);
@@ -349,6 +679,12 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 		goto err_put_ctrl;
 	}
 
+	pa->irq = platform_get_irq(pdev, 0);
+	if (pa->irq < 0) {
+		err = pa->irq;
+		goto err_put_ctrl;
+	}
+
 	for (i = 0; i < ARRAY_SIZE(pa->mapping_table); ++i)
 		pa->mapping_table[i] = readl_relaxed(
 				pa->cnfg + SPMI_MAPPING_TABLE_REG(i));
@@ -364,15 +700,30 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
 	ctrl->read_cmd = pmic_arb_read_cmd;
 	ctrl->write_cmd = pmic_arb_write_cmd;
 
Quoted 10 lines

drivers/spmi/spmi-pmic-arb.c static int spmi_pmic_arb_probe(struct platform_device *pdev) · line 708

Quoted 6 lines
drivers/spmi/spmi-pmic-arb.c +6 -0
+	dev_dbg(&pdev->dev, "adding irq domain\n");
+	pa->domain = irq_domain_add_tree(pdev->dev.of_node,
+					 &pmic_arb_irq_domain_ops, pa);
+	if (!pa->domain) {
+		dev_err(&pdev->dev, "unable to create irq_domain\n");
+		goto err_put_ctrl;

Why do we silently ignore the error here? Is the irqchip functionality optional? Setting err here should allow us to skip intializing err to 0 up at the top of this function.

Nice catch, it wasn't my intent to ignore it.

Thanks again,
Josh

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#23 lore raw

PATCH v3 6/10 spmi: document the PMIC arbiter SPMI bindings

In reply to Josh Cartwright
---
 .../bindings/spmi/qcom,spmi-pmic-arb.txt           | 42 ++++++++++++++++++++++
 1 file changed, 42 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt
Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt new file +42 -0
new file mode 100644
index 0000000..68949aa
@@ -0,0 +1,42 @@
+Qualcomm SPMI Controller (PMIC Arbiter)
+
+The SPMI PMIC Arbiter is found on the Snapdragon 800 Series.  It is an SPMI
+controller with wrapping arbitration logic to allow for multiple on-chip
+devices to control a single SPMI master.
+
+The PMIC Arbiter can also act as an interrupt controller, providing interrupts
+to slave devices.
+
+See spmi.txt for the generic SPMI controller binding requirements for child
+nodes.
+
+Required properties:
+- compatible : should be "qcom,spmi-pmic-arb".
+- reg-names  : should be "core", "intr", "cnfg"
+- reg : offset and length of the PMIC Arbiter Core register map.
+- reg : offset and length of the PMIC Arbiter Interrupt controller register map.
+- reg : offset and length of the PMIC Arbiter Configuration register map.
+- #address-cells : must be set to 1
+- #size-cells : must be set to 0
+- interrupt-controller : indicates the PMIC arbiter is an interrupt controller
+- #interrupt-cells = <4>:  interrupts are specified as a 4-tuple:
+    cell 1: slave ID for the requested interrupt (0-15)
+    cell 2: peripheral ID for requested interrupt (0-255)
+    cell 3: the requested peripheral interrupt (0-7)
+    cell 4: interrupt flags indicating level-sense information, as defined in
+            dt-bindings/interrupt-controller/irq.h
+
+Example:
+
+	qcom,spmi at fc4c0000 {
+		compatible = "qcom,spmi-pmic-arb";
+		reg-names = "core", "intr", "cnfg";
+		reg = <0xfc4cf000 0x1000>,
+		      <0Xfc4cb000 0x1000>,
+		      <0Xfc4ca000 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		interrupt-controller;
+		#interrupt-cells = <4>;
+	};
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#24 lore raw

Re: [PATCH v3 06/10] spmi: document the PMIC arbiter SPMI bindings

Hi Josh,

Quoted 21 lines · Josh Cartwright
---
 .../bindings/spmi/qcom,spmi-pmic-arb.txt           | 42 ++++++++++++++++++++++
 1 file changed, 42 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt
Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt new file +9 -0
new file mode 100644
index 0000000..68949aa
@@ -0,0 +1,42 @@
+Qualcomm SPMI Controller (PMIC Arbiter)
+
+The SPMI PMIC Arbiter is found on the Snapdragon 800 Series.  It is an SPMI
+controller with wrapping arbitration logic to allow for multiple on-chip
+devices to control a single SPMI master.
+
+The PMIC Arbiter can also act as an interrupt controller, providing interrupts
+to slave devices.
+

Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt line 19

Quoted 10 lines
Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt new file +10 -0
+See spmi.txt for the generic SPMI controller binding requirements for child
+nodes.
+
+Required properties:
+- compatible : should be "qcom,spmi-pmic-arb".
+- reg-names  : should be "core", "intr", "cnfg"
+- reg : offset and length of the PMIC Arbiter Core register map.
+- reg : offset and length of the PMIC Arbiter Interrupt controller register map.
+- reg : offset and length of the PMIC Arbiter Configuration register map.
+- #address-cells : must be set to 1

This doesn't seem to follow generic set of bindings for the SPMI controllers. #address-cells : must be set to 2.

Regards,
Ivan

Quoted 23 lines
Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt new file +23 -0
+- #size-cells : must be set to 0
+- interrupt-controller : indicates the PMIC arbiter is an interrupt controller
+- #interrupt-cells = <4>:  interrupts are specified as a 4-tuple:
+    cell 1: slave ID for the requested interrupt (0-15)
+    cell 2: peripheral ID for requested interrupt (0-255)
+    cell 3: the requested peripheral interrupt (0-7)
+    cell 4: interrupt flags indicating level-sense information, as defined in
+            dt-bindings/interrupt-controller/irq.h
+
+Example:
+
+	qcom,spmi at fc4c0000 {
+		compatible = "qcom,spmi-pmic-arb";
+		reg-names = "core", "intr", "cnfg";
+		reg = <0xfc4cf000 0x1000>,
+		      <0Xfc4cb000 0x1000>,
+		      <0Xfc4ca000 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		interrupt-controller;
+		#interrupt-cells = <4>;
+	};
#25 lore raw

Re: [PATCH v3 06/10] spmi: document the PMIC arbiter SPMI bindings

Quoted 27 lines · Ivan T. Ivanov
Quoted 26 lines · Josh Cartwright
---
 .../bindings/spmi/qcom,spmi-pmic-arb.txt           | 42 ++++++++++++++++++++++
 1 file changed, 42 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt
Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt new file +14 -0
new file mode 100644
index 0000000..68949aa
@@ -0,0 +1,42 @@
+Qualcomm SPMI Controller (PMIC Arbiter)
+
+The SPMI PMIC Arbiter is found on the Snapdragon 800 Series.  It is an SPMI
+controller with wrapping arbitration logic to allow for multiple on-chip
+devices to control a single SPMI master.
+
+The PMIC Arbiter can also act as an interrupt controller, providing interrupts
+to slave devices.
+
+See spmi.txt for the generic SPMI controller binding requirements for child
+nodes.
+
+Required properties:
+- compatible : should be "qcom,spmi-pmic-arb".
Quoted 8 lines

Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt line 19

Quoted 5 lines
Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt new file +5 -0
+- reg-names  : should be "core", "intr", "cnfg"
+- reg : offset and length of the PMIC Arbiter Core register map.
+- reg : offset and length of the PMIC Arbiter Interrupt controller register map.
+- reg : offset and length of the PMIC Arbiter Configuration register map.
+- #address-cells : must be set to 1

This doesn't seem to follow generic set of bindings for the SPMI controllers. #address-cells : must be set to 2.

Indeed, good catch. I'll fix it up.

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#26 lore raw

PATCH v3 7/10 regmap: add SPMI support

In reply to Josh Cartwright

Add basic support for the System Power Management Interface (SPMI) bus. This is a simple implementation which only implements register accesses via the Extended Register Read/Write Long commands.

---
 drivers/base/regmap/Kconfig       |  5 ++-
 drivers/base/regmap/Makefile      |  1 +
 drivers/base/regmap/regmap-spmi.c | 90 +++++++++++++++++++++++++++++++++++++++
 include/linux/regmap.h            |  5 +++
 4 files changed, 100 insertions(+), 1 deletion(-)
 create mode 100644 drivers/base/regmap/regmap-spmi.c
drivers/base/regmap/Kconfig +4 -1
index f0d3054..4251570 100644
@@ -3,7 +3,7 @@
 # subsystems should select the appropriate symbols.
 
 config REGMAP
-	default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_MMIO || REGMAP_IRQ)
+	default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_MMIO || REGMAP_IRQ)
 	select LZO_COMPRESS
 	select LZO_DECOMPRESS
 	select IRQ_DOMAIN if REGMAP_IRQ
@@ -15,6 +15,9 @@ config REGMAP_I2C
 config REGMAP_SPI
 	tristate
 
+config REGMAP_SPMI
+	tristate
+
 config REGMAP_MMIO
 	tristate
 
drivers/base/regmap/Makefile +1 -0
index cf12998..a7c670b 100644
@@ -3,5 +3,6 @@ obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o
 obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
 obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
 obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
+obj-$(CONFIG_REGMAP_SPMI) += regmap-spmi.o
 obj-$(CONFIG_REGMAP_MMIO) += regmap-mmio.o
 obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o
drivers/base/regmap/regmap-spmi.c new file +90 -0

90 lines not on this page · raw message

include/linux/regmap.h +5 -0
index a10380b..3f5abc8 100644
@@ -23,6 +23,7 @@ struct device;
 struct i2c_client;
 struct irq_domain;
 struct spi_device;
+struct spmi_device;
 struct regmap;
 struct regmap_range_cfg;
 struct regmap_field;
@@ -318,6 +319,8 @@ struct regmap *regmap_init_i2c(struct i2c_client *i2c,
 			       const struct regmap_config *config);
 struct regmap *regmap_init_spi(struct spi_device *dev,
 			       const struct regmap_config *config);
+struct regmap *regmap_init_spmi(struct spmi_device *dev,
+			       const struct regmap_config *config);
 struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id,
 				    void __iomem *regs,
 				    const struct regmap_config *config);
@@ -330,6 +333,8 @@ struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c,
 				    const struct regmap_config *config);
 struct regmap *devm_regmap_init_spi(struct spi_device *dev,
 				    const struct regmap_config *config);
+struct regmap *devm_regmap_init_spmi(struct spmi_device *dev,
+				     const struct regmap_config *config);
 struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id,
 					 void __iomem *regs,
 					 const struct regmap_config *config);
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
maintainer
#27 lore raw

Re: [PATCH v3 07/10] regmap: add SPMI support

Quoted 3 lines · Josh Cartwright

Add basic support for the System Power Management Interface (SPMI) bus. This is a simple implementation which only implements register accesses via the Extended Register Read/Write Long commands.

This looks good - I've applied it on the assumption that the underlying interfaces won't change and the suspicion that it'll be after the merge window before users get merged. However I did provide a tag at:

git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git tags/spmi

which I'm happy to see pulled into any tree that requires it. I can
drop the patch for now if there would be a problem with getting it in
during the merge window.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20131028/70fffb8a/attachment.sig>

#28 lore raw

PATCH v3 8/10 mfd: pm8x41: add support for Qualcomm 8x41 PMICs

In reply to Josh Cartwright

The Qualcomm 8941 and 8841 PMICs are components used with the Snapdragon 800 series SoC family. This driver exists largely as a glue mfd component, it exists to be an owner of an SPMI regmap for children devices described in device tree.

---
 drivers/mfd/Kconfig  | 10 ++++++++
 drivers/mfd/Makefile |  1 +
 drivers/mfd/pm8x41.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 75 insertions(+)
 create mode 100644 drivers/mfd/pm8x41.c
drivers/mfd/Kconfig +10 -0
index 914c3d1..0a288cb 100644
@@ -476,6 +476,16 @@ config MFD_PM8XXX_IRQ
 	  This is required to use certain other PM 8xxx features, such as GPIO
 	  and MPP.
 
+config MFD_PM8X41
+	bool "Qualcomm PM8X41 PMIC"
+	depends on ARCH_MSM
+	select REGMAP_SPMI
+	help
+	  This enables basic support for the Qualcomm 8941 and 8841 PMICs.  These
+	  PMICs are currently used with the Snapdragon 800 series of SoCs.  Note, that
+	  this will only be useful paired with descriptions of the independent functions
+	  as children nodes in the device tree.
+
 config MFD_RDC321X
 	tristate "RDC R-321x southbridge"
 	select MFD_CORE
drivers/mfd/Makefile +1 -0
index 15b905c..ee4d338 100644
@@ -149,6 +149,7 @@ obj-$(CONFIG_MFD_CS5535)	+= cs5535-mfd.o
 obj-$(CONFIG_MFD_OMAP_USB_HOST)	+= omap-usb-host.o omap-usb-tll.o
 obj-$(CONFIG_MFD_PM8921_CORE) 	+= pm8921-core.o ssbi.o
 obj-$(CONFIG_MFD_PM8XXX_IRQ) 	+= pm8xxx-irq.o
+obj-$(CONFIG_MFD_PM8X41)	+= pm8x41.o
 obj-$(CONFIG_TPS65911_COMPARATOR)	+= tps65911-comparator.o
 obj-$(CONFIG_MFD_TPS65090)	+= tps65090.o
 obj-$(CONFIG_MFD_AAT2870_CORE)	+= aat2870-core.o
drivers/mfd/pm8x41.c new file +64 -0

64 lines not on this page · raw message

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#29 lore raw

Re: [PATCH v3 08/10] mfd: pm8x41: add support for Qualcomm 8x41 PMICs

drivers/mfd/Kconfig config MFD_PM8XXX_IRQ · line 480

Quoted 10 lines · Josh Cartwright
drivers/mfd/Kconfig +2 -0
index 914c3d1..0a288cb 100644
@@ -476,6 +476,16 @@ config MFD_PM8XXX_IRQ
 	  This is required to use certain other PM 8xxx features, such as GPIO
 	  and MPP.
 
+config MFD_PM8X41
+	bool "Qualcomm PM8X41 PMIC"

Can this be tristate?

drivers/mfd/Kconfig config MFD_PM8XXX_IRQ · line 481

Quoted 1 line
drivers/mfd/Kconfig +1 -0
+	depends on ARCH_MSM

It would be nice if we didn't have to depend on ARCH_MSM so we get some more build coverage but the driver is so simple it probably doesn't matter.

Quoted 16 lines
drivers/mfd/Kconfig +7 -0
+	select REGMAP_SPMI
+	help
+	  This enables basic support for the Qualcomm 8941 and 8841 PMICs.  These
+	  PMICs are currently used with the Snapdragon 800 series of SoCs.  Note, that
+	  this will only be useful paired with descriptions of the independent functions
+	  as children nodes in the device tree.
+
 config MFD_RDC321X
 	tristate "RDC R-321x southbridge"
 	select MFD_CORE
drivers/mfd/pm8x41.c renamed from dev/nullalso +0 -0
new file mode 100644
index 0000000..0a57221
@@ -0,0 +1,64 @@

[...]

Quoted 5 lines
drivers/mfd/pm8x41.c renamed from dev/nullalso +5 -0
+
+static int pm8x41_probe(struct spmi_device *sdev)
+{
+	struct regmap *regmap;
+

drivers/mfd/pm8x41.c line 49

Quoted 10 lines
drivers/mfd/pm8x41.c renamed from dev/nullalso +10 -0
+	regmap = devm_regmap_init_spmi(sdev, &pm8x41_regmap_config);
+	if (IS_ERR(regmap)) {
+		dev_dbg(&sdev->dev, "regmap creation failed.\n");
+		return PTR_ERR(regmap);
+	}
+
+	return of_platform_populate(sdev->dev.of_node, NULL, NULL, &sdev->dev);
+}
+
+static struct of_device_id pm8x41_id_table[] = {

const?

Quoted 6 lines
drivers/mfd/pm8x41.c renamed from dev/nullalso +5 -0
+	{ "qcom,pm8841", },
+	{ "qcom,pm8941", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, pm8x41_id_table);
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#30 lore raw

Re: [PATCH v3 08/10] mfd: pm8x41: add support for Qualcomm 8x41 PMICs

In reply to Josh Cartwright
Quoted 10 lines · Josh Cartwright

The Qualcomm 8941 and 8841 PMICs are components used with the Snapdragon 800 series SoC family. This driver exists largely as a glue mfd component, it exists to be an owner of an SPMI regmap for children devices described in device tree.

---
 drivers/mfd/Kconfig  | 10 ++++++++
 drivers/mfd/Makefile |  1 +
 drivers/mfd/pm8x41.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++

Can you CC me on your next submission, or it may not get applied.

Signature · 4 lines
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
#31 lore raw

Re: [PATCH v3 08/10] mfd: pm8x41: add support for Qualcomm 8x41 PMICs

Quoted 7 lines · Lee Jones
Quoted 5 lines · Josh Cartwright

The Qualcomm 8941 and 8841 PMICs are components used with the Snapdragon 800 series SoC family. This driver exists largely as a glue mfd component, it exists to be an owner of an SPMI regmap for children devices described in device tree.

Quoted 7 lines
Quoted 5 lines
---
 drivers/mfd/Kconfig  | 10 ++++++++
 drivers/mfd/Makefile |  1 +
 drivers/mfd/pm8x41.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++

Can you CC me on your next submission, or it may not get applied.

Certainly. Sorry about that.

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#32 lore raw

PATCH v3 9/10 mfd: pm8x41: document device tree bindings

In reply to Josh Cartwright

Document the bindings used to describe the Qualcomm 8x41 PMICs.

---
 Documentation/devicetree/bindings/mfd/pm8x41.txt | 33 ++++++++++++++++++++++++
 1 file changed, 33 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/pm8x41.txt
Documentation/devicetree/bindings/mfd/pm8x41.txt new file +33 -0
new file mode 100644
index 0000000..6afd4ce
@@ -0,0 +1,33 @@
+Qualcomm PM8841 and PM8941 PMIC multi-function devices
+
+The PM8x41 PMICs are used with the Qualcomm Snapdragon 800 series SoCs, and are
+interfaced to the chip via the SPMI (System Power Management Interface) bus.
+Support for  multiple independent functions are implemented by splitting the
+16-bit SPMI slave address space into 256 smaller fixed-size regions, 256 bytes
+each.  A function can consume one or more of these fixed-size register regions.
+
+Required properties:
+- compatible: Must be one of:
+     "qcom,pm8841"
+     "qcom,pm8941"
+- reg: Specifies the SPMI USID slave address for this device
+- #address-cells = <1>
+- #size-cells = <0>
+
+Each child node represents a function of the PM8x41.  Each child 'reg' entry
+describes an offset within the USID slave address where the region starts.
+
+Example:
+
+pm8941 at 0 {
+	compatible = "qcom,pm8941";
+	reg = <0x0>;
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	rtc {
+		compatible = "qcom,pm8941-rtc";
+		reg = <0x6000 0x6100>;
+	};
+}
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#33 lore raw

Re: [PATCH v3 09/10] mfd: pm8x41: document device tree bindings

Hi Josh,

Quoted 35 lines · Josh Cartwright

Document the bindings used to describe the Qualcomm 8x41 PMICs.

---
 Documentation/devicetree/bindings/mfd/pm8x41.txt | 33 ++++++++++++++++++++++++
 1 file changed, 33 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/pm8x41.txt
Documentation/devicetree/bindings/mfd/pm8x41.txt new file +21 -0
new file mode 100644
index 0000000..6afd4ce
@@ -0,0 +1,33 @@
+Qualcomm PM8841 and PM8941 PMIC multi-function devices
+
+The PM8x41 PMICs are used with the Qualcomm Snapdragon 800 series SoCs, and are
+interfaced to the chip via the SPMI (System Power Management Interface) bus.
+Support for  multiple independent functions are implemented by splitting the
+16-bit SPMI slave address space into 256 smaller fixed-size regions, 256 bytes
+each.  A function can consume one or more of these fixed-size register regions.
+
+Required properties:
+- compatible: Must be one of:
+     "qcom,pm8841"
+     "qcom,pm8941"
+- reg: Specifies the SPMI USID slave address for this device
+- #address-cells = <1>
+- #size-cells = <0>
+
+Each child node represents a function of the PM8x41.  Each child 'reg' entry
+describes an offset within the USID slave address where the region starts.
+
+Example:
+

Documentation/devicetree/bindings/mfd/pm8x41.txt line 31

Quoted 10 lines
Documentation/devicetree/bindings/mfd/pm8x41.txt new file +10 -0
+pm8941 at 0 {
+	compatible = "qcom,pm8941";
+	reg = <0x0>;
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	rtc {
+		compatible = "qcom,pm8941-rtc";
+		reg = <0x6000 0x6100>;

This doesn't look right. Probably #size-cells have to be <1>?

Regards,
Ivan

Quoted 2 lines
Documentation/devicetree/bindings/mfd/pm8x41.txt new file +2 -0
+	};
+}
#34 lore raw

Re: [PATCH v3 09/10] mfd: pm8x41: document device tree bindings

Quoted 40 lines · Ivan T. Ivanov
Quoted 39 lines · Josh Cartwright

Document the bindings used to describe the Qualcomm 8x41 PMICs.

---
 Documentation/devicetree/bindings/mfd/pm8x41.txt | 33 ++++++++++++++++++++++++
 1 file changed, 33 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/pm8x41.txt
Documentation/devicetree/bindings/mfd/pm8x41.txt new file +25 -0
new file mode 100644
index 0000000..6afd4ce
@@ -0,0 +1,33 @@
+Qualcomm PM8841 and PM8941 PMIC multi-function devices
+
+The PM8x41 PMICs are used with the Qualcomm Snapdragon 800 series SoCs, and are
+interfaced to the chip via the SPMI (System Power Management Interface) bus.
+Support for  multiple independent functions are implemented by splitting the
+16-bit SPMI slave address space into 256 smaller fixed-size regions, 256 bytes
+each.  A function can consume one or more of these fixed-size register regions.
+
+Required properties:
+- compatible: Must be one of:
+     "qcom,pm8841"
+     "qcom,pm8941"
+- reg: Specifies the SPMI USID slave address for this device
+- #address-cells = <1>
+- #size-cells = <0>
+
+Each child node represents a function of the PM8x41.  Each child 'reg' entry
+describes an offset within the USID slave address where the region starts.
+
+Example:
+
+pm8941 at 0 {
+	compatible = "qcom,pm8941";
+	reg = <0x0>;
+
Quoted 8 lines

Documentation/devicetree/bindings/mfd/pm8x41.txt line 31

Quoted 6 lines
Documentation/devicetree/bindings/mfd/pm8x41.txt new file +6 -0
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	rtc {
+		compatible = "qcom,pm8941-rtc";
+		reg = <0x6000 0x6100>;

This doesn't look right. Probably #size-cells have to be <1>?

Some functions of the PMIC actually consume more than one fixed-size region of the slave address space. This example is showing one such peripheral (consuming the region starting at 0x6000 and another at 0x6100).

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#35 lore raw

Re: [PATCH v3 09/10] mfd: pm8x41: document device tree bindings

Hi,

Quoted 50 lines · Josh Cartwright
Quoted 40 lines · Ivan T. Ivanov
Quoted 39 lines · Josh Cartwright

Document the bindings used to describe the Qualcomm 8x41 PMICs.

---
 Documentation/devicetree/bindings/mfd/pm8x41.txt | 33 ++++++++++++++++++++++++
 1 file changed, 33 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/pm8x41.txt
Documentation/devicetree/bindings/mfd/pm8x41.txt new file +25 -0
new file mode 100644
index 0000000..6afd4ce
@@ -0,0 +1,33 @@
+Qualcomm PM8841 and PM8941 PMIC multi-function devices
+
+The PM8x41 PMICs are used with the Qualcomm Snapdragon 800 series SoCs, and are
+interfaced to the chip via the SPMI (System Power Management Interface) bus.
+Support for  multiple independent functions are implemented by splitting the
+16-bit SPMI slave address space into 256 smaller fixed-size regions, 256 bytes
+each.  A function can consume one or more of these fixed-size register regions.
+
+Required properties:
+- compatible: Must be one of:
+     "qcom,pm8841"
+     "qcom,pm8941"
+- reg: Specifies the SPMI USID slave address for this device
+- #address-cells = <1>
+- #size-cells = <0>
+
+Each child node represents a function of the PM8x41.  Each child 'reg' entry
+describes an offset within the USID slave address where the region starts.
+
+Example:
+
+pm8941 at 0 {
+	compatible = "qcom,pm8941";
+	reg = <0x0>;
+
Quoted 8 lines

Documentation/devicetree/bindings/mfd/pm8x41.txt line 31

Quoted 6 lines
Documentation/devicetree/bindings/mfd/pm8x41.txt new file +6 -0
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	rtc {
+		compatible = "qcom,pm8941-rtc";
+		reg = <0x6000 0x6100>;

This doesn't look right. Probably #size-cells have to be <1>?

Quoted 5 lines

Some functions of the PMIC actually consume more than one fixed-size region of the slave address space. This example is showing one such peripheral (consuming the region starting at 0x6000 and another at 0x6100).

Ok. Thanks for clarification.

Regards,
Ivan

#36 lore raw

PATCH v3 10/10 rtc: pm8xxx: add support for pm8941

In reply to Josh Cartwright

Adapt the existing pm8xxx driver to work with the RTC available on Qualcomm's 8941 PMIC. In order to do this, rework the register access functions to use a regmap provided by the parent driver. Account for slight differences in the RTC address space by parameterizing addresses and providing a chip-specific initialization function.

---
 drivers/rtc/Kconfig      |   1 -
 drivers/rtc/rtc-pm8xxx.c | 229 +++++++++++++++++++++++++++++------------------
 2 files changed, 143 insertions(+), 87 deletions(-)
drivers/rtc/Kconfig +0 -1
index 9654aa3..19b89ee 100644
@@ -1177,7 +1177,6 @@ config RTC_DRV_LPC32XX
 
 config RTC_DRV_PM8XXX
 	tristate "Qualcomm PMIC8XXX RTC"
-	depends on MFD_PM8XXX
 	help
 	  If you say yes here you get support for the
 	  Qualcomm PMIC8XXX RTC.
drivers/rtc/rtc-pm8xxx.c +143 -86

364 lines not on this page · raw message

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#37 lore raw

Re: [PATCH v3 10/10] rtc: pm8xxx: add support for pm8941

drivers/rtc/rtc-pm8xxx.c line 3

Quoted 8 lines · Josh Cartwright
drivers/rtc/rtc-pm8xxx.c +1 -0
index 03f8f75..a9044d4 100644
@@ -1,4 +1,5 @@
 /* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
  *

Please rewrite this as '2010-2011,2013, The Linux Foundation'

Quoted 2 lines
drivers/rtc/rtc-pm8xxx.c +0 -0
  * 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
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#38 lore raw

Re: [PATCH v3 10/10] rtc: pm8xxx: add support for pm8941

Quoted 11 lines · Stephen Boyd

drivers/rtc/rtc-pm8xxx.c line 3

Quoted 8 lines · Josh Cartwright
drivers/rtc/rtc-pm8xxx.c +1 -0
index 03f8f75..a9044d4 100644
@@ -1,4 +1,5 @@
 /* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
  *

Please rewrite this as '2010-2011,2013, The Linux Foundation'

Has the Linux Foundation really taken on all prior copyrights of this codebase? CAF wasn't around in 2010 as part of the LF, so be careful here.

greg k-h

#39 lore raw

Re: [PATCH v3 10/10] rtc: pm8xxx: add support for pm8941

Quoted 11 lines · Greg Kroah-Hartman
Quoted 10 lines · Stephen Boyd

drivers/rtc/rtc-pm8xxx.c line 3

Quoted 8 lines · Josh Cartwright
drivers/rtc/rtc-pm8xxx.c +1 -0
index 03f8f75..a9044d4 100644
@@ -1,4 +1,5 @@
 /* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
  *

Please rewrite this as '2010-2011,2013, The Linux Foundation'

Quoted 6 lines

Has the Linux Foundation really taken on all prior copyrights of this codebase? CAF wasn't around in 2010 as part of the LF, so be careful here.

From what I recall our lawyers told us to do this and there is some

precedence for this upstream as well.

commit e1858b2a21cd84a855945a4747fb2db41b250c22

Author: Richard Kuo <[email protected]>
Date:   Wed Sep 19 16:22:02 2012 -0500

Hexagon: Copyright marking changes

Code Aurora Forum (CAF) is becoming a part of Linux Foundation Labs.

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#40 lore raw

Re: [PATCH v3 10/10] rtc: pm8xxx: add support for pm8941

Quoted 21 lines · Stephen Boyd
Quoted 11 lines · Greg Kroah-Hartman
Quoted 10 lines · Stephen Boyd

drivers/rtc/rtc-pm8xxx.c line 3

Quoted 8 lines · Josh Cartwright
drivers/rtc/rtc-pm8xxx.c +1 -0
index 03f8f75..a9044d4 100644
@@ -1,4 +1,5 @@
 /* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
  *

Please rewrite this as '2010-2011,2013, The Linux Foundation'

Quoted 6 lines

Has the Linux Foundation really taken on all prior copyrights of this codebase? CAF wasn't around in 2010 as part of the LF, so be careful here.

From what I recall our lawyers told us to do this and there is some

precedence for this upstream as well.

commit e1858b2a21cd84a855945a4747fb2db41b250c22

Quoted 8 lines
Author: Richard Kuo <[email protected]>
Date:   Wed Sep 19 16:22:02 2012 -0500

Hexagon: Copyright marking changes

Code Aurora Forum (CAF) is becoming a part of Linux Foundation Labs.

Ok, fair enough, I was not aware of this.

sorry for the noise,

greg k-h