Add support for the System Power Management Interface (SPMI)
Subsystems (8)
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
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
@@ -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
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_OFis disabled.Signed-off-by Sylwester Nawrocki <[email protected]>Signed-off-by Kyungmin Park <[email protected]>
I'm assuming the rest of this is not going to make 3.13, so I've applied this for 3.13.
Rob
PATCH v3 2/10 spmi: Linux driver framework for SPMI
In reply to Josh CartwrightFrom: 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
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.
Signed-off-by Kenneth Heitke <[email protected]>Signed-off-by Michael Bohan <[email protected]>Signed-off-by Josh Cartwright <[email protected]>--- 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
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.
Signed-off-by Kenneth Heitke <[email protected]>Signed-off-by Michael Bohan <[email protected]>Signed-off-by Josh Cartwright <[email protected]>
[..]
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
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.
Signed-off-by Kenneth Heitke <[email protected]>Signed-off-by Michael Bohan <[email protected]>Signed-off-by Josh Cartwright <[email protected]>[..]
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
Re: [PATCH v3 02/10] spmi: Linux driver framework for SPMI
In reply to Josh CartwrightCouple 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
[...]
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 bothdev->driveranddev->driver->pmand 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 bothdevice_del()andput_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_opsjust 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
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
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
Re: [PATCH v3 02/10] spmi: Linux driver framework for SPMI
In reply to Josh CartwrightQuoted 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 bothdevice_del()andput_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'srelease()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.
Re: [PATCH v3 02/10] spmi: Linux driver framework for SPMI
In reply to Josh Cartwrightdrivers/spmi/Kconfig line 5
Quoted 11 lines · Josh Cartwright
drivers/spmi/Kconfig new file +5
-0@@ -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@@ -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@@ -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
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@@ -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@@ -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_typespmi_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
0x1fshould 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@@ -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 0x1Binclude/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 controllerThere 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 readThis 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
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
0x1fshould be a #define.Is
0x1Fwith 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
Re: [PATCH v3 02/10] spmi: Linux driver framework for SPMI
In reply to Josh CartwrightQuoted 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.
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
@@ -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
PATCH v3 4/10 spmi: Add MSM PMIC Arbiter SPMI controller
In reply to Josh CartwrightFrom: 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
@@ -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
@@ -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
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
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
__exitspmi_pmic_arb_remove(struct platform_device *pdev)
__exitshouldn'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
PATCH v3 5/10 spmi: pmic_arb: add support for interrupt handling
In reply to Josh CartwrightThe 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
@@ -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
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
-1struct 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
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
-1struct 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
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
@@ -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
Re: [PATCH v3 06/10] spmi: document the PMIC arbiter SPMI bindings
Hi Josh,
Quoted 21 lines · Josh Cartwright
Signed-off-by Josh Cartwright <[email protected]>--- .../bindings/spmi/qcom,spmi-pmic-arb.txt | 42 ++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txtDocumentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt new file +9
-0@@ -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>; + };
Re: [PATCH v3 06/10] spmi: document the PMIC arbiter SPMI bindings
Quoted 27 lines · Ivan T. Ivanov
Quoted 26 lines · Josh Cartwright
Signed-off-by Josh Cartwright <[email protected]>--- .../bindings/spmi/qcom,spmi-pmic-arb.txt | 42 ++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txtDocumentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt new file +14
-0@@ -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 1This 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
PATCH v3 7/10 regmap: add SPMI support
In reply to Josh CartwrightAdd 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
@@ -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
@@ -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
@@ -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
Mark Brown
maintainerRe: [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>
PATCH v3 8/10 mfd: pm8x41: add support for Qualcomm 8x41 PMICs
In reply to Josh CartwrightThe 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
@@ -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
@@ -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
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@@ -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_COREdrivers/mfd/pm8x41.c renamed from dev/nullalso +0
-0@@ -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
Re: [PATCH v3 08/10] mfd: pm8x41: add support for Qualcomm 8x41 PMICs
In reply to Josh CartwrightQuoted 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.
Signed-off-by Josh Cartwright <[email protected]>--- 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
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
Signed-off-by Josh Cartwright <[email protected]>--- 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
PATCH v3 9/10 mfd: pm8x41: document device tree bindings
In reply to Josh CartwrightDocument 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
@@ -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
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.
Signed-off-by Josh Cartwright <[email protected]>--- Documentation/devicetree/bindings/mfd/pm8x41.txt | 33 ++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/pm8x41.txtDocumentation/devicetree/bindings/mfd/pm8x41.txt new file +21
-0@@ -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+ }; +}
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.
Signed-off-by Josh Cartwright <[email protected]>--- Documentation/devicetree/bindings/mfd/pm8x41.txt | 33 ++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/pm8x41.txtDocumentation/devicetree/bindings/mfd/pm8x41.txt new file +25
-0@@ -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
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.
Signed-off-by Josh Cartwright <[email protected]>--- Documentation/devicetree/bindings/mfd/pm8x41.txt | 33 ++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/pm8x41.txtDocumentation/devicetree/bindings/mfd/pm8x41.txt new file +25
-0@@ -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
0x6000and another at0x6100).
Ok. Thanks for clarification.
Regards,
Ivan
PATCH v3 10/10 rtc: pm8xxx: add support for pm8941
In reply to Josh CartwrightAdapt 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
@@ -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
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@@ -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
Greg Kroah-Hartman
maintainerRe: [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@@ -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
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@@ -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
Greg Kroah-Hartman
maintainerRe: [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@@ -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 -0500Hexagon: Copyright marking changes
Code Aurora Forum (CAF) is becoming a part of Linux Foundation Labs.
Signed-off-by Richard Kuo <[email protected]>
Ok, fair enough, I was not aware of this.
sorry for the noise,
greg k-h