2016-10-06 09:12:51

by Steve Twiss

[permalink] [raw]
Subject: [PATCH V1 00/10] da9061: DA9061 driver submission

From: Steve Twiss <[email protected]>

This patch set adds support for the Dialog DA9061 Power Management IC.
Support is made by altering the existing DA9062 device driver.

In this patch set the following is provided:

[PATCH V1 01/10] MFD core support
[PATCH V1 02/10] BUCKs and LDOs
[PATCH V1 03/10] Onkey
[PATCH V1 04/10] Watchdog
[PATCH V1 05/10] PMIC temperature monitoring
[PATCH V1 06/10] Binding for onkey
[PATCH V1 07/10] Binding for watchdog
[PATCH V1 08/10] Binding for thermal supervisor
[PATCH V1 09/10] Binding for MFD and regulators
[PATCH V1 10/10] MAINTAINERS update

This patch applies against linux-next and v4.8

Thank you,
Steve Twiss, Dialog Semiconductor Ltd.

Steve Twiss (10):
mfd: da9061: MFD core support
regulator: da9061: BUCK and LDO regulator driver
Input: da9061: onkey driver
watchdog: da9061: watchdog driver
thermal: da9062/61: Thermal junction temperature monitoring driver
Documentation: dt: input: temperature driver
Documentation: dt: watchdog: da9062/61 Watchdog timer binding
Documentation: dt: thermal: da9062/61 TJUNC temperature binding
Documentation: dt: mfd: da9062/61 MFD binding
MAINTAINERS: da9062/61 updates to the Dialog Semiconductor search
terms

.../devicetree/bindings/input/da9062-onkey.txt | 19 +-
Documentation/devicetree/bindings/mfd/da9062.txt | 45 +-
.../devicetree/bindings/thermal/da9062-thermal.txt | 30 ++
.../devicetree/bindings/watchdog/da9062-wdt.txt | 11 +
MAINTAINERS | 4 +
drivers/input/misc/Kconfig | 7 +-
drivers/input/misc/da9063_onkey.c | 24 +-
drivers/mfd/Kconfig | 5 +-
drivers/mfd/da9062-core.c | 454 ++++++++++++++++++++-
drivers/regulator/Kconfig | 4 +-
drivers/regulator/da9062-regulator.c | 299 +++++++++++++-
drivers/thermal/Kconfig | 10 +
drivers/thermal/Makefile | 1 +
drivers/thermal/da9062-thermal.c | 313 ++++++++++++++
drivers/watchdog/Kconfig | 4 +-
drivers/watchdog/da9062_wdt.c | 24 +-
include/linux/mfd/da9062/core.h | 27 +-
include/linux/mfd/da9062/registers.h | 2 +
18 files changed, 1212 insertions(+), 71 deletions(-)
create mode 100644 Documentation/devicetree/bindings/thermal/da9062-thermal.txt
create mode 100644 Documentation/devicetree/bindings/watchdog/da9062-wdt.txt
create mode 100644 drivers/thermal/da9062-thermal.c

--
end-of-patch for PATCH V1


2016-10-06 09:09:37

by Steve Twiss

[permalink] [raw]
Subject: [PATCH V1 08/10] Documentation: dt: thermal: da9062/61 TJUNC temperature binding

From: Steve Twiss <[email protected]>

Device tree binding information for DA9062 and DA9061 thermal junction
temperature monitor.

Binding descriptions for the DA9061 and DA9062 thermal TJUNC supervisor
device driver, using a single THERMAL_TRIP_HOT trip-wire and allowing for a
configurable polling period for over-temperature polling.

Signed-off-by: Steve Twiss <[email protected]>

---
This patch applies against linux-next and v4.8

Hi,

This patch depends on the acceptance of the main code for the onkey:
[PATCH V1 5/10] thermal: da9061: TJUNC temperature driver

Regards,
Steve Twiss, Dialog Semiconductor Ltd.


.../devicetree/bindings/thermal/da9062-thermal.txt | 30 ++++++++++++++++++++++
1 file changed, 30 insertions(+)
create mode 100644 Documentation/devicetree/bindings/thermal/da9062-thermal.txt

diff --git a/Documentation/devicetree/bindings/thermal/da9062-thermal.txt b/Documentation/devicetree/bindings/thermal/da9062-thermal.txt
new file mode 100644
index 0000000..338de2f
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/da9062-thermal.txt
@@ -0,0 +1,30 @@
+* Dialog DA9062/61 TJUNC Thermal Module
+
+This module is part of the DA9061/DA9062. For more details about entire
+DA9062 and DA9061 chips see Documentation/devicetree/bindings/mfd/da9062.txt
+
+Junction temperature thermal module uses an interrupt signal to identify
+high THERMAL_TRIP_HOT temperatures for the PMIC device.
+
+Required properties:
+
+- compatible: should be one of:
+ dlg,da9061-thermal
+ dlg,da9062-thermal
+
+Optional properties:
+
+- dlg,tjunc-temp-polling-period-ms : Specify the polling period, measured
+ in milliseconds, between thermal zone device update checks.
+
+Example:
+
+ pmic0: da9062@58 {
+
+ thermal {
+ compatible = "dlg,da9062-thermal";
+ dlg,tjunc-temp-polling-period-ms = <3000>;
+ };
+
+ };
+
--
end-of-patch for PATCH V1

2016-10-06 09:09:42

by Steve Twiss

[permalink] [raw]
Subject: [PATCH V1 07/10] Documentation: dt: watchdog: da9062/61 Watchdog timer binding

From: Steve Twiss <[email protected]>

Add binding information for DA9062 and DA9061 watchdog.

Signed-off-by: Steve Twiss <[email protected]>

---
This patch applies against linux-next and v4.8

Hi,

This patch depends on the acceptance of DA9061 watchdog driver:
[PATCH V1 4/10] watchdog: da9061: watchdog driver

Regards,
Steve Twiss, Dialog Semiconductor Ltd.


Documentation/devicetree/bindings/watchdog/da9062-wdt.txt | 11 +++++++++++
1 file changed, 11 insertions(+)
create mode 100644 Documentation/devicetree/bindings/watchdog/da9062-wdt.txt

diff --git a/Documentation/devicetree/bindings/watchdog/da9062-wdt.txt b/Documentation/devicetree/bindings/watchdog/da9062-wdt.txt
new file mode 100644
index 0000000..eac0062
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/da9062-wdt.txt
@@ -0,0 +1,11 @@
+* Dialog Semiconductor DA9062/61 Watchdog Timer
+
+Required properties:
+- compatible: "dlg,da9062-watchdog"
+ "dlg,da9061-watchdog"
+
+Example:
+ watchdog {
+ compatible = "dlg,da9062-watchdog";
+ };
+
--
end-of-patch for PATCH V1

2016-10-06 09:09:51

by Steve Twiss

[permalink] [raw]
Subject: [PATCH V1 05/10] thermal: da9062/61: Thermal junction temperature monitoring driver

From: Steve Twiss <[email protected]>

Add junction temperature monitoring supervisor device driver, compatible
with the DA9062 and DA9061 PMICs.

If the PMIC's internal junction temperature rises above TEMP_WARN (125
degC) an interrupt is issued. This TEMP_WARN level is defined as the
THERMAL_TRIP_HOT trip-wire inside the device driver. A kernel work queue
is configured to repeatedly poll this temperature trip-wire, between 1 and
10 second intervals (defaulting at 3 seconds).

This first level of temperature supervision is intended for non-invasive
temperature control, where the necessary measures for cooling the system
down are left to the host software. In this case, inside the thermal
notification function da9062_thermal_notify().

Signed-off-by: Steve Twiss <[email protected]>

---
This patch applies against linux-next and v4.8

Regards,
Steve Twiss, Dialog Semiconductor Ltd.


drivers/thermal/Kconfig | 10 ++
drivers/thermal/Makefile | 1 +
drivers/thermal/da9062-thermal.c | 313 +++++++++++++++++++++++++++++++++++++++
3 files changed, 324 insertions(+)
create mode 100644 drivers/thermal/da9062-thermal.c

diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 2d702ca..da58e54 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -272,6 +272,16 @@ config DB8500_CPUFREQ_COOLING
bound cpufreq cooling device turns active to set CPU frequency low to
cool down the CPU.

+config DA9062_THERMAL
+ tristate "DA9062/DA9061 Dialog Semiconductor thermal driver"
+ depends on MFD_DA9062
+ depends on OF
+ help
+ Enable this for the Dialog Semiconductor thermal sensor driver.
+ This will report PMIC junction over-temperature for one thermal trip
+ zone.
+ Compatible with the DA9062 and DA9061 PMICs.
+
config INTEL_POWERCLAMP
tristate "Intel PowerClamp idle injection driver"
depends on THERMAL
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 10b07c1..0a2b3f2 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o
obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o
obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o
obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o
+obj-$(CONFIG_DA9062_THERMAL) += da9062-thermal.o
obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o
obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o
obj-$(CONFIG_INTEL_SOC_DTS_IOSF_CORE) += intel_soc_dts_iosf.o
diff --git a/drivers/thermal/da9062-thermal.c b/drivers/thermal/da9062-thermal.c
new file mode 100644
index 0000000..feeabf6
--- /dev/null
+++ b/drivers/thermal/da9062-thermal.c
@@ -0,0 +1,313 @@
+/*
+ * Thermal device driver for DA9062 and DA9061
+ * Copyright (C) 2016 Dialog Semiconductor Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/regmap.h>
+#include <linux/thermal.h>
+#include <linux/of.h>
+
+#include <linux/mfd/da9062/core.h>
+#include <linux/mfd/da9062/registers.h>
+
+#define DA9062_DEFAULT_POLLING_MS_PERIOD 3000
+#define DA9062_MAX_POLLING_MS_PERIOD 10000
+#define DA9062_MIN_POLLING_MS_PERIOD 1000
+
+#define DA9062_MILLI_CELSIUS(t) ((t)*1000)
+
+struct da9062_thermal_config {
+ const char *name;
+};
+
+struct da9062_thermal {
+ struct da9062 *hw;
+ struct delayed_work work;
+ struct thermal_zone_device *zone;
+ enum thermal_device_mode mode;
+ unsigned int polling_period;
+ struct mutex lock;
+ int temperature;
+ int irq;
+ const struct da9062_thermal_config *config;
+ struct device *dev;
+};
+
+static void da9062_thermal_poll_on(struct work_struct *work)
+{
+ struct da9062_thermal *thermal = container_of(work,
+ struct da9062_thermal,
+ work.work);
+ unsigned int val;
+ int ret;
+
+ /* clear E_TEMP */
+ ret = regmap_write(thermal->hw->regmap,
+ DA9062AA_EVENT_B,
+ DA9062AA_E_TEMP_MASK);
+ if (ret < 0) {
+ dev_err(thermal->dev,
+ "Cannot clear the TJUNC temperature status\n");
+ goto err_enable_irq;
+ }
+
+ /* Now read E_TEMP again: it is acting like a status bit.
+ * If over-temperature, then this status will be true.
+ * If not over-temperature, this staus will be false.
+ */
+ ret = regmap_read(thermal->hw->regmap,
+ DA9062AA_EVENT_B,
+ &val);
+ if (ret < 0) {
+ dev_err(thermal->dev,
+ "Cannot check the TJUNC temperature status\n");
+ goto err_enable_irq;
+ } else {
+ if (val & DA9062AA_E_TEMP_MASK) {
+ mutex_lock(&thermal->lock);
+ thermal->temperature = DA9062_MILLI_CELSIUS(125);
+ mutex_unlock(&thermal->lock);
+ thermal_zone_device_update(thermal->zone);
+
+ schedule_delayed_work(&thermal->work,
+ msecs_to_jiffies(thermal->polling_period));
+ return;
+ } else {
+ mutex_lock(&thermal->lock);
+ thermal->temperature = DA9062_MILLI_CELSIUS(0);
+ mutex_unlock(&thermal->lock);
+ thermal_zone_device_update(thermal->zone);
+ }
+ }
+
+err_enable_irq:
+ enable_irq(thermal->irq);
+}
+
+static irqreturn_t da9062_thermal_irq_handler(int irq, void *data)
+{
+ struct da9062_thermal *thermal = data;
+
+ disable_irq_nosync(thermal->irq);
+ schedule_delayed_work(&thermal->work, 0);
+
+ return IRQ_HANDLED;
+}
+
+static int da9062_thermal_get_mode(struct thermal_zone_device *z,
+ enum thermal_device_mode *mode)
+{
+ struct da9062_thermal *thermal = z->devdata;
+ *mode = thermal->mode;
+ return 0;
+}
+
+static int da9062_thermal_get_trip_type(struct thermal_zone_device *z,
+ int trip,
+ enum thermal_trip_type *type)
+{
+ struct da9062_thermal *thermal = z->devdata;
+
+ switch (trip) {
+ case 0:
+ *type = THERMAL_TRIP_HOT;
+ break;
+ default:
+ dev_err(thermal->dev,
+ "Driver does not support more than 1 trip-wire\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int da9062_thermal_get_trip_temp(struct thermal_zone_device *z,
+ int trip,
+ int *temp)
+{
+ struct da9062_thermal *thermal = z->devdata;
+
+ switch (trip) {
+ case 0:
+ *temp = DA9062_MILLI_CELSIUS(125);
+ break;
+ default:
+ dev_err(thermal->dev,
+ "Driver does not support more than 1 trip-wire\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int da9062_thermal_notify(struct thermal_zone_device *z,
+ int trip,
+ enum thermal_trip_type type)
+{
+ struct da9062_thermal *thermal = z->devdata;
+
+ switch (type) {
+ case THERMAL_TRIP_HOT:
+ dev_warn(thermal->dev, "Reached HOT (125degC) temperature\n");
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int da9062_thermal_get_temp(struct thermal_zone_device *z,
+ int *temp)
+{
+ struct da9062_thermal *thermal = z->devdata;
+
+ mutex_lock(&thermal->lock);
+ *temp = thermal->temperature;
+ mutex_unlock(&thermal->lock);
+
+ return 0;
+}
+
+static struct thermal_zone_device_ops da9062_thermal_ops = {
+ .get_temp = da9062_thermal_get_temp,
+ .get_mode = da9062_thermal_get_mode,
+ .get_trip_type = da9062_thermal_get_trip_type,
+ .get_trip_temp = da9062_thermal_get_trip_temp,
+ .notify = da9062_thermal_notify,
+};
+
+static const struct da9062_thermal_config da9062_config = {
+ .name = "da9062-thermal",
+};
+
+static const struct da9062_thermal_config da9061_config = {
+ .name = "da9061-thermal",
+};
+
+static const struct of_device_id da9062_compatible_reg_id_table[] = {
+ { .compatible = "dlg,da9062-thermal", .data = &da9062_config },
+ { .compatible = "dlg,da9061-thermal", .data = &da9061_config },
+ { },
+};
+
+static int da9062_thermal_probe(struct platform_device *pdev)
+{
+ struct da9062 *chip = dev_get_drvdata(pdev->dev.parent);
+ struct da9062_thermal *thermal;
+ unsigned int pp_tmp = DA9062_DEFAULT_POLLING_MS_PERIOD;
+ const struct of_device_id *match;
+ int ret = 0;
+
+ match = of_match_node(da9062_compatible_reg_id_table,
+ pdev->dev.of_node);
+ if (!match)
+ return -ENXIO;
+
+ if (pdev->dev.of_node) {
+ if (!of_property_read_u32(pdev->dev.of_node,
+ "dlg,tjunc-temp-polling-period-ms",
+ &pp_tmp)) {
+ if (pp_tmp < DA9062_MIN_POLLING_MS_PERIOD ||
+ pp_tmp > DA9062_MAX_POLLING_MS_PERIOD)
+ pp_tmp = DA9062_DEFAULT_POLLING_MS_PERIOD;
+ }
+
+ dev_dbg(&pdev->dev,
+ "TJUNC temp polling period set at %d ms\n",
+ pp_tmp);
+ }
+
+ thermal = devm_kzalloc(&pdev->dev, sizeof(struct da9062_thermal),
+ GFP_KERNEL);
+ if (!thermal) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ thermal->config = match->data;
+
+ INIT_DELAYED_WORK(&thermal->work, da9062_thermal_poll_on);
+ mutex_init(&thermal->lock);
+
+ thermal->zone = thermal_zone_device_register(thermal->config->name,
+ 1, 0, thermal,
+ &da9062_thermal_ops, NULL, 0,
+ 0);
+ if (IS_ERR(thermal->zone)) {
+ dev_err(&pdev->dev, "Cannot register thermal zone device\n");
+ ret = PTR_ERR(thermal->zone);
+ goto err;
+ }
+
+ ret = platform_get_irq_byname(pdev, "THERMAL");
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to get platform IRQ.\n");
+ goto err_zone;
+ }
+ thermal->irq = ret;
+
+ ret = request_threaded_irq(thermal->irq, NULL,
+ da9062_thermal_irq_handler,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "THERMAL", thermal);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed to request thermal device IRQ.\n");
+ goto err_zone;
+ }
+
+ thermal->hw = chip;
+ thermal->polling_period = pp_tmp;
+ thermal->mode = THERMAL_DEVICE_ENABLED;
+ thermal->dev = &pdev->dev;
+
+ platform_set_drvdata(pdev, thermal);
+ return 0;
+
+err_zone:
+ thermal_zone_device_unregister(thermal->zone);
+err:
+ return ret;
+}
+
+static int da9062_thermal_remove(struct platform_device *pdev)
+{
+ struct da9062_thermal *thermal = platform_get_drvdata(pdev);
+
+ free_irq(thermal->irq, thermal);
+ thermal_zone_device_unregister(thermal->zone);
+ cancel_delayed_work_sync(&thermal->work);
+ return 0;
+}
+
+static struct platform_driver da9062_thermal_driver = {
+ .probe = da9062_thermal_probe,
+ .remove = da9062_thermal_remove,
+ .driver = {
+ .name = "da9062-thermal",
+ .of_match_table = da9062_compatible_reg_id_table,
+ },
+};
+
+module_platform_driver(da9062_thermal_driver);
+
+MODULE_AUTHOR("Steve Twiss, Dialog Semiconductor");
+MODULE_DESCRIPTION("Thermal TJUNC device driver for Dialog DA9062 and DA9061");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:da9062-thermal");
--
end-of-patch for PATCH V1

2016-10-06 09:10:10

by Steve Twiss

[permalink] [raw]
Subject: [PATCH V1 02/10] regulator: da9061: BUCK and LDO regulator driver

From: Steve Twiss <[email protected]>

Regulator support for the DA9061 is added into the DA9062 regulator driver.

The regulators for DA9061 differ from those of DA9062.
A new DA9061 enumeration list for the LDOs and Bucks supported by this
device is added. Regulator information added: the old regulator
information for DA9062 is renamed from local_regulator_info[] to
local_da9062_regulator_info[] and a new array is added to support
local_da9061_regulator_info[].

The probe() function switches on the da9062_compatible_types enumeration
and configures the correct da9062_regulator_info array and number of
regulator entries.

Kconfig is updated to reflect support for DA9061 and DA9062 regulators.

Signed-off-by: Steve Twiss <[email protected]>

---
This patch applies against linux-next and v4.8

Mark,

These changes depend on a header file provided as part of an earlier
patch [PATCH V1 1/10] from this set. The regulator probe() switches on the
chip_type which uses enum da9062_compatible_types from core.h.

Regards,
Steve Twiss, Dialog Semiconductor Ltd.


drivers/regulator/Kconfig | 4 +-
drivers/regulator/da9062-regulator.c | 299 +++++++++++++++++++++++++++++++++--
2 files changed, 291 insertions(+), 12 deletions(-)

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 6c88e31..c4f678fe 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -188,11 +188,11 @@ config REGULATOR_DA9055
will be called da9055-regulator.

config REGULATOR_DA9062
- tristate "Dialog Semiconductor DA9062 regulators"
+ tristate "Dialog Semiconductor DA9061/62 regulators"
depends on MFD_DA9062
help
Say y here to support the BUCKs and LDOs regulators found on
- DA9062 PMICs.
+ DA9061 and DA9062 PMICs.

This driver can also be built as a module. If so, the module
will be called da9062-regulator.
diff --git a/drivers/regulator/da9062-regulator.c b/drivers/regulator/da9062-regulator.c
index 0638c8b..309da3a 100644
--- a/drivers/regulator/da9062-regulator.c
+++ b/drivers/regulator/da9062-regulator.c
@@ -28,6 +28,17 @@

/* Regulator IDs */
enum {
+ DA9061_ID_BUCK1,
+ DA9061_ID_BUCK2,
+ DA9061_ID_BUCK3,
+ DA9061_ID_LDO1,
+ DA9061_ID_LDO2,
+ DA9061_ID_LDO3,
+ DA9061_ID_LDO4,
+ DA9061_MAX_REGULATORS,
+};
+
+enum {
DA9062_ID_BUCK1,
DA9062_ID_BUCK2,
DA9062_ID_BUCK3,
@@ -88,15 +99,21 @@ enum {

/* Regulator operations */

-/* Current limits array (in uA) BUCK1 and BUCK3.
- Entry indexes corresponds to register values. */
+/* Current limits array (in uA)
+ * - DA9061_ID_[BUCK1|BUCK3]
+ * - DA9062_ID_[BUCK1|BUCK2|BUCK4]
+ * Entry indexes corresponds to register values.
+ */
static const int da9062_buck_a_limits[] = {
500000, 600000, 700000, 800000, 900000, 1000000, 1100000, 1200000,
1300000, 1400000, 1500000, 1600000, 1700000, 1800000, 1900000, 2000000
};

-/* Current limits array (in uA) for BUCK2.
- Entry indexes corresponds to register values. */
+/* Current limits array (in uA)
+ * - DA9061_ID_BUCK2
+ * - DA9062_ID_BUCK3
+ * Entry indexes corresponds to register values.
+ */
static const int da9062_buck_b_limits[] = {
1500000, 1600000, 1700000, 1800000, 1900000, 2000000, 2100000, 2200000,
2300000, 2400000, 2500000, 2600000, 2700000, 2800000, 2900000, 3000000
@@ -405,8 +422,254 @@ static const struct regulator_ops da9062_ldo_ops = {
.set_suspend_mode = da9062_ldo_set_suspend_mode,
};

-/* Regulator information */
-static const struct da9062_regulator_info local_regulator_info[] = {
+/* DA9061 Regulator information */
+static const struct da9062_regulator_info local_da9061_regulator_info[] = {
+ {
+ .desc.id = DA9061_ID_BUCK1,
+ .desc.name = "DA9061 BUCK1",
+ .desc.of_match = of_match_ptr("buck1"),
+ .desc.regulators_node = of_match_ptr("regulators"),
+ .desc.ops = &da9062_buck_ops,
+ .desc.min_uV = (300) * 1000,
+ .desc.uV_step = (10) * 1000,
+ .desc.n_voltages = ((1570) - (300))/(10) + 1,
+ .current_limits = da9062_buck_a_limits,
+ .n_current_limits = ARRAY_SIZE(da9062_buck_a_limits),
+ .desc.enable_reg = DA9062AA_BUCK1_CONT,
+ .desc.enable_mask = DA9062AA_BUCK1_EN_MASK,
+ .desc.vsel_reg = DA9062AA_VBUCK1_A,
+ .desc.vsel_mask = DA9062AA_VBUCK1_A_MASK,
+ .desc.linear_min_sel = 0,
+ .sleep = REG_FIELD(DA9062AA_VBUCK1_A,
+ __builtin_ffs((int)DA9062AA_BUCK1_SL_A_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_BUCK1_SL_A_MASK)) - 1),
+ .suspend_sleep = REG_FIELD(DA9062AA_VBUCK1_B,
+ __builtin_ffs((int)DA9062AA_BUCK1_SL_B_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_BUCK1_SL_B_MASK)) - 1),
+ .suspend_vsel_reg = DA9062AA_VBUCK1_B,
+ .mode = REG_FIELD(DA9062AA_BUCK1_CFG,
+ __builtin_ffs((int)DA9062AA_BUCK1_MODE_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_BUCK1_MODE_MASK)) - 1),
+ .suspend = REG_FIELD(DA9062AA_DVC_1,
+ __builtin_ffs((int)DA9062AA_VBUCK1_SEL_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_VBUCK1_SEL_MASK)) - 1),
+ .ilimit = REG_FIELD(DA9062AA_BUCK_ILIM_C,
+ __builtin_ffs((int)DA9062AA_BUCK1_ILIM_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_BUCK1_ILIM_MASK)) - 1),
+ },
+ {
+ .desc.id = DA9061_ID_BUCK2,
+ .desc.name = "DA9061 BUCK2",
+ .desc.of_match = of_match_ptr("buck2"),
+ .desc.regulators_node = of_match_ptr("regulators"),
+ .desc.ops = &da9062_buck_ops,
+ .desc.min_uV = (800) * 1000,
+ .desc.uV_step = (20) * 1000,
+ .desc.n_voltages = ((3340) - (800))/(20) + 1,
+ .current_limits = da9062_buck_b_limits,
+ .n_current_limits = ARRAY_SIZE(da9062_buck_b_limits),
+ .desc.enable_reg = DA9062AA_BUCK3_CONT,
+ .desc.enable_mask = DA9062AA_BUCK3_EN_MASK,
+ .desc.vsel_reg = DA9062AA_VBUCK3_A,
+ .desc.vsel_mask = DA9062AA_VBUCK3_A_MASK,
+ .desc.linear_min_sel = 0,
+ .sleep = REG_FIELD(DA9062AA_VBUCK3_A,
+ __builtin_ffs((int)DA9062AA_BUCK3_SL_A_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_BUCK3_SL_A_MASK)) - 1),
+ .suspend_sleep = REG_FIELD(DA9062AA_VBUCK3_B,
+ __builtin_ffs((int)DA9062AA_BUCK3_SL_B_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_BUCK3_SL_B_MASK)) - 1),
+ .suspend_vsel_reg = DA9062AA_VBUCK3_B,
+ .mode = REG_FIELD(DA9062AA_BUCK3_CFG,
+ __builtin_ffs((int)DA9062AA_BUCK3_MODE_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_BUCK3_MODE_MASK)) - 1),
+ .suspend = REG_FIELD(DA9062AA_DVC_1,
+ __builtin_ffs((int)DA9062AA_VBUCK3_SEL_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_VBUCK3_SEL_MASK)) - 1),
+ .ilimit = REG_FIELD(DA9062AA_BUCK_ILIM_A,
+ __builtin_ffs((int)DA9062AA_BUCK3_ILIM_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_BUCK3_ILIM_MASK)) - 1),
+ },
+ {
+ .desc.id = DA9061_ID_BUCK3,
+ .desc.name = "DA9061 BUCK3",
+ .desc.of_match = of_match_ptr("buck3"),
+ .desc.regulators_node = of_match_ptr("regulators"),
+ .desc.ops = &da9062_buck_ops,
+ .desc.min_uV = (530) * 1000,
+ .desc.uV_step = (10) * 1000,
+ .desc.n_voltages = ((1800) - (530))/(10) + 1,
+ .current_limits = da9062_buck_a_limits,
+ .n_current_limits = ARRAY_SIZE(da9062_buck_a_limits),
+ .desc.enable_reg = DA9062AA_BUCK4_CONT,
+ .desc.enable_mask = DA9062AA_BUCK4_EN_MASK,
+ .desc.vsel_reg = DA9062AA_VBUCK4_A,
+ .desc.vsel_mask = DA9062AA_VBUCK4_A_MASK,
+ .desc.linear_min_sel = 0,
+ .sleep = REG_FIELD(DA9062AA_VBUCK4_A,
+ __builtin_ffs((int)DA9062AA_BUCK4_SL_A_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_BUCK4_SL_A_MASK)) - 1),
+ .suspend_sleep = REG_FIELD(DA9062AA_VBUCK4_B,
+ __builtin_ffs((int)DA9062AA_BUCK4_SL_B_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_BUCK4_SL_B_MASK)) - 1),
+ .suspend_vsel_reg = DA9062AA_VBUCK4_B,
+ .mode = REG_FIELD(DA9062AA_BUCK4_CFG,
+ __builtin_ffs((int)DA9062AA_BUCK4_MODE_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_BUCK4_MODE_MASK)) - 1),
+ .suspend = REG_FIELD(DA9062AA_DVC_1,
+ __builtin_ffs((int)DA9062AA_VBUCK4_SEL_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_VBUCK4_SEL_MASK)) - 1),
+ .ilimit = REG_FIELD(DA9062AA_BUCK_ILIM_B,
+ __builtin_ffs((int)DA9062AA_BUCK4_ILIM_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_BUCK4_ILIM_MASK)) - 1),
+ },
+ {
+ .desc.id = DA9061_ID_LDO1,
+ .desc.name = "DA9061 LDO1",
+ .desc.of_match = of_match_ptr("ldo1"),
+ .desc.regulators_node = of_match_ptr("regulators"),
+ .desc.ops = &da9062_ldo_ops,
+ .desc.min_uV = (900) * 1000,
+ .desc.uV_step = (50) * 1000,
+ .desc.n_voltages = ((3600) - (900))/(50) + 1,
+ .desc.enable_reg = DA9062AA_LDO1_CONT,
+ .desc.enable_mask = DA9062AA_LDO1_EN_MASK,
+ .desc.vsel_reg = DA9062AA_VLDO1_A,
+ .desc.vsel_mask = DA9062AA_VLDO1_A_MASK,
+ .desc.linear_min_sel = 0,
+ .sleep = REG_FIELD(DA9062AA_VLDO1_A,
+ __builtin_ffs((int)DA9062AA_LDO1_SL_A_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_LDO1_SL_A_MASK)) - 1),
+ .suspend_sleep = REG_FIELD(DA9062AA_VLDO1_B,
+ __builtin_ffs((int)DA9062AA_LDO1_SL_B_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_LDO1_SL_B_MASK)) - 1),
+ .suspend_vsel_reg = DA9062AA_VLDO1_B,
+ .suspend = REG_FIELD(DA9062AA_DVC_1,
+ __builtin_ffs((int)DA9062AA_VLDO1_SEL_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_VLDO1_SEL_MASK)) - 1),
+ .oc_event = REG_FIELD(DA9062AA_STATUS_D,
+ __builtin_ffs((int)DA9062AA_LDO1_ILIM_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_LDO1_ILIM_MASK)) - 1),
+ },
+ {
+ .desc.id = DA9061_ID_LDO2,
+ .desc.name = "DA9061 LDO2",
+ .desc.of_match = of_match_ptr("ldo2"),
+ .desc.regulators_node = of_match_ptr("regulators"),
+ .desc.ops = &da9062_ldo_ops,
+ .desc.min_uV = (900) * 1000,
+ .desc.uV_step = (50) * 1000,
+ .desc.n_voltages = ((3600) - (600))/(50) + 1,
+ .desc.enable_reg = DA9062AA_LDO2_CONT,
+ .desc.enable_mask = DA9062AA_LDO2_EN_MASK,
+ .desc.vsel_reg = DA9062AA_VLDO2_A,
+ .desc.vsel_mask = DA9062AA_VLDO2_A_MASK,
+ .desc.linear_min_sel = 0,
+ .sleep = REG_FIELD(DA9062AA_VLDO2_A,
+ __builtin_ffs((int)DA9062AA_LDO2_SL_A_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_LDO2_SL_A_MASK)) - 1),
+ .suspend_sleep = REG_FIELD(DA9062AA_VLDO2_B,
+ __builtin_ffs((int)DA9062AA_LDO2_SL_B_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_LDO2_SL_B_MASK)) - 1),
+ .suspend_vsel_reg = DA9062AA_VLDO2_B,
+ .suspend = REG_FIELD(DA9062AA_DVC_1,
+ __builtin_ffs((int)DA9062AA_VLDO2_SEL_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_VLDO2_SEL_MASK)) - 1),
+ .oc_event = REG_FIELD(DA9062AA_STATUS_D,
+ __builtin_ffs((int)DA9062AA_LDO2_ILIM_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_LDO2_ILIM_MASK)) - 1),
+ },
+ {
+ .desc.id = DA9061_ID_LDO3,
+ .desc.name = "DA9061 LDO3",
+ .desc.of_match = of_match_ptr("ldo3"),
+ .desc.regulators_node = of_match_ptr("regulators"),
+ .desc.ops = &da9062_ldo_ops,
+ .desc.min_uV = (900) * 1000,
+ .desc.uV_step = (50) * 1000,
+ .desc.n_voltages = ((3600) - (900))/(50) + 1,
+ .desc.enable_reg = DA9062AA_LDO3_CONT,
+ .desc.enable_mask = DA9062AA_LDO3_EN_MASK,
+ .desc.vsel_reg = DA9062AA_VLDO3_A,
+ .desc.vsel_mask = DA9062AA_VLDO3_A_MASK,
+ .desc.linear_min_sel = 0,
+ .sleep = REG_FIELD(DA9062AA_VLDO3_A,
+ __builtin_ffs((int)DA9062AA_LDO3_SL_A_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_LDO3_SL_A_MASK)) - 1),
+ .suspend_sleep = REG_FIELD(DA9062AA_VLDO3_B,
+ __builtin_ffs((int)DA9062AA_LDO3_SL_B_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_LDO3_SL_B_MASK)) - 1),
+ .suspend_vsel_reg = DA9062AA_VLDO3_B,
+ .suspend = REG_FIELD(DA9062AA_DVC_1,
+ __builtin_ffs((int)DA9062AA_VLDO3_SEL_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_VLDO3_SEL_MASK)) - 1),
+ .oc_event = REG_FIELD(DA9062AA_STATUS_D,
+ __builtin_ffs((int)DA9062AA_LDO3_ILIM_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_LDO3_ILIM_MASK)) - 1),
+ },
+ {
+ .desc.id = DA9061_ID_LDO4,
+ .desc.name = "DA9061 LDO4",
+ .desc.of_match = of_match_ptr("ldo4"),
+ .desc.regulators_node = of_match_ptr("regulators"),
+ .desc.ops = &da9062_ldo_ops,
+ .desc.min_uV = (900) * 1000,
+ .desc.uV_step = (50) * 1000,
+ .desc.n_voltages = ((3600) - (900))/(50) + 1,
+ .desc.enable_reg = DA9062AA_LDO4_CONT,
+ .desc.enable_mask = DA9062AA_LDO4_EN_MASK,
+ .desc.vsel_reg = DA9062AA_VLDO4_A,
+ .desc.vsel_mask = DA9062AA_VLDO4_A_MASK,
+ .desc.linear_min_sel = 0,
+ .sleep = REG_FIELD(DA9062AA_VLDO4_A,
+ __builtin_ffs((int)DA9062AA_LDO4_SL_A_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_LDO4_SL_A_MASK)) - 1),
+ .suspend_sleep = REG_FIELD(DA9062AA_VLDO4_B,
+ __builtin_ffs((int)DA9062AA_LDO4_SL_B_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_LDO4_SL_B_MASK)) - 1),
+ .suspend_vsel_reg = DA9062AA_VLDO4_B,
+ .suspend = REG_FIELD(DA9062AA_DVC_1,
+ __builtin_ffs((int)DA9062AA_VLDO4_SEL_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_VLDO4_SEL_MASK)) - 1),
+ .oc_event = REG_FIELD(DA9062AA_STATUS_D,
+ __builtin_ffs((int)DA9062AA_LDO4_ILIM_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_LDO4_ILIM_MASK)) - 1),
+ },
+};
+
+/* DA9062 Regulator information */
+static const struct da9062_regulator_info local_da9062_regulator_info[] = {
{
.desc.id = DA9062_ID_BUCK1,
.desc.name = "DA9062 BUCK1",
@@ -727,17 +990,33 @@ static int da9062_regulator_probe(struct platform_device *pdev)
struct da9062_regulators *regulators;
struct da9062_regulator *regl;
struct regulator_config config = { };
+ const struct da9062_regulator_info *rinfo;
int irq, n, ret;
size_t size;
+ int max_regulators;
+
+ switch (chip->chip_type) {
+ case COMPAT_TYPE_DA9061:
+ max_regulators = DA9061_MAX_REGULATORS;
+ rinfo = local_da9061_regulator_info;
+ break;
+ case COMPAT_TYPE_DA9062:
+ max_regulators = DA9062_MAX_REGULATORS;
+ rinfo = local_da9062_regulator_info;
+ break;
+ default:
+ dev_err(chip->dev, "Unrecognised chip type\n");
+ return -ENODEV;
+ }

/* Allocate memory required by usable regulators */
size = sizeof(struct da9062_regulators) +
- DA9062_MAX_REGULATORS * sizeof(struct da9062_regulator);
+ max_regulators * sizeof(struct da9062_regulator);
regulators = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
if (!regulators)
return -ENOMEM;

- regulators->n_regulators = DA9062_MAX_REGULATORS;
+ regulators->n_regulators = max_regulators;
platform_set_drvdata(pdev, regulators);

n = 0;
@@ -745,7 +1024,7 @@ static int da9062_regulator_probe(struct platform_device *pdev)
/* Initialise regulator structure */
regl = &regulators->regulator[n];
regl->hw = chip;
- regl->info = &local_regulator_info[n];
+ regl->info = &rinfo[n];
regl->desc = regl->info->desc;
regl->desc.type = REGULATOR_VOLTAGE;
regl->desc.owner = THIS_MODULE;
@@ -836,6 +1115,6 @@ module_exit(da9062_regulator_cleanup);

/* Module information */
MODULE_AUTHOR("S Twiss <[email protected]>");
-MODULE_DESCRIPTION("REGULATOR device driver for Dialog DA9062");
+MODULE_DESCRIPTION("REGULATOR device driver for Dialog DA9062 and DA9061");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:da9062-regulators");
--
end-of-patch for PATCH V1

2016-10-06 09:10:19

by Steve Twiss

[permalink] [raw]
Subject: [PATCH V1 06/10] Documentation: dt: input: temperature driver

From: Steve Twiss <[email protected]>

Add binding information for DA9061 onkey.

This patch updates the compatible string "dlg,da9061-onkey" to support
DA9061, removes ther reference to KEY_SLEEP (which the driver no longer
supports) and fixes a typo in the example.

Signed-off-by: Steve Twiss <[email protected]>

---
This patch applies against linux-next and v4.8

Hi,

This patch depends on the acceptance of the main code for the onkey:
[PATCH V1 3/10] Input: da9061: onkey driver.

Regards,
Steve Twiss, Dialog Semiconductor Ltd.


.../devicetree/bindings/input/da9062-onkey.txt | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/Documentation/devicetree/bindings/input/da9062-onkey.txt b/Documentation/devicetree/bindings/input/da9062-onkey.txt
index ab0e048..ce45436 100644
--- a/Documentation/devicetree/bindings/input/da9062-onkey.txt
+++ b/Documentation/devicetree/bindings/input/da9062-onkey.txt
@@ -1,28 +1,27 @@
-* Dialog DA9062/63 OnKey Module
+* Dialog DA9061/62/63 OnKey Module

-This module is part of the DA9062/DA9063. For more details about entire
-chips see Documentation/devicetree/bindings/mfd/da9062.txt and
-Documentation/devicetree/bindings/mfd/da9063.txt
+This module is part of the DA9061/DA9062/DA9063. For more details about entire
+DA9062 and DA9061 chips see Documentation/devicetree/bindings/mfd/da9062.txt
+For DA9063 see Documentation/devicetree/bindings/mfd/da9063.txt

-This module provides KEY_POWER, KEY_SLEEP and events.
+This module provides the KEY_POWER event.

Required properties:

- compatible: should be one of:
+ dlg,da9061-onkey
dlg,da9062-onkey
dlg,da9063-onkey

Optional properties:

- - dlg,disable-key-power : Disable power-down using a long key-press. If this
+- dlg,disable-key-power : Disable power-down using a long key-press. If this
entry exists the OnKey driver will remove support for the KEY_POWER key
- press. If this entry does not exist then by default the key-press
- triggered power down is enabled and the OnKey will support both KEY_POWER
- and KEY_SLEEP.
+ press when triggered using a long press of the OnKey.

Example:

- pmic0: da9062@58 {
+ pmic0: da9063@58 {

onkey {
compatible = "dlg,da9063-onkey";
--
end-of-patch for PATCH V1

2016-10-06 09:10:27

by Steve Twiss

[permalink] [raw]
Subject: [PATCH V1 09/10] Documentation: dt: mfd: da9062/61 MFD binding

From: Steve Twiss <[email protected]>

Extend existing DA9062 binding information to include the DA9061 PMIC for
MFD core and regulators.

Add a da9062-onkey link to the existing onkey binding file.

Add a da9062-thermal link to the new temperature monitoring binding file
found in [PATCH V1 8/10].

Delete the da9062-watchdog section and replace it with a link to the new
DA9061/62 binding information file added by [PATCH V1 7/10].

Signed-off-by: Steve Twiss <[email protected]>

---
This patch applies against linux-next and v4.8

Hi,

This patch depends on acceptance of the main code for the DA9061 MFD:

- [PATCH V1 1/10] mfd: da9061: MFD core support

and also from the following binding file changes:

- [PATCH V1 6/10] Binding for onkey
- [PATCH V1 7/10] Binding for watchdog
- [PATCH V1 8/10] Binding for thermal

Regards,
Steve Twiss, Dialog Semiconductor Ltd.


Documentation/devicetree/bindings/mfd/da9062.txt | 45 +++++++++++++++++-------
1 file changed, 33 insertions(+), 12 deletions(-)

diff --git a/Documentation/devicetree/bindings/mfd/da9062.txt b/Documentation/devicetree/bindings/mfd/da9062.txt
index 38802b5..38ba5e2 100644
--- a/Documentation/devicetree/bindings/mfd/da9062.txt
+++ b/Documentation/devicetree/bindings/mfd/da9062.txt
@@ -1,22 +1,32 @@
* Dialog DA9062 Power Management Integrated Circuit (PMIC)

-DA9062 consists of a large and varied group of sub-devices:
+The DA9062 driver is compatible with the DA9062 and DA9061 devices.
+
+Product information can be found here:
+- http://www.dialog-semiconductor.com/products/da9062
+- http://www.dialog-semiconductor.com/products/da9061
+
+DA9062 driver consists of a large and varied group of sub-devices:

Device Supply Names Description
------ ------------ -----------
da9062-regulator : : LDOs & BUCKs
da9062-rtc : : Real-Time Clock
+da9062-onkey : : On Key
da9062-watchdog : : Watchdog Timer
+da9062-thermal : : Thermal

======

Required properties:

-- compatible : Should be "dlg,da9062".
+- compatible : Should be
+ "dlg,da9062" for DA9062
+ "dlg,da9061" for DA9061
- reg : Specifies the I2C slave address (this defaults to 0x58 but it can be
modified to match the chip's OTP settings).
- interrupt-parent : Specifies the reference to the interrupt controller for
- the DA9062.
+ the DA9062 or DA9061.
- interrupts : IRQ line information.
- interrupt-controller

@@ -25,8 +35,8 @@ further information on IRQ bindings.

Sub-nodes:

-- regulators : This node defines the settings for the LDOs and BUCKs. The
- DA9062 regulators are bound using their names listed below:
+- regulators : This node defines the settings for the LDOs and BUCKs.
+ The DA9062 regulators are bound using their names listed below:

buck1 : BUCK_1
buck2 : BUCK_2
@@ -37,6 +47,16 @@ Sub-nodes:
ldo3 : LDO_3
ldo4 : LDO_4

+ The DA9061 regulators are bound using their names listed below:
+
+ buck1 : BUCK_1
+ buck2 : BUCK_2
+ buck3 : BUCK_3
+ ldo1 : LDO_1
+ ldo2 : LDO_2
+ ldo3 : LDO_3
+ ldo4 : LDO_4
+
The component follows the standard regulator framework and the bindings
details of individual regulator device can be found in:
Documentation/devicetree/bindings/regulator/regulator.txt
@@ -46,9 +66,14 @@ Sub-nodes:
with the DA9062. There are currently no entries in this binding, however
compatible = "dlg,da9062-rtc" should be added if a node is created.

-- watchdog: This node defines the settings for the watchdog driver associated
- with the DA9062 PMIC. The compatible = "dlg,da9062-watchdog" should be added
- if a node is created.
+
+- onkey : See ../input/da9062-onkey.txt
+
+
+- watchdog: See ../watchdog/da9062-watchdog.txt
+
+
+- thermal : See ../thermal/da9062-thermal.txt


Example:
@@ -64,10 +89,6 @@ Example:
compatible = "dlg,da9062-rtc";
};

- watchdog {
- compatible = "dlg,da9062-watchdog";
- };
-
regulators {
DA9062_BUCK1: buck1 {
regulator-name = "BUCK1";
--
end-of-patch for PATCH V1

2016-10-06 09:10:23

by Steve Twiss

[permalink] [raw]
Subject: [PATCH V1 03/10] Input: da9061: onkey driver

From: Steve Twiss <[email protected]>

Support for the DA9061 onkey is added into the DA9063 onkey driver.

The of_device_id match array is expanded to support "dlg,da9061-onkey" as a
valid .compatible string. A new chip configuration register map listed in
da9061_regs is added and linked to this device tree compatible string in
the .data section.

Copyright header is updated to add DA9061 in its description and the module
description macro is extended to include DA9061.

Kconfig is updated to reflect support for DA9061/62/63.

Signed-off-by: Steve Twiss <[email protected]>

---
This patch applies against linux-next and v4.8

Dmitry,

The DA9063 onkey driver is modified to support the DA9061 onkey.
Because of earlier work with DA9062 it is a simple matter to extend this
for DA9061 by adding a new compatible string and register mapping.
{ .compatible = "dlg,da9061-onkey", .data = &da9061_regs },

Regards,
Steve Twiss, Dialog Semiconductor Ltd.


drivers/input/misc/Kconfig | 7 ++++---
drivers/input/misc/da9063_onkey.c | 24 ++++++++++++++++++++----
2 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index efb0ca8..57cc9c2 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -613,11 +613,12 @@ config INPUT_DA9055_ONKEY
will be called da9055_onkey.

config INPUT_DA9063_ONKEY
- tristate "Dialog DA9062/63 OnKey"
+ tristate "Dialog DA9063/62/61 OnKey"
depends on MFD_DA9063 || MFD_DA9062
help
- Support the ONKEY of Dialog DA9063 and DA9062 Power Management ICs
- as an input device capable of reporting the power button status.
+ Support the ONKEY of Dialog DA9063, DA9062 and DA9061 Power
+ Management ICs as an input device capable of reporting the
+ power button status.

To compile this driver as a module, choose M here: the module
will be called da9063_onkey.
diff --git a/drivers/input/misc/da9063_onkey.c b/drivers/input/misc/da9063_onkey.c
index bb863e0..60c29cd 100644
--- a/drivers/input/misc/da9063_onkey.c
+++ b/drivers/input/misc/da9063_onkey.c
@@ -1,5 +1,5 @@
/*
- * OnKey device driver for DA9063 and DA9062 PMICs
+ * OnKey device driver for DA9063, DA9062 and DA9061 PMICs
* Copyright (C) 2015 Dialog Semiconductor Ltd.
*
* This program is free software; you can redistribute it and/or
@@ -82,9 +82,25 @@ static const struct da906x_chip_config da9062_regs = {
.name = "da9062-onkey",
};

+static const struct da906x_chip_config da9061_regs = {
+ /* REGS */
+ .onkey_status = DA9062AA_STATUS_A,
+ .onkey_pwr_signalling = DA9062AA_CONTROL_B,
+ .onkey_fault_log = DA9062AA_FAULT_LOG,
+ .onkey_shutdown = DA9062AA_CONTROL_F,
+ /* MASKS */
+ .onkey_nonkey_mask = DA9062AA_NONKEY_MASK,
+ .onkey_nonkey_lock_mask = DA9062AA_NONKEY_LOCK_MASK,
+ .onkey_key_reset_mask = DA9062AA_KEY_RESET_MASK,
+ .onkey_shutdown_mask = DA9062AA_SHUTDOWN_MASK,
+ /* NAMES */
+ .name = "da9061-onkey",
+};
+
static const struct of_device_id da9063_compatible_reg_id_table[] = {
{ .compatible = "dlg,da9063-onkey", .data = &da9063_regs },
{ .compatible = "dlg,da9062-onkey", .data = &da9062_regs },
+ { .compatible = "dlg,da9061-onkey", .data = &da9061_regs },
{ },
};

@@ -149,13 +165,13 @@ static void da9063_poll_on(struct work_struct *work)
* and then send shutdown command
*/
dev_dbg(&onkey->input->dev,
- "Sending SHUTDOWN to DA9063 ...\n");
+ "Sending SHUTDOWN to PMIC ...\n");
error = regmap_write(onkey->regmap,
config->onkey_shutdown,
config->onkey_shutdown_mask);
if (error)
dev_err(&onkey->input->dev,
- "Cannot SHUTDOWN DA9063: %d\n",
+ "Cannot SHUTDOWN PMIC: %d\n",
error);
}
}
@@ -300,6 +316,6 @@ static struct platform_driver da9063_onkey_driver = {
module_platform_driver(da9063_onkey_driver);

MODULE_AUTHOR("S Twiss <[email protected]>");
-MODULE_DESCRIPTION("Onkey device driver for Dialog DA9063 and DA9062");
+MODULE_DESCRIPTION("Onkey device driver for Dialog DA9063, DA9062 and DA9061");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" DA9063_DRVNAME_ONKEY);
--
end-of-patch for PATCH V1

2016-10-06 09:11:17

by Steve Twiss

[permalink] [raw]
Subject: [PATCH V1 01/10] mfd: da9061: MFD core support

From: Steve Twiss <[email protected]>

MFD support for DA9061 is provided as part of the DA9062 device driver.

The registers header file adds two new chip variant IDs defined in DA9061
and DA9062 hardware. The core header file adds new software enumerations
for listing the valid DA9061 IRQs and a da9062_compatible_types enumeration
for distinguishing between DA9061/62 devices in software.

The core source code adds a new .compatible of_device_id entry. This is
extended from DA9062 to support both "dlg,da9061" and "dlg,da9062". The
.data entry now holds a reference to the enumerated device type.

A new regmap_irq_chip model is added for DA9061 and this supports the new
list of regmap_irq entries. A new mfd_cell da9061_devs[] array lists the
new sub system components for DA9061. Support is added for a new DA9061
regmap_config which lists the correct readble, writable and volatile
ranges for this chip.

The probe function uses the device tree compatible string to switch on the
da9062_compatible_types and configure the correct mfd cells, irq chip and
regmap config. The regmap is initialised first, before reading the variant
ID in hardware to decide if there is a conflict between the device tree
compatible string and the hardware definition. The remainder of the MFD
is finally configured after that.

Kconfig is updated to reflect support for DA9061 and DA9062 PMICs.

Signed-off-by: Steve Twiss <[email protected]>

---
This patch applies against linux-next and v4.8

Lee,

This patch adds support for the DA9061 PMIC. This is done as part of the
existing DA9062 device driver by extending the of_device_id match table.
This in turn allows new MFD cells, irq chip and regmap definitions to
support DA9061.

Regards,
Steve Twiss, Dialog Semiconductor Ltd.


drivers/mfd/Kconfig | 5 +-
drivers/mfd/da9062-core.c | 454 +++++++++++++++++++++++++++++++++--
include/linux/mfd/da9062/core.h | 27 ++-
include/linux/mfd/da9062/registers.h | 2 +
4 files changed, 463 insertions(+), 25 deletions(-)

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 2d1fb64..533798a 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -236,13 +236,14 @@ config MFD_DA9055
called "da9055"

config MFD_DA9062
- tristate "Dialog Semiconductor DA9062 PMIC Support"
+ tristate "Dialog Semiconductor DA9062/61 PMIC Support"
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
depends on I2C
help
- Say yes here for support for the Dialog Semiconductor DA9062 PMIC.
+ Say yes here for support for the Dialog Semiconductor DA9061 and
+ DA9062 PMICs.
This includes the I2C driver and core APIs.
Additional drivers must be enabled in order to use the functionality
of the device.
diff --git a/drivers/mfd/da9062-core.c b/drivers/mfd/da9062-core.c
index 8f873866..bfbc065 100644
--- a/drivers/mfd/da9062-core.c
+++ b/drivers/mfd/da9062-core.c
@@ -1,5 +1,5 @@
/*
- * Core, IRQ and I2C device driver for DA9062 PMIC
+ * Core, IRQ and I2C device driver for DA9062 and DA9061 PMICs
* Copyright (C) 2015 Dialog Semiconductor Ltd.
*
* This program is free software; you can redistribute it and/or
@@ -30,6 +30,70 @@
#define DA9062_REG_EVENT_B_OFFSET 1
#define DA9062_REG_EVENT_C_OFFSET 2

+static struct regmap_irq da9061_irqs[] = {
+ /* EVENT A */
+ [DA9061_IRQ_ONKEY] = {
+ .reg_offset = DA9062_REG_EVENT_A_OFFSET,
+ .mask = DA9062AA_M_NONKEY_MASK,
+ },
+ [DA9061_IRQ_WDG_WARN] = {
+ .reg_offset = DA9062_REG_EVENT_A_OFFSET,
+ .mask = DA9062AA_M_WDG_WARN_MASK,
+ },
+ [DA9061_IRQ_SEQ_RDY] = {
+ .reg_offset = DA9062_REG_EVENT_A_OFFSET,
+ .mask = DA9062AA_M_SEQ_RDY_MASK,
+ },
+ /* EVENT B */
+ [DA9061_IRQ_TEMP] = {
+ .reg_offset = DA9062_REG_EVENT_B_OFFSET,
+ .mask = DA9062AA_M_TEMP_MASK,
+ },
+ [DA9061_IRQ_LDO_LIM] = {
+ .reg_offset = DA9062_REG_EVENT_B_OFFSET,
+ .mask = DA9062AA_M_LDO_LIM_MASK,
+ },
+ [DA9061_IRQ_DVC_RDY] = {
+ .reg_offset = DA9062_REG_EVENT_B_OFFSET,
+ .mask = DA9062AA_M_DVC_RDY_MASK,
+ },
+ [DA9061_IRQ_VDD_WARN] = {
+ .reg_offset = DA9062_REG_EVENT_B_OFFSET,
+ .mask = DA9062AA_M_VDD_WARN_MASK,
+ },
+ /* EVENT C */
+ [DA9061_IRQ_GPI0] = {
+ .reg_offset = DA9062_REG_EVENT_C_OFFSET,
+ .mask = DA9062AA_M_GPI0_MASK,
+ },
+ [DA9061_IRQ_GPI1] = {
+ .reg_offset = DA9062_REG_EVENT_C_OFFSET,
+ .mask = DA9062AA_M_GPI1_MASK,
+ },
+ [DA9061_IRQ_GPI2] = {
+ .reg_offset = DA9062_REG_EVENT_C_OFFSET,
+ .mask = DA9062AA_M_GPI2_MASK,
+ },
+ [DA9061_IRQ_GPI3] = {
+ .reg_offset = DA9062_REG_EVENT_C_OFFSET,
+ .mask = DA9062AA_M_GPI3_MASK,
+ },
+ [DA9061_IRQ_GPI4] = {
+ .reg_offset = DA9062_REG_EVENT_C_OFFSET,
+ .mask = DA9062AA_M_GPI4_MASK,
+ },
+};
+
+static struct regmap_irq_chip da9061_irq_chip = {
+ .name = "da9061-irq",
+ .irqs = da9061_irqs,
+ .num_irqs = DA9061_NUM_IRQ,
+ .num_regs = 3,
+ .status_base = DA9062AA_EVENT_A,
+ .mask_base = DA9062AA_IRQ_MASK_A,
+ .ack_base = DA9062AA_EVENT_A,
+};
+
static struct regmap_irq da9062_irqs[] = {
/* EVENT A */
[DA9062_IRQ_ONKEY] = {
@@ -102,6 +166,57 @@ static struct regmap_irq_chip da9062_irq_chip = {
.ack_base = DA9062AA_EVENT_A,
};

+static struct resource da9061_core_resources[] = {
+ DEFINE_RES_NAMED(DA9061_IRQ_VDD_WARN, 1, "VDD_WARN", IORESOURCE_IRQ),
+};
+
+static struct resource da9061_regulators_resources[] = {
+ DEFINE_RES_NAMED(DA9061_IRQ_LDO_LIM, 1, "LDO_LIM", IORESOURCE_IRQ),
+};
+
+static struct resource da9061_thermal_resources[] = {
+ DEFINE_RES_NAMED(DA9061_IRQ_TEMP, 1, "THERMAL", IORESOURCE_IRQ),
+};
+
+static struct resource da9061_wdt_resources[] = {
+ DEFINE_RES_NAMED(DA9061_IRQ_WDG_WARN, 1, "WD_WARN", IORESOURCE_IRQ),
+};
+
+static struct resource da9061_onkey_resources[] = {
+ DEFINE_RES_NAMED(DA9061_IRQ_ONKEY, 1, "ONKEY", IORESOURCE_IRQ),
+};
+
+static const struct mfd_cell da9061_devs[] = {
+ {
+ .name = "da9061-core",
+ .num_resources = ARRAY_SIZE(da9061_core_resources),
+ .resources = da9061_core_resources,
+ },
+ {
+ .name = "da9062-regulators",
+ .num_resources = ARRAY_SIZE(da9061_regulators_resources),
+ .resources = da9061_regulators_resources,
+ },
+ {
+ .name = "da9061-watchdog",
+ .num_resources = ARRAY_SIZE(da9061_wdt_resources),
+ .resources = da9061_wdt_resources,
+ .of_compatible = "dlg,da9061-watchdog",
+ },
+ {
+ .name = "da9061-thermal",
+ .num_resources = ARRAY_SIZE(da9061_thermal_resources),
+ .resources = da9061_thermal_resources,
+ .of_compatible = "dlg,da9061-thermal",
+ },
+ {
+ .name = "da9061-onkey",
+ .num_resources = ARRAY_SIZE(da9061_onkey_resources),
+ .resources = da9061_onkey_resources,
+ .of_compatible = "dlg,da9061-onkey",
+ },
+};
+
static struct resource da9062_core_resources[] = {
DEFINE_RES_NAMED(DA9062_IRQ_VDD_WARN, 1, "VDD_WARN", IORESOURCE_IRQ),
};
@@ -142,7 +257,7 @@ static const struct mfd_cell da9062_devs[] = {
.name = "da9062-watchdog",
.num_resources = ARRAY_SIZE(da9062_wdt_resources),
.resources = da9062_wdt_resources,
- .of_compatible = "dlg,da9062-wdt",
+ .of_compatible = "dlg,da9062-watchdog",
},
{
.name = "da9062-thermal",
@@ -198,9 +313,10 @@ static int da9062_clear_fault_log(struct da9062 *chip)
return ret;
}

-static int da9062_get_device_type(struct da9062 *chip)
+static int da9062_get_device_type(struct da9062 *chip, int *vrc)
{
- int device_id, variant_id, variant_mrc;
+ int device_id, variant_id, variant_mrc, variant_vrc;
+ char *type;
int ret;

ret = regmap_read(chip->regmap, DA9062AA_DEVICE_ID, &device_id);
@@ -208,6 +324,7 @@ static int da9062_get_device_type(struct da9062 *chip)
dev_err(chip->dev, "Cannot read chip ID.\n");
return -EIO;
}
+
if (device_id != DA9062_PMIC_DEVICE_ID) {
dev_err(chip->dev, "Invalid device ID: 0x%02x\n", device_id);
return -ENODEV;
@@ -219,9 +336,23 @@ static int da9062_get_device_type(struct da9062 *chip)
return -EIO;
}

+ variant_vrc = (variant_id & DA9062AA_VRC_MASK) >> DA9062AA_VRC_SHIFT;
+
+ switch (variant_vrc) {
+ case DA9062_PMIC_VARIANT_VRC_DA9061:
+ type = "DA9061";
+ break;
+ case DA9062_PMIC_VARIANT_VRC_DA9062:
+ type = "DA9062";
+ break;
+ default:
+ type = "Unknown";
+ break;
+ }
+
dev_info(chip->dev,
- "Device detected (device-ID: 0x%02X, var-ID: 0x%02X)\n",
- device_id, variant_id);
+ "Device detected (device-ID: 0x%02X, var-ID: 0x%02X, %s)\n",
+ device_id, variant_id, type);

variant_mrc = (variant_id & DA9062AA_MRC_MASK) >> DA9062AA_MRC_SHIFT;

@@ -231,9 +362,239 @@ static int da9062_get_device_type(struct da9062 *chip)
return -ENODEV;
}

+ *vrc = variant_vrc;
+
return ret;
}

+static const struct regmap_range da9061_aa_readable_ranges[] = {
+ {
+ .range_min = DA9062AA_PAGE_CON,
+ .range_max = DA9062AA_STATUS_B,
+ }, {
+ .range_min = DA9062AA_STATUS_D,
+ .range_max = DA9062AA_EVENT_C,
+ }, {
+ .range_min = DA9062AA_IRQ_MASK_A,
+ .range_max = DA9062AA_IRQ_MASK_C,
+ }, {
+ .range_min = DA9062AA_CONTROL_A,
+ .range_max = DA9062AA_GPIO_4,
+ }, {
+ .range_min = DA9062AA_GPIO_WKUP_MODE,
+ .range_max = DA9062AA_GPIO_OUT3_4,
+ }, {
+ .range_min = DA9062AA_BUCK1_CONT,
+ .range_max = DA9062AA_BUCK4_CONT,
+ }, {
+ .range_min = DA9062AA_BUCK3_CONT,
+ .range_max = DA9062AA_BUCK3_CONT,
+ }, {
+ .range_min = DA9062AA_LDO1_CONT,
+ .range_max = DA9062AA_LDO4_CONT,
+ }, {
+ .range_min = DA9062AA_DVC_1,
+ .range_max = DA9062AA_DVC_1,
+ }, {
+ .range_min = DA9062AA_SEQ,
+ .range_max = DA9062AA_ID_4_3,
+ }, {
+ .range_min = DA9062AA_ID_12_11,
+ .range_max = DA9062AA_ID_16_15,
+ }, {
+ .range_min = DA9062AA_ID_22_21,
+ .range_max = DA9062AA_ID_32_31,
+ }, {
+ .range_min = DA9062AA_SEQ_A,
+ .range_max = DA9062AA_WAIT,
+ }, {
+ .range_min = DA9062AA_RESET,
+ .range_max = DA9062AA_BUCK_ILIM_C,
+ }, {
+ .range_min = DA9062AA_BUCK1_CFG,
+ .range_max = DA9062AA_BUCK3_CFG,
+ }, {
+ .range_min = DA9062AA_VBUCK1_A,
+ .range_max = DA9062AA_VBUCK4_A,
+ }, {
+ .range_min = DA9062AA_VBUCK3_A,
+ .range_max = DA9062AA_VBUCK3_A,
+ }, {
+ .range_min = DA9062AA_VLDO1_A,
+ .range_max = DA9062AA_VLDO4_A,
+ }, {
+ .range_min = DA9062AA_VBUCK1_B,
+ .range_max = DA9062AA_VBUCK4_B,
+ }, {
+ .range_min = DA9062AA_VBUCK3_B,
+ .range_max = DA9062AA_VBUCK3_B,
+ }, {
+ .range_min = DA9062AA_VLDO1_B,
+ .range_max = DA9062AA_VLDO4_B,
+ }, {
+ .range_min = DA9062AA_BBAT_CONT,
+ .range_max = DA9062AA_BBAT_CONT,
+ }, {
+ .range_min = DA9062AA_INTERFACE,
+ .range_max = DA9062AA_CONFIG_E,
+ }, {
+ .range_min = DA9062AA_CONFIG_G,
+ .range_max = DA9062AA_CONFIG_K,
+ }, {
+ .range_min = DA9062AA_CONFIG_M,
+ .range_max = DA9062AA_CONFIG_M,
+ }, {
+ .range_min = DA9062AA_GP_ID_0,
+ .range_max = DA9062AA_GP_ID_19,
+ }, {
+ .range_min = DA9062AA_DEVICE_ID,
+ .range_max = DA9062AA_CONFIG_ID,
+ },
+};
+
+static const struct regmap_range da9061_aa_writeable_ranges[] = {
+ {
+ .range_min = DA9062AA_PAGE_CON,
+ .range_max = DA9062AA_PAGE_CON,
+ }, {
+ .range_min = DA9062AA_FAULT_LOG,
+ .range_max = DA9062AA_EVENT_C,
+ }, {
+ .range_min = DA9062AA_IRQ_MASK_A,
+ .range_max = DA9062AA_IRQ_MASK_C,
+ }, {
+ .range_min = DA9062AA_CONTROL_A,
+ .range_max = DA9062AA_GPIO_4,
+ }, {
+ .range_min = DA9062AA_GPIO_WKUP_MODE,
+ .range_max = DA9062AA_GPIO_OUT3_4,
+ }, {
+ .range_min = DA9062AA_BUCK1_CONT,
+ .range_max = DA9062AA_BUCK4_CONT,
+ }, {
+ .range_min = DA9062AA_BUCK3_CONT,
+ .range_max = DA9062AA_BUCK3_CONT,
+ }, {
+ .range_min = DA9062AA_LDO1_CONT,
+ .range_max = DA9062AA_LDO4_CONT,
+ }, {
+ .range_min = DA9062AA_DVC_1,
+ .range_max = DA9062AA_DVC_1,
+ }, {
+ .range_min = DA9062AA_SEQ,
+ .range_max = DA9062AA_ID_4_3,
+ }, {
+ .range_min = DA9062AA_ID_12_11,
+ .range_max = DA9062AA_ID_16_15,
+ }, {
+ .range_min = DA9062AA_ID_22_21,
+ .range_max = DA9062AA_ID_32_31,
+ }, {
+ .range_min = DA9062AA_SEQ_A,
+ .range_max = DA9062AA_WAIT,
+ }, {
+ .range_min = DA9062AA_RESET,
+ .range_max = DA9062AA_BUCK_ILIM_C,
+ }, {
+ .range_min = DA9062AA_BUCK1_CFG,
+ .range_max = DA9062AA_BUCK3_CFG,
+ }, {
+ .range_min = DA9062AA_VBUCK1_A,
+ .range_max = DA9062AA_VBUCK4_A,
+ }, {
+ .range_min = DA9062AA_VBUCK3_A,
+ .range_max = DA9062AA_VBUCK3_A,
+ }, {
+ .range_min = DA9062AA_VLDO1_A,
+ .range_max = DA9062AA_VLDO4_A,
+ }, {
+ .range_min = DA9062AA_VBUCK1_B,
+ .range_max = DA9062AA_VBUCK4_B,
+ }, {
+ .range_min = DA9062AA_VBUCK3_B,
+ .range_max = DA9062AA_VBUCK3_B,
+ }, {
+ .range_min = DA9062AA_VLDO1_B,
+ .range_max = DA9062AA_VLDO4_B,
+ }, {
+ .range_min = DA9062AA_BBAT_CONT,
+ .range_max = DA9062AA_BBAT_CONT,
+ }, {
+ .range_min = DA9062AA_GP_ID_0,
+ .range_max = DA9062AA_GP_ID_19,
+ },
+};
+
+static const struct regmap_range da9061_aa_volatile_ranges[] = {
+ {
+ .range_min = DA9062AA_PAGE_CON,
+ .range_max = DA9062AA_STATUS_B,
+ }, {
+ .range_min = DA9062AA_STATUS_D,
+ .range_max = DA9062AA_EVENT_C,
+ }, {
+ .range_min = DA9062AA_CONTROL_A,
+ .range_max = DA9062AA_CONTROL_B,
+ }, {
+ .range_min = DA9062AA_CONTROL_E,
+ .range_max = DA9062AA_CONTROL_F,
+ }, {
+ .range_min = DA9062AA_BUCK1_CONT,
+ .range_max = DA9062AA_BUCK4_CONT,
+ }, {
+ .range_min = DA9062AA_BUCK3_CONT,
+ .range_max = DA9062AA_BUCK3_CONT,
+ }, {
+ .range_min = DA9062AA_LDO1_CONT,
+ .range_max = DA9062AA_LDO4_CONT,
+ }, {
+ .range_min = DA9062AA_DVC_1,
+ .range_max = DA9062AA_DVC_1,
+ }, {
+ .range_min = DA9062AA_SEQ,
+ .range_max = DA9062AA_SEQ,
+ },
+};
+
+static const struct regmap_access_table da9061_aa_readable_table = {
+ .yes_ranges = da9061_aa_readable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(da9061_aa_readable_ranges),
+};
+
+static const struct regmap_access_table da9061_aa_writeable_table = {
+ .yes_ranges = da9061_aa_writeable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(da9061_aa_writeable_ranges),
+};
+
+static const struct regmap_access_table da9061_aa_volatile_table = {
+ .yes_ranges = da9061_aa_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(da9061_aa_volatile_ranges),
+};
+
+static const struct regmap_range_cfg da9061_range_cfg[] = {
+ {
+ .range_min = DA9062AA_PAGE_CON,
+ .range_max = DA9062AA_CONFIG_ID,
+ .selector_reg = DA9062AA_PAGE_CON,
+ .selector_mask = 1 << DA9062_I2C_PAGE_SEL_SHIFT,
+ .selector_shift = DA9062_I2C_PAGE_SEL_SHIFT,
+ .window_start = 0,
+ .window_len = 256,
+ }
+};
+
+static struct regmap_config da9061_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .ranges = da9061_range_cfg,
+ .num_ranges = ARRAY_SIZE(da9061_range_cfg),
+ .max_register = DA9062AA_CONFIG_ID,
+ .cache_type = REGCACHE_RBTREE,
+ .rd_table = &da9061_aa_readable_table,
+ .wr_table = &da9061_aa_writeable_table,
+ .volatile_table = &da9061_aa_volatile_table,
+};
+
static const struct regmap_range da9062_aa_readable_ranges[] = {
{
.range_min = DA9062AA_PAGE_CON,
@@ -456,17 +817,39 @@ static struct regmap_config da9062_regmap_config = {
.volatile_table = &da9062_aa_volatile_table,
};

+static const struct of_device_id da9062_dt_ids[] = {
+ { .compatible = "dlg,da9062", .data = (void *)COMPAT_TYPE_DA9062, },
+ { .compatible = "dlg,da9061", .data = (void *)COMPAT_TYPE_DA9061, },
+ { }
+};
+MODULE_DEVICE_TABLE(of, da9062_dt_ids);
+
static int da9062_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct da9062 *chip;
+ const struct of_device_id *match;
unsigned int irq_base;
+ const struct mfd_cell *cell;
+ const struct regmap_irq_chip *irq_chip;
+ const struct regmap_config *config;
+ int cell_num;
+ int variant_vrc;
int ret;

chip = devm_kzalloc(&i2c->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;

+ if (i2c->dev.of_node) {
+ match = of_match_node(da9062_dt_ids, i2c->dev.of_node);
+ if (!match)
+ return -EINVAL;
+
+ chip->chip_type = (int)match->data;
+ } else
+ chip->chip_type = id->driver_data;
+
i2c_set_clientdata(i2c, chip);
chip->dev = &i2c->dev;

@@ -475,7 +858,25 @@ static int da9062_i2c_probe(struct i2c_client *i2c,
return -EINVAL;
}

- chip->regmap = devm_regmap_init_i2c(i2c, &da9062_regmap_config);
+ switch (chip->chip_type) {
+ case(COMPAT_TYPE_DA9061):
+ cell = da9061_devs;
+ cell_num = ARRAY_SIZE(da9061_devs);
+ irq_chip = &da9061_irq_chip;
+ config = &da9061_regmap_config;
+ break;
+ case(COMPAT_TYPE_DA9062):
+ cell = da9062_devs;
+ cell_num = ARRAY_SIZE(da9062_devs);
+ irq_chip = &da9062_irq_chip;
+ config = &da9062_regmap_config;
+ break;
+ default:
+ dev_err(chip->dev, "Unrecognised chip type\n");
+ return -ENODEV;
+ };
+
+ chip->regmap = devm_regmap_init_i2c(i2c, config);
if (IS_ERR(chip->regmap)) {
ret = PTR_ERR(chip->regmap);
dev_err(chip->dev, "Failed to allocate register map: %d\n",
@@ -483,17 +884,31 @@ static int da9062_i2c_probe(struct i2c_client *i2c,
return ret;
}

+ ret = da9062_get_device_type(chip, &variant_vrc);
+ if (ret)
+ return ret;
+
+ if (chip->chip_type == COMPAT_TYPE_DA9061 &&
+ variant_vrc != DA9062_PMIC_VARIANT_VRC_DA9061) {
+ dev_err(chip->dev,
+ "Expected DA9061 type mismatch with hardware");
+ return -ENODEV;
+ }
+
+ if (chip->chip_type == COMPAT_TYPE_DA9062 &&
+ variant_vrc != DA9062_PMIC_VARIANT_VRC_DA9062) {
+ dev_err(chip->dev,
+ "Expected DA9062 type mismatch with hardware");
+ return -ENODEV;
+ }
+
ret = da9062_clear_fault_log(chip);
if (ret < 0)
dev_warn(chip->dev, "Cannot clear fault log\n");

- ret = da9062_get_device_type(chip);
- if (ret)
- return ret;
-
ret = regmap_add_irq_chip(chip->regmap, i2c->irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
- -1, &da9062_irq_chip,
+ -1, irq_chip,
&chip->regmap_irq);
if (ret) {
dev_err(chip->dev, "Failed to request IRQ %d: %d\n",
@@ -503,8 +918,8 @@ static int da9062_i2c_probe(struct i2c_client *i2c,

irq_base = regmap_irq_chip_get_base(chip->regmap_irq);

- ret = mfd_add_devices(chip->dev, PLATFORM_DEVID_NONE, da9062_devs,
- ARRAY_SIZE(da9062_devs), NULL, irq_base,
+ ret = mfd_add_devices(chip->dev, PLATFORM_DEVID_NONE, cell,
+ cell_num, NULL, irq_base,
NULL);
if (ret) {
dev_err(chip->dev, "Cannot register child devices\n");
@@ -526,17 +941,12 @@ static int da9062_i2c_remove(struct i2c_client *i2c)
}

static const struct i2c_device_id da9062_i2c_id[] = {
- { "da9062", 0 },
+ { "da9062", COMPAT_TYPE_DA9062 },
+ { "da9061", COMPAT_TYPE_DA9061 },
{ },
};
MODULE_DEVICE_TABLE(i2c, da9062_i2c_id);

-static const struct of_device_id da9062_dt_ids[] = {
- { .compatible = "dlg,da9062", },
- { }
-};
-MODULE_DEVICE_TABLE(of, da9062_dt_ids);
-
static struct i2c_driver da9062_i2c_driver = {
.driver = {
.name = "da9062",
@@ -549,6 +959,6 @@ static struct i2c_driver da9062_i2c_driver = {

module_i2c_driver(da9062_i2c_driver);

-MODULE_DESCRIPTION("Core device driver for Dialog DA9062");
+MODULE_DESCRIPTION("Core device driver for Dialog DA9062 and DA9061");
MODULE_AUTHOR("Steve Twiss <[email protected]>");
MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/da9062/core.h b/include/linux/mfd/da9062/core.h
index 376ba84..199c524 100644
--- a/include/linux/mfd/da9062/core.h
+++ b/include/linux/mfd/da9062/core.h
@@ -18,7 +18,31 @@
#include <linux/interrupt.h>
#include <linux/mfd/da9062/registers.h>

-/* Interrupts */
+enum da9062_compatible_types {
+ COMPAT_TYPE_DA9061 = 1,
+ COMPAT_TYPE_DA9062,
+};
+
+enum da9061_irqs {
+ /* IRQ A */
+ DA9061_IRQ_ONKEY,
+ DA9061_IRQ_WDG_WARN,
+ DA9061_IRQ_SEQ_RDY,
+ /* IRQ B*/
+ DA9061_IRQ_TEMP,
+ DA9061_IRQ_LDO_LIM,
+ DA9061_IRQ_DVC_RDY,
+ DA9061_IRQ_VDD_WARN,
+ /* IRQ C */
+ DA9061_IRQ_GPI0,
+ DA9061_IRQ_GPI1,
+ DA9061_IRQ_GPI2,
+ DA9061_IRQ_GPI3,
+ DA9061_IRQ_GPI4,
+
+ DA9061_NUM_IRQ,
+};
+
enum da9062_irqs {
/* IRQ A */
DA9062_IRQ_ONKEY,
@@ -45,6 +69,7 @@ struct da9062 {
struct device *dev;
struct regmap *regmap;
struct regmap_irq_chip_data *regmap_irq;
+ enum da9062_compatible_types chip_type;
};

#endif /* __MFD_DA9062_CORE_H__ */
diff --git a/include/linux/mfd/da9062/registers.h b/include/linux/mfd/da9062/registers.h
index 97790d1..4457fdc 100644
--- a/include/linux/mfd/da9062/registers.h
+++ b/include/linux/mfd/da9062/registers.h
@@ -18,6 +18,8 @@

#define DA9062_PMIC_DEVICE_ID 0x62
#define DA9062_PMIC_VARIANT_MRC_AA 0x01
+#define DA9062_PMIC_VARIANT_VRC_DA9061 0x01
+#define DA9062_PMIC_VARIANT_VRC_DA9062 0x02

#define DA9062_I2C_PAGE_SEL_SHIFT 1

--
end-of-patch for PATCH V1

2016-10-06 09:13:32

by Steve Twiss

[permalink] [raw]
Subject: [PATCH V1 04/10] watchdog: da9061: watchdog driver

From: Steve Twiss <[email protected]>

Support for the DA9061 watchdog is added into the DA9062 watchdog driver.

The of_device_id match array is expanded to support "dlg,da9061-watchdog"
as a valid .compatible string. A new watchdog_info structure is added and
linked to this device tree compatible string in the .data section. Extra
code is added into the probe function to search-for and assign this match
data.

Copyright header is updated to add DA9061 in its description and the module
description macro is extended to include DA9061.

Kconfig is updated to reflect support for DA9061/62.

Signed-off-by: Steve Twiss <[email protected]>

---
This patch applies against linux-next and v4.8

Regards,
Steve Twiss, Dialog Semiconductor Ltd.


drivers/watchdog/Kconfig | 4 ++--
drivers/watchdog/da9062_wdt.c | 24 +++++++++++++++++++++---
2 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 1bffe00..d6b4088 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -104,11 +104,11 @@ config DA9063_WATCHDOG
This driver can be built as a module. The module name is da9063_wdt.

config DA9062_WATCHDOG
- tristate "Dialog DA9062 Watchdog"
+ tristate "Dialog DA9062/61 Watchdog"
depends on MFD_DA9062
select WATCHDOG_CORE
help
- Support for the watchdog in the DA9062 PMIC.
+ Support for the watchdog in the DA9062 and DA9061 PMICs.

This driver can be built as a module. The module name is da9062_wdt.

diff --git a/drivers/watchdog/da9062_wdt.c b/drivers/watchdog/da9062_wdt.c
index 7386111..5b9d408 100644
--- a/drivers/watchdog/da9062_wdt.c
+++ b/drivers/watchdog/da9062_wdt.c
@@ -1,5 +1,5 @@
/*
- * da9062_wdt.c - WDT device driver for DA9062
+ * Watchdog device driver for DA9062 and DA9061 PMICs
* Copyright (C) 2015 Dialog Semiconductor Ltd.
*
* This program is free software; you can redistribute it and/or
@@ -180,6 +180,11 @@ static const struct watchdog_info da9062_watchdog_info = {
.identity = "DA9062 WDT",
};

+static const struct watchdog_info da9061_watchdog_info = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+ .identity = "DA9061 WDT",
+};
+
static const struct watchdog_ops da9062_watchdog_ops = {
.owner = THIS_MODULE,
.start = da9062_wdt_start,
@@ -188,23 +193,35 @@ static const struct watchdog_ops da9062_watchdog_ops = {
.set_timeout = da9062_wdt_set_timeout,
};

+static const struct of_device_id da9062_compatible_id_table[] = {
+ { .compatible = "dlg,da9062-watchdog", .data = &da9062_watchdog_info },
+ { .compatible = "dlg,da9061-watchdog", .data = &da9061_watchdog_info },
+ { },
+};
+
static int da9062_wdt_probe(struct platform_device *pdev)
{
int ret;
struct da9062 *chip;
struct da9062_watchdog *wdt;
+ const struct of_device_id *match;

chip = dev_get_drvdata(pdev->dev.parent);
if (!chip)
return -EINVAL;

+ match = of_match_node(da9062_compatible_id_table,
+ pdev->dev.of_node);
+ if (!match)
+ return -ENXIO;
+
wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
if (!wdt)
return -ENOMEM;

wdt->hw = chip;

- wdt->wdtdev.info = &da9062_watchdog_info;
+ wdt->wdtdev.info = (const struct watchdog_info *)match->data;
wdt->wdtdev.ops = &da9062_watchdog_ops;
wdt->wdtdev.min_timeout = DA9062_WDT_MIN_TIMEOUT;
wdt->wdtdev.max_timeout = DA9062_WDT_MAX_TIMEOUT;
@@ -244,11 +261,12 @@ static struct platform_driver da9062_wdt_driver = {
.remove = da9062_wdt_remove,
.driver = {
.name = "da9062-watchdog",
+ .of_match_table = da9062_compatible_id_table,
},
};
module_platform_driver(da9062_wdt_driver);

MODULE_AUTHOR("S Twiss <[email protected]>");
-MODULE_DESCRIPTION("WDT device driver for Dialog DA9062");
+MODULE_DESCRIPTION("WDT device driver for Dialog DA9062 and DA9061");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:da9062-watchdog");
--
end-of-patch for PATCH V1

2016-10-06 09:13:28

by Steve Twiss

[permalink] [raw]
Subject: [PATCH V1 10/10] MAINTAINERS: da9062/61 updates to the Dialog Semiconductor search terms

From: Steve Twiss <[email protected]>

Hi,

Dialog Semiconductor support would like to add to the MAINTAINERS search
terms. This update will allow us to follow files for device tree bindings
and source code relating to input onkey drivers, chip thermal monitoring
and watchdog timers.

Signed-off-by: Steve Twiss <[email protected]>

---
This patch applies against linux-next and v4.8

Hi,

This patch depends on acceptance of the following from this patch set:

- [PATCH V1 5/10] PMIC temperature monitoring

and also from the following binding file changes:

- [PATCH V1 6/10] Binding for onkey
- [PATCH V1 7/10] Binding for watchdog
- [PATCH V1 8/10] Binding for thermal

Regards,
Steve Twiss, Dialog Semiconductor Ltd.


MAINTAINERS | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index f593300..a7fd809 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3752,7 +3752,10 @@ W: http://www.dialog-semiconductor.com/products
S: Supported
F: Documentation/hwmon/da90??
F: Documentation/devicetree/bindings/mfd/da90*.txt
+F: Documentation/devicetree/bindings/input/da90??-onkey.txt
+F: Documentation/devicetree/bindings/thermal/da90??-thermal.txt
F: Documentation/devicetree/bindings/regulator/da92*.txt
+F: Documentation/devicetree/bindings/watchdog/da92??-wdt.txt
F: Documentation/devicetree/bindings/sound/da[79]*.txt
F: drivers/gpio/gpio-da90??.c
F: drivers/hwmon/da90??-hwmon.c
@@ -3767,6 +3770,7 @@ F: drivers/power/da9052-battery.c
F: drivers/power/da91??-*.c
F: drivers/regulator/da903x.c
F: drivers/regulator/da9???-regulator.[ch]
+F: drivers/thermal/da90??-thermal.c
F: drivers/rtc/rtc-da90??.c
F: drivers/video/backlight/da90??_bl.c
F: drivers/watchdog/da90??_wdt.c
--
end-of-patch for PATCH V1

2016-10-06 10:39:00

by Keerthy

[permalink] [raw]
Subject: Re: [PATCH V1 01/10] mfd: da9061: MFD core support



On Thursday 06 October 2016 02:13 PM, Steve Twiss wrote:
> From: Steve Twiss <[email protected]>
>
> MFD support for DA9061 is provided as part of the DA9062 device driver.
>
> The registers header file adds two new chip variant IDs defined in DA9061
> and DA9062 hardware. The core header file adds new software enumerations
> for listing the valid DA9061 IRQs and a da9062_compatible_types enumeration
> for distinguishing between DA9061/62 devices in software.
>
> The core source code adds a new .compatible of_device_id entry. This is
> extended from DA9062 to support both "dlg,da9061" and "dlg,da9062". The
> .data entry now holds a reference to the enumerated device type.
>
> A new regmap_irq_chip model is added for DA9061 and this supports the new
> list of regmap_irq entries. A new mfd_cell da9061_devs[] array lists the
> new sub system components for DA9061. Support is added for a new DA9061
> regmap_config which lists the correct readble, writable and volatile

/s/readble/readable

> ranges for this chip.
>
> The probe function uses the device tree compatible string to switch on the
> da9062_compatible_types and configure the correct mfd cells, irq chip and
> regmap config. The regmap is initialised first, before reading the variant
> ID in hardware to decide if there is a conflict between the device tree
> compatible string and the hardware definition. The remainder of the MFD
> is finally configured after that.
>
> Kconfig is updated to reflect support for DA9061 and DA9062 PMICs.
>
> Signed-off-by: Steve Twiss <[email protected]>
>
> ---
> This patch applies against linux-next and v4.8
>
> Lee,
>
> This patch adds support for the DA9061 PMIC. This is done as part of the
> existing DA9062 device driver by extending the of_device_id match table.
> This in turn allows new MFD cells, irq chip and regmap definitions to
> support DA9061.
>
> Regards,
> Steve Twiss, Dialog Semiconductor Ltd.
>
>
> drivers/mfd/Kconfig | 5 +-
> drivers/mfd/da9062-core.c | 454 +++++++++++++++++++++++++++++++++--
> include/linux/mfd/da9062/core.h | 27 ++-
> include/linux/mfd/da9062/registers.h | 2 +
> 4 files changed, 463 insertions(+), 25 deletions(-)
>
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 2d1fb64..533798a 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -236,13 +236,14 @@ config MFD_DA9055
> called "da9055"
>
> config MFD_DA9062
> - tristate "Dialog Semiconductor DA9062 PMIC Support"
> + tristate "Dialog Semiconductor DA9062/61 PMIC Support"
> select MFD_CORE
> select REGMAP_I2C
> select REGMAP_IRQ
> depends on I2C
> help
> - Say yes here for support for the Dialog Semiconductor DA9062 PMIC.
> + Say yes here for support for the Dialog Semiconductor DA9061 and
> + DA9062 PMICs.
> This includes the I2C driver and core APIs.
> Additional drivers must be enabled in order to use the functionality
> of the device.
> diff --git a/drivers/mfd/da9062-core.c b/drivers/mfd/da9062-core.c
> index 8f873866..bfbc065 100644
> --- a/drivers/mfd/da9062-core.c
> +++ b/drivers/mfd/da9062-core.c
> @@ -1,5 +1,5 @@
> /*
> - * Core, IRQ and I2C device driver for DA9062 PMIC
> + * Core, IRQ and I2C device driver for DA9062 and DA9061 PMICs
> * Copyright (C) 2015 Dialog Semiconductor Ltd.
> *
> * This program is free software; you can redistribute it and/or
> @@ -30,6 +30,70 @@
> #define DA9062_REG_EVENT_B_OFFSET 1
> #define DA9062_REG_EVENT_C_OFFSET 2
>
> +static struct regmap_irq da9061_irqs[] = {
> + /* EVENT A */
> + [DA9061_IRQ_ONKEY] = {
> + .reg_offset = DA9062_REG_EVENT_A_OFFSET,
> + .mask = DA9062AA_M_NONKEY_MASK,
> + },
> + [DA9061_IRQ_WDG_WARN] = {
> + .reg_offset = DA9062_REG_EVENT_A_OFFSET,
> + .mask = DA9062AA_M_WDG_WARN_MASK,
> + },
> + [DA9061_IRQ_SEQ_RDY] = {
> + .reg_offset = DA9062_REG_EVENT_A_OFFSET,
> + .mask = DA9062AA_M_SEQ_RDY_MASK,
> + },
> + /* EVENT B */
> + [DA9061_IRQ_TEMP] = {
> + .reg_offset = DA9062_REG_EVENT_B_OFFSET,
> + .mask = DA9062AA_M_TEMP_MASK,
> + },
> + [DA9061_IRQ_LDO_LIM] = {
> + .reg_offset = DA9062_REG_EVENT_B_OFFSET,
> + .mask = DA9062AA_M_LDO_LIM_MASK,
> + },
> + [DA9061_IRQ_DVC_RDY] = {
> + .reg_offset = DA9062_REG_EVENT_B_OFFSET,
> + .mask = DA9062AA_M_DVC_RDY_MASK,
> + },
> + [DA9061_IRQ_VDD_WARN] = {
> + .reg_offset = DA9062_REG_EVENT_B_OFFSET,
> + .mask = DA9062AA_M_VDD_WARN_MASK,
> + },
> + /* EVENT C */
> + [DA9061_IRQ_GPI0] = {
> + .reg_offset = DA9062_REG_EVENT_C_OFFSET,
> + .mask = DA9062AA_M_GPI0_MASK,
> + },
> + [DA9061_IRQ_GPI1] = {
> + .reg_offset = DA9062_REG_EVENT_C_OFFSET,
> + .mask = DA9062AA_M_GPI1_MASK,
> + },
> + [DA9061_IRQ_GPI2] = {
> + .reg_offset = DA9062_REG_EVENT_C_OFFSET,
> + .mask = DA9062AA_M_GPI2_MASK,
> + },
> + [DA9061_IRQ_GPI3] = {
> + .reg_offset = DA9062_REG_EVENT_C_OFFSET,
> + .mask = DA9062AA_M_GPI3_MASK,
> + },
> + [DA9061_IRQ_GPI4] = {
> + .reg_offset = DA9062_REG_EVENT_C_OFFSET,
> + .mask = DA9062AA_M_GPI4_MASK,
> + },
> +};
> +
> +static struct regmap_irq_chip da9061_irq_chip = {
> + .name = "da9061-irq",
> + .irqs = da9061_irqs,
> + .num_irqs = DA9061_NUM_IRQ,
> + .num_regs = 3,
> + .status_base = DA9062AA_EVENT_A,
> + .mask_base = DA9062AA_IRQ_MASK_A,
> + .ack_base = DA9062AA_EVENT_A,
> +};
> +
> static struct regmap_irq da9062_irqs[] = {
> /* EVENT A */
> [DA9062_IRQ_ONKEY] = {
> @@ -102,6 +166,57 @@ static struct regmap_irq_chip da9062_irq_chip = {
> .ack_base = DA9062AA_EVENT_A,
> };
>
> +static struct resource da9061_core_resources[] = {
> + DEFINE_RES_NAMED(DA9061_IRQ_VDD_WARN, 1, "VDD_WARN", IORESOURCE_IRQ),
> +};
> +
> +static struct resource da9061_regulators_resources[] = {
> + DEFINE_RES_NAMED(DA9061_IRQ_LDO_LIM, 1, "LDO_LIM", IORESOURCE_IRQ),
> +};
> +
> +static struct resource da9061_thermal_resources[] = {
> + DEFINE_RES_NAMED(DA9061_IRQ_TEMP, 1, "THERMAL", IORESOURCE_IRQ),
> +};
> +
> +static struct resource da9061_wdt_resources[] = {
> + DEFINE_RES_NAMED(DA9061_IRQ_WDG_WARN, 1, "WD_WARN", IORESOURCE_IRQ),
> +};
> +
> +static struct resource da9061_onkey_resources[] = {
> + DEFINE_RES_NAMED(DA9061_IRQ_ONKEY, 1, "ONKEY", IORESOURCE_IRQ),
> +};
> +
> +static const struct mfd_cell da9061_devs[] = {
> + {
> + .name = "da9061-core",
> + .num_resources = ARRAY_SIZE(da9061_core_resources),
> + .resources = da9061_core_resources,
> + },
> + {
> + .name = "da9062-regulators",
> + .num_resources = ARRAY_SIZE(da9061_regulators_resources),
> + .resources = da9061_regulators_resources,
> + },
> + {
> + .name = "da9061-watchdog",
> + .num_resources = ARRAY_SIZE(da9061_wdt_resources),
> + .resources = da9061_wdt_resources,
> + .of_compatible = "dlg,da9061-watchdog",
> + },
> + {
> + .name = "da9061-thermal",
> + .num_resources = ARRAY_SIZE(da9061_thermal_resources),
> + .resources = da9061_thermal_resources,
> + .of_compatible = "dlg,da9061-thermal",
> + },
> + {
> + .name = "da9061-onkey",
> + .num_resources = ARRAY_SIZE(da9061_onkey_resources),
> + .resources = da9061_onkey_resources,
> + .of_compatible = "dlg,da9061-onkey",
> + },
> +};
> +
> static struct resource da9062_core_resources[] = {
> DEFINE_RES_NAMED(DA9062_IRQ_VDD_WARN, 1, "VDD_WARN", IORESOURCE_IRQ),
> };
> @@ -142,7 +257,7 @@ static const struct mfd_cell da9062_devs[] = {
> .name = "da9062-watchdog",
> .num_resources = ARRAY_SIZE(da9062_wdt_resources),
> .resources = da9062_wdt_resources,
> - .of_compatible = "dlg,da9062-wdt",
> + .of_compatible = "dlg,da9062-watchdog",

Any particular reason why this compatible needs to be changed?

> },
> {
> .name = "da9062-thermal",
> @@ -198,9 +313,10 @@ static int da9062_clear_fault_log(struct da9062 *chip)
> return ret;
> }
>
> -static int da9062_get_device_type(struct da9062 *chip)
> +static int da9062_get_device_type(struct da9062 *chip, int *vrc)
> {
> - int device_id, variant_id, variant_mrc;
> + int device_id, variant_id, variant_mrc, variant_vrc;
> + char *type;
> int ret;
>
> ret = regmap_read(chip->regmap, DA9062AA_DEVICE_ID, &device_id);
> @@ -208,6 +324,7 @@ static int da9062_get_device_type(struct da9062 *chip)
> dev_err(chip->dev, "Cannot read chip ID.\n");
> return -EIO;
> }
> +
> if (device_id != DA9062_PMIC_DEVICE_ID) {
> dev_err(chip->dev, "Invalid device ID: 0x%02x\n", device_id);
> return -ENODEV;
> @@ -219,9 +336,23 @@ static int da9062_get_device_type(struct da9062 *chip)
> return -EIO;
> }
>
> + variant_vrc = (variant_id & DA9062AA_VRC_MASK) >> DA9062AA_VRC_SHIFT;
> +
> + switch (variant_vrc) {
> + case DA9062_PMIC_VARIANT_VRC_DA9061:
> + type = "DA9061";
> + break;
> + case DA9062_PMIC_VARIANT_VRC_DA9062:
> + type = "DA9062";
> + break;
> + default:
> + type = "Unknown";
> + break;
> + }
> +
> dev_info(chip->dev,
> - "Device detected (device-ID: 0x%02X, var-ID: 0x%02X)\n",
> - device_id, variant_id);
> + "Device detected (device-ID: 0x%02X, var-ID: 0x%02X, %s)\n",
> + device_id, variant_id, type);
>
> variant_mrc = (variant_id & DA9062AA_MRC_MASK) >> DA9062AA_MRC_SHIFT;
>
> @@ -231,9 +362,239 @@ static int da9062_get_device_type(struct da9062 *chip)
> return -ENODEV;
> }
>
> + *vrc = variant_vrc;
> +
> return ret;
> }
>
> +static const struct regmap_range da9061_aa_readable_ranges[] = {
> + {
> + .range_min = DA9062AA_PAGE_CON,
> + .range_max = DA9062AA_STATUS_B,
> + }, {
> + .range_min = DA9062AA_STATUS_D,
> + .range_max = DA9062AA_EVENT_C,
> + }, {
> + .range_min = DA9062AA_IRQ_MASK_A,
> + .range_max = DA9062AA_IRQ_MASK_C,
> + }, {
> + .range_min = DA9062AA_CONTROL_A,
> + .range_max = DA9062AA_GPIO_4,
> + }, {
> + .range_min = DA9062AA_GPIO_WKUP_MODE,
> + .range_max = DA9062AA_GPIO_OUT3_4,
> + }, {
> + .range_min = DA9062AA_BUCK1_CONT,
> + .range_max = DA9062AA_BUCK4_CONT,
> + }, {
> + .range_min = DA9062AA_BUCK3_CONT,
> + .range_max = DA9062AA_BUCK3_CONT,
> + }, {
> + .range_min = DA9062AA_LDO1_CONT,
> + .range_max = DA9062AA_LDO4_CONT,
> + }, {
> + .range_min = DA9062AA_DVC_1,
> + .range_max = DA9062AA_DVC_1,
> + }, {
> + .range_min = DA9062AA_SEQ,
> + .range_max = DA9062AA_ID_4_3,
> + }, {
> + .range_min = DA9062AA_ID_12_11,
> + .range_max = DA9062AA_ID_16_15,
> + }, {
> + .range_min = DA9062AA_ID_22_21,
> + .range_max = DA9062AA_ID_32_31,
> + }, {
> + .range_min = DA9062AA_SEQ_A,
> + .range_max = DA9062AA_WAIT,
> + }, {
> + .range_min = DA9062AA_RESET,
> + .range_max = DA9062AA_BUCK_ILIM_C,
> + }, {
> + .range_min = DA9062AA_BUCK1_CFG,
> + .range_max = DA9062AA_BUCK3_CFG,
> + }, {
> + .range_min = DA9062AA_VBUCK1_A,
> + .range_max = DA9062AA_VBUCK4_A,
> + }, {
> + .range_min = DA9062AA_VBUCK3_A,
> + .range_max = DA9062AA_VBUCK3_A,
> + }, {
> + .range_min = DA9062AA_VLDO1_A,
> + .range_max = DA9062AA_VLDO4_A,
> + }, {
> + .range_min = DA9062AA_VBUCK1_B,
> + .range_max = DA9062AA_VBUCK4_B,
> + }, {
> + .range_min = DA9062AA_VBUCK3_B,
> + .range_max = DA9062AA_VBUCK3_B,
> + }, {
> + .range_min = DA9062AA_VLDO1_B,
> + .range_max = DA9062AA_VLDO4_B,
> + }, {
> + .range_min = DA9062AA_BBAT_CONT,
> + .range_max = DA9062AA_BBAT_CONT,
> + }, {
> + .range_min = DA9062AA_INTERFACE,
> + .range_max = DA9062AA_CONFIG_E,
> + }, {
> + .range_min = DA9062AA_CONFIG_G,
> + .range_max = DA9062AA_CONFIG_K,
> + }, {
> + .range_min = DA9062AA_CONFIG_M,
> + .range_max = DA9062AA_CONFIG_M,
> + }, {
> + .range_min = DA9062AA_GP_ID_0,
> + .range_max = DA9062AA_GP_ID_19,
> + }, {
> + .range_min = DA9062AA_DEVICE_ID,
> + .range_max = DA9062AA_CONFIG_ID,
> + },
> +};
> +
> +static const struct regmap_range da9061_aa_writeable_ranges[] = {
> + {
> + .range_min = DA9062AA_PAGE_CON,
> + .range_max = DA9062AA_PAGE_CON,
> + }, {
> + .range_min = DA9062AA_FAULT_LOG,
> + .range_max = DA9062AA_EVENT_C,
> + }, {
> + .range_min = DA9062AA_IRQ_MASK_A,
> + .range_max = DA9062AA_IRQ_MASK_C,
> + }, {
> + .range_min = DA9062AA_CONTROL_A,
> + .range_max = DA9062AA_GPIO_4,
> + }, {
> + .range_min = DA9062AA_GPIO_WKUP_MODE,
> + .range_max = DA9062AA_GPIO_OUT3_4,
> + }, {
> + .range_min = DA9062AA_BUCK1_CONT,
> + .range_max = DA9062AA_BUCK4_CONT,
> + }, {
> + .range_min = DA9062AA_BUCK3_CONT,
> + .range_max = DA9062AA_BUCK3_CONT,
> + }, {
> + .range_min = DA9062AA_LDO1_CONT,
> + .range_max = DA9062AA_LDO4_CONT,
> + }, {
> + .range_min = DA9062AA_DVC_1,
> + .range_max = DA9062AA_DVC_1,
> + }, {
> + .range_min = DA9062AA_SEQ,
> + .range_max = DA9062AA_ID_4_3,
> + }, {
> + .range_min = DA9062AA_ID_12_11,
> + .range_max = DA9062AA_ID_16_15,
> + }, {
> + .range_min = DA9062AA_ID_22_21,
> + .range_max = DA9062AA_ID_32_31,
> + }, {
> + .range_min = DA9062AA_SEQ_A,
> + .range_max = DA9062AA_WAIT,
> + }, {
> + .range_min = DA9062AA_RESET,
> + .range_max = DA9062AA_BUCK_ILIM_C,
> + }, {
> + .range_min = DA9062AA_BUCK1_CFG,
> + .range_max = DA9062AA_BUCK3_CFG,
> + }, {
> + .range_min = DA9062AA_VBUCK1_A,
> + .range_max = DA9062AA_VBUCK4_A,
> + }, {
> + .range_min = DA9062AA_VBUCK3_A,
> + .range_max = DA9062AA_VBUCK3_A,
> + }, {
> + .range_min = DA9062AA_VLDO1_A,
> + .range_max = DA9062AA_VLDO4_A,
> + }, {
> + .range_min = DA9062AA_VBUCK1_B,
> + .range_max = DA9062AA_VBUCK4_B,
> + }, {
> + .range_min = DA9062AA_VBUCK3_B,
> + .range_max = DA9062AA_VBUCK3_B,
> + }, {
> + .range_min = DA9062AA_VLDO1_B,
> + .range_max = DA9062AA_VLDO4_B,
> + }, {
> + .range_min = DA9062AA_BBAT_CONT,
> + .range_max = DA9062AA_BBAT_CONT,
> + }, {
> + .range_min = DA9062AA_GP_ID_0,
> + .range_max = DA9062AA_GP_ID_19,
> + },
> +};
> +
> +static const struct regmap_range da9061_aa_volatile_ranges[] = {
> + {
> + .range_min = DA9062AA_PAGE_CON,
> + .range_max = DA9062AA_STATUS_B,
> + }, {
> + .range_min = DA9062AA_STATUS_D,
> + .range_max = DA9062AA_EVENT_C,
> + }, {
> + .range_min = DA9062AA_CONTROL_A,
> + .range_max = DA9062AA_CONTROL_B,
> + }, {
> + .range_min = DA9062AA_CONTROL_E,
> + .range_max = DA9062AA_CONTROL_F,
> + }, {
> + .range_min = DA9062AA_BUCK1_CONT,
> + .range_max = DA9062AA_BUCK4_CONT,
> + }, {
> + .range_min = DA9062AA_BUCK3_CONT,
> + .range_max = DA9062AA_BUCK3_CONT,
> + }, {
> + .range_min = DA9062AA_LDO1_CONT,
> + .range_max = DA9062AA_LDO4_CONT,
> + }, {
> + .range_min = DA9062AA_DVC_1,
> + .range_max = DA9062AA_DVC_1,
> + }, {
> + .range_min = DA9062AA_SEQ,
> + .range_max = DA9062AA_SEQ,
> + },
> +};
> +
> +static const struct regmap_access_table da9061_aa_readable_table = {
> + .yes_ranges = da9061_aa_readable_ranges,
> + .n_yes_ranges = ARRAY_SIZE(da9061_aa_readable_ranges),
> +};
> +
> +static const struct regmap_access_table da9061_aa_writeable_table = {
> + .yes_ranges = da9061_aa_writeable_ranges,
> + .n_yes_ranges = ARRAY_SIZE(da9061_aa_writeable_ranges),
> +};
> +
> +static const struct regmap_access_table da9061_aa_volatile_table = {
> + .yes_ranges = da9061_aa_volatile_ranges,
> + .n_yes_ranges = ARRAY_SIZE(da9061_aa_volatile_ranges),
> +};
> +
> +static const struct regmap_range_cfg da9061_range_cfg[] = {
> + {
> + .range_min = DA9062AA_PAGE_CON,
> + .range_max = DA9062AA_CONFIG_ID,
> + .selector_reg = DA9062AA_PAGE_CON,
> + .selector_mask = 1 << DA9062_I2C_PAGE_SEL_SHIFT,
> + .selector_shift = DA9062_I2C_PAGE_SEL_SHIFT,
> + .window_start = 0,
> + .window_len = 256,
> + }
> +};
> +
> +static struct regmap_config da9061_regmap_config = {
> + .reg_bits = 8,
> + .val_bits = 8,
> + .ranges = da9061_range_cfg,
> + .num_ranges = ARRAY_SIZE(da9061_range_cfg),
> + .max_register = DA9062AA_CONFIG_ID,
> + .cache_type = REGCACHE_RBTREE,
> + .rd_table = &da9061_aa_readable_table,
> + .wr_table = &da9061_aa_writeable_table,
> + .volatile_table = &da9061_aa_volatile_table,
> +};
> +
> static const struct regmap_range da9062_aa_readable_ranges[] = {
> {
> .range_min = DA9062AA_PAGE_CON,
> @@ -456,17 +817,39 @@ static struct regmap_config da9062_regmap_config = {
> .volatile_table = &da9062_aa_volatile_table,
> };
>
> +static const struct of_device_id da9062_dt_ids[] = {
> + { .compatible = "dlg,da9062", .data = (void *)COMPAT_TYPE_DA9062, },
> + { .compatible = "dlg,da9061", .data = (void *)COMPAT_TYPE_DA9061, },

WARNING: DT compatible string "dlg,da9061" appears un-documented --
check ./Documentation/devicetree/bindings/
#622: FILE: drivers/mfd/da9062-core.c:822:
+ { .compatible = "dlg,da9061", .data = (void *)COMPAT_TYPE_DA9061, },

Might want to re-order patches so that you have the compatibles
documented before usage

> + { }
> +};
> +MODULE_DEVICE_TABLE(of, da9062_dt_ids);
> +
> static int da9062_i2c_probe(struct i2c_client *i2c,
> const struct i2c_device_id *id)
> {
> struct da9062 *chip;
> + const struct of_device_id *match;
> unsigned int irq_base;
> + const struct mfd_cell *cell;
> + const struct regmap_irq_chip *irq_chip;
> + const struct regmap_config *config;
> + int cell_num;

No need of cell_num.

> + int variant_vrc;
> int ret;
>
> chip = devm_kzalloc(&i2c->dev, sizeof(*chip), GFP_KERNEL);
> if (!chip)
> return -ENOMEM;
>
> + if (i2c->dev.of_node) {
> + match = of_match_node(da9062_dt_ids, i2c->dev.of_node);
> + if (!match)
> + return -EINVAL;
> +
> + chip->chip_type = (int)match->data;
> + } else
> + chip->chip_type = id->driver_data;
> +
> i2c_set_clientdata(i2c, chip);
> chip->dev = &i2c->dev;
>
> @@ -475,7 +858,25 @@ static int da9062_i2c_probe(struct i2c_client *i2c,
> return -EINVAL;
> }
>
> - chip->regmap = devm_regmap_init_i2c(i2c, &da9062_regmap_config);
> + switch (chip->chip_type) {
> + case(COMPAT_TYPE_DA9061):
> + cell = da9061_devs;
> + cell_num = ARRAY_SIZE(da9061_devs);

No need of the above assignment

> + irq_chip = &da9061_irq_chip;
> + config = &da9061_regmap_config;
> + break;
> + case(COMPAT_TYPE_DA9062):
> + cell = da9062_devs;
> + cell_num = ARRAY_SIZE(da9062_devs);

No need of the above assignment

> + irq_chip = &da9062_irq_chip;
> + config = &da9062_regmap_config;
> + break;
> + default:
> + dev_err(chip->dev, "Unrecognised chip type\n");
> + return -ENODEV;
> + };
> +
> + chip->regmap = devm_regmap_init_i2c(i2c, config);
> if (IS_ERR(chip->regmap)) {
> ret = PTR_ERR(chip->regmap);
> dev_err(chip->dev, "Failed to allocate register map: %d\n",
> @@ -483,17 +884,31 @@ static int da9062_i2c_probe(struct i2c_client *i2c,
> return ret;
> }
>
> + ret = da9062_get_device_type(chip, &variant_vrc);
> + if (ret)
> + return ret;
> +
> + if (chip->chip_type == COMPAT_TYPE_DA9061 &&
> + variant_vrc != DA9062_PMIC_VARIANT_VRC_DA9061) {
> + dev_err(chip->dev,
> + "Expected DA9061 type mismatch with hardware");
> + return -ENODEV;
> + }
> +
> + if (chip->chip_type == COMPAT_TYPE_DA9062 &&
> + variant_vrc != DA9062_PMIC_VARIANT_VRC_DA9062) {
> + dev_err(chip->dev,
> + "Expected DA9062 type mismatch with hardware");
> + return -ENODEV;
> + }
> +
> ret = da9062_clear_fault_log(chip);
> if (ret < 0)
> dev_warn(chip->dev, "Cannot clear fault log\n");
>
> - ret = da9062_get_device_type(chip);
> - if (ret)
> - return ret;
> -
> ret = regmap_add_irq_chip(chip->regmap, i2c->irq,
> IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
> - -1, &da9062_irq_chip,
> + -1, irq_chip,
> &chip->regmap_irq);
> if (ret) {
> dev_err(chip->dev, "Failed to request IRQ %d: %d\n",
> @@ -503,8 +918,8 @@ static int da9062_i2c_probe(struct i2c_client *i2c,
>
> irq_base = regmap_irq_chip_get_base(chip->regmap_irq);
>
> - ret = mfd_add_devices(chip->dev, PLATFORM_DEVID_NONE, da9062_devs,
> - ARRAY_SIZE(da9062_devs), NULL, irq_base,
> + ret = mfd_add_devices(chip->dev, PLATFORM_DEVID_NONE, cell,
> + cell_num, NULL, irq_base,

Use ARRAY_SIZE(cell) instead if cell_num

> NULL);
> if (ret) {
> dev_err(chip->dev, "Cannot register child devices\n");
> @@ -526,17 +941,12 @@ static int da9062_i2c_remove(struct i2c_client *i2c)
> }
>
> static const struct i2c_device_id da9062_i2c_id[] = {
> - { "da9062", 0 },
> + { "da9062", COMPAT_TYPE_DA9062 },
> + { "da9061", COMPAT_TYPE_DA9061 },
> { },
> };
> MODULE_DEVICE_TABLE(i2c, da9062_i2c_id);
>
> -static const struct of_device_id da9062_dt_ids[] = {
> - { .compatible = "dlg,da9062", },
> - { }
> -};
> -MODULE_DEVICE_TABLE(of, da9062_dt_ids);
> -
> static struct i2c_driver da9062_i2c_driver = {
> .driver = {
> .name = "da9062",
> @@ -549,6 +959,6 @@ static struct i2c_driver da9062_i2c_driver = {
>
> module_i2c_driver(da9062_i2c_driver);
>
> -MODULE_DESCRIPTION("Core device driver for Dialog DA9062");
> +MODULE_DESCRIPTION("Core device driver for Dialog DA9062 and DA9061");
> MODULE_AUTHOR("Steve Twiss <[email protected]>");
> MODULE_LICENSE("GPL");
> diff --git a/include/linux/mfd/da9062/core.h b/include/linux/mfd/da9062/core.h
> index 376ba84..199c524 100644
> --- a/include/linux/mfd/da9062/core.h
> +++ b/include/linux/mfd/da9062/core.h
> @@ -18,7 +18,31 @@
> #include <linux/interrupt.h>
> #include <linux/mfd/da9062/registers.h>
>
> -/* Interrupts */
> +enum da9062_compatible_types {
> + COMPAT_TYPE_DA9061 = 1,
> + COMPAT_TYPE_DA9062,
> +};
> +
> +enum da9061_irqs {
> + /* IRQ A */
> + DA9061_IRQ_ONKEY,
> + DA9061_IRQ_WDG_WARN,
> + DA9061_IRQ_SEQ_RDY,
> + /* IRQ B*/
> + DA9061_IRQ_TEMP,
> + DA9061_IRQ_LDO_LIM,
> + DA9061_IRQ_DVC_RDY,
> + DA9061_IRQ_VDD_WARN,
> + /* IRQ C */
> + DA9061_IRQ_GPI0,
> + DA9061_IRQ_GPI1,
> + DA9061_IRQ_GPI2,
> + DA9061_IRQ_GPI3,
> + DA9061_IRQ_GPI4,
> +
> + DA9061_NUM_IRQ,
> +};
> +
> enum da9062_irqs {
> /* IRQ A */
> DA9062_IRQ_ONKEY,
> @@ -45,6 +69,7 @@ struct da9062 {
> struct device *dev;
> struct regmap *regmap;
> struct regmap_irq_chip_data *regmap_irq;
> + enum da9062_compatible_types chip_type;
> };
>
> #endif /* __MFD_DA9062_CORE_H__ */
> diff --git a/include/linux/mfd/da9062/registers.h b/include/linux/mfd/da9062/registers.h
> index 97790d1..4457fdc 100644
> --- a/include/linux/mfd/da9062/registers.h
> +++ b/include/linux/mfd/da9062/registers.h
> @@ -18,6 +18,8 @@
>
> #define DA9062_PMIC_DEVICE_ID 0x62
> #define DA9062_PMIC_VARIANT_MRC_AA 0x01
> +#define DA9062_PMIC_VARIANT_VRC_DA9061 0x01
> +#define DA9062_PMIC_VARIANT_VRC_DA9062 0x02
>
> #define DA9062_I2C_PAGE_SEL_SHIFT 1
>
>

Regards,
Keerthy

2016-10-06 13:28:45

by Guenter Roeck

[permalink] [raw]
Subject: Re: [PATCH V1 04/10] watchdog: da9061: watchdog driver

On 10/06/2016 01:43 AM, Steve Twiss wrote:
> From: Steve Twiss <[email protected]>
>
> Support for the DA9061 watchdog is added into the DA9062 watchdog driver.
>
> The of_device_id match array is expanded to support "dlg,da9061-watchdog"
> as a valid .compatible string. A new watchdog_info structure is added and
> linked to this device tree compatible string in the .data section. Extra
> code is added into the probe function to search-for and assign this match
> data.
>
> Copyright header is updated to add DA9061 in its description and the module
> description macro is extended to include DA9061.
>
> Kconfig is updated to reflect support for DA9061/62.
>
> Signed-off-by: Steve Twiss <[email protected]>
>
> ---
> This patch applies against linux-next and v4.8
>
> Regards,
> Steve Twiss, Dialog Semiconductor Ltd.
>
>
> drivers/watchdog/Kconfig | 4 ++--
> drivers/watchdog/da9062_wdt.c | 24 +++++++++++++++++++++---
> 2 files changed, 23 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> index 1bffe00..d6b4088 100644
> --- a/drivers/watchdog/Kconfig
> +++ b/drivers/watchdog/Kconfig
> @@ -104,11 +104,11 @@ config DA9063_WATCHDOG
> This driver can be built as a module. The module name is da9063_wdt.
>
> config DA9062_WATCHDOG
> - tristate "Dialog DA9062 Watchdog"
> + tristate "Dialog DA9062/61 Watchdog"

Please keep this in numerical order, and use "DA9061/62" Watchdog.
Same everywhere else.

> depends on MFD_DA9062
> select WATCHDOG_CORE
> help
> - Support for the watchdog in the DA9062 PMIC.
> + Support for the watchdog in the DA9062 and DA9061 PMICs.
>
> This driver can be built as a module. The module name is da9062_wdt.
>
> diff --git a/drivers/watchdog/da9062_wdt.c b/drivers/watchdog/da9062_wdt.c
> index 7386111..5b9d408 100644
> --- a/drivers/watchdog/da9062_wdt.c
> +++ b/drivers/watchdog/da9062_wdt.c
> @@ -1,5 +1,5 @@
> /*
> - * da9062_wdt.c - WDT device driver for DA9062
> + * Watchdog device driver for DA9062 and DA9061 PMICs
> * Copyright (C) 2015 Dialog Semiconductor Ltd.
> *
> * This program is free software; you can redistribute it and/or
> @@ -180,6 +180,11 @@ static const struct watchdog_info da9062_watchdog_info = {
> .identity = "DA9062 WDT",
> };
>
> +static const struct watchdog_info da9061_watchdog_info = {
> + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
> + .identity = "DA9061 WDT",

This adds a lot of complexity to the driver just to be able to display "DA9061".
Why not just change the existing identity to "DA9061/DA9062 WDT" ?

> +};
> +
> static const struct watchdog_ops da9062_watchdog_ops = {
> .owner = THIS_MODULE,
> .start = da9062_wdt_start,
> @@ -188,23 +193,35 @@ static const struct watchdog_ops da9062_watchdog_ops = {
> .set_timeout = da9062_wdt_set_timeout,
> };
>
> +static const struct of_device_id da9062_compatible_id_table[] = {
> + { .compatible = "dlg,da9062-watchdog", .data = &da9062_watchdog_info },
> + { .compatible = "dlg,da9061-watchdog", .data = &da9061_watchdog_info },
> + { },
> +};
> +
> static int da9062_wdt_probe(struct platform_device *pdev)
> {
> int ret;
> struct da9062 *chip;
> struct da9062_watchdog *wdt;
> + const struct of_device_id *match;
>
> chip = dev_get_drvdata(pdev->dev.parent);
> if (!chip)
> return -EINVAL;
>
> + match = of_match_node(da9062_compatible_id_table,
> + pdev->dev.of_node);
> + if (!match)
> + return -ENXIO;
> +
> wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
> if (!wdt)
> return -ENOMEM;
>
> wdt->hw = chip;
>
> - wdt->wdtdev.info = &da9062_watchdog_info;
> + wdt->wdtdev.info = (const struct watchdog_info *)match->data;
> wdt->wdtdev.ops = &da9062_watchdog_ops;
> wdt->wdtdev.min_timeout = DA9062_WDT_MIN_TIMEOUT;
> wdt->wdtdev.max_timeout = DA9062_WDT_MAX_TIMEOUT;
> @@ -244,11 +261,12 @@ static struct platform_driver da9062_wdt_driver = {
> .remove = da9062_wdt_remove,
> .driver = {
> .name = "da9062-watchdog",
> + .of_match_table = da9062_compatible_id_table,
> },
> };
> module_platform_driver(da9062_wdt_driver);
>
> MODULE_AUTHOR("S Twiss <[email protected]>");
> -MODULE_DESCRIPTION("WDT device driver for Dialog DA9062");
> +MODULE_DESCRIPTION("WDT device driver for Dialog DA9062 and DA9061");
> MODULE_LICENSE("GPL");
> MODULE_ALIAS("platform:da9062-watchdog");
>

2016-10-06 16:34:31

by Steve Twiss

[permalink] [raw]
Subject: RE: [PATCH V1 01/10] mfd: da9061: MFD core support

Hi,

On 06 October 2016 11:38, Keerthy [mailto:[email protected]], wrote:

> > regmap_config which lists the correct readble, writable and volatile
>
> /s/readble/readable

Done

[...]

> > static struct resource da9062_core_resources[] = {
> > DEFINE_RES_NAMED(DA9062_IRQ_VDD_WARN, 1, "VDD_WARN",
> IORESOURCE_IRQ),
> > };
> > @@ -142,7 +257,7 @@ static const struct mfd_cell da9062_devs[] = {
> > .name = "da9062-watchdog",
> > .num_resources =
> ARRAY_SIZE(da9062_wdt_resources),
> > .resources = da9062_wdt_resources,
> > - .of_compatible = "dlg,da9062-wdt",
> > + .of_compatible = "dlg,da9062-watchdog",
>
> Any particular reason why this compatible needs to be changed?

Yes. It was incorrect in the original DA9062 submission.
The binding said "dlg,da9062-watchdog", but the MFD component implemented it
incorrectly as "dlg,da9062-wdt" in the da9062.txt binding file. This fixes that error.

The watchdog driver did not use the compatible during probe for da9062. But, it now
checks the compatible string as part of this patch set.

[...]

> > +static const struct of_device_id da9062_dt_ids[] = {
> > + { .compatible = "dlg,da9062", .data = (void *)COMPAT_TYPE_DA9062,
> },
> > + { .compatible = "dlg,da9061", .data = (void *)COMPAT_TYPE_DA9061,
> },
>
> WARNING: DT compatible string "dlg,da9061" appears un-documented --
> check ./Documentation/devicetree/bindings/
> #622: FILE: drivers/mfd/da9062-core.c:822:
> + { .compatible = "dlg,da9061", .data = (void *)COMPAT_TYPE_DA9061,
> },
>
> Might want to re-order patches so that you have the compatibles
> documented before usage

Ah. I ordered them last because I thought the driver would need approval before
the device tree docs were accepted. On second look, that doesn't make much sense.

I will change my scripts to complete the checkpatch.pl on the e-mails to be sent to LKML
(instead of the whole files) so this sort of thing doesn't happen again.

I will re-order the patches from V1 when doing V2.

> > + { }
> > +};
> > +MODULE_DEVICE_TABLE(of, da9062_dt_ids);
> > +
> > static int da9062_i2c_probe(struct i2c_client *i2c,
> > const struct i2c_device_id *id)
> > {
> > struct da9062 *chip;
> > + const struct of_device_id *match;
> > unsigned int irq_base;
> > + const struct mfd_cell *cell;
> > + const struct regmap_irq_chip *irq_chip;
> > + const struct regmap_config *config;
> > + int cell_num;
>
> No need of cell_num.
[...]

> > + cell_num = ARRAY_SIZE(da9061_devs);
>
> No need of the above assignment
[...]

> > + cell_num = ARRAY_SIZE(da9062_devs);
>
> No need of the above assignment
>
> > + ret = mfd_add_devices(chip->dev, PLATFORM_DEVID_NONE, cell,
> > + cell_num, NULL, irq_base,
>
> Use ARRAY_SIZE(cell) instead if cell_num

Okay. Can do that.
It will appear in V2.

Regards,
Steve

2016-10-07 05:30:17

by Keerthy

[permalink] [raw]
Subject: Re: [PATCH V1 05/10] thermal: da9062/61: Thermal junction temperature monitoring driver

Steve,

On Thursday 06 October 2016 02:13 PM, Steve Twiss wrote:
> From: Steve Twiss <[email protected]>
>
> Add junction temperature monitoring supervisor device driver, compatible
> with the DA9062 and DA9061 PMICs.
>
> If the PMIC's internal junction temperature rises above TEMP_WARN (125
> degC) an interrupt is issued. This TEMP_WARN level is defined as the
> THERMAL_TRIP_HOT trip-wire inside the device driver. A kernel work queue
> is configured to repeatedly poll this temperature trip-wire, between 1 and
> 10 second intervals (defaulting at 3 seconds).
>
> This first level of temperature supervision is intended for non-invasive
> temperature control, where the necessary measures for cooling the system
> down are left to the host software. In this case, inside the thermal
> notification function da9062_thermal_notify().
>
> Signed-off-by: Steve Twiss <[email protected]>
>
> ---
> This patch applies against linux-next and v4.8
>
> Regards,
> Steve Twiss, Dialog Semiconductor Ltd.
>
>
> drivers/thermal/Kconfig | 10 ++
> drivers/thermal/Makefile | 1 +
> drivers/thermal/da9062-thermal.c | 313 +++++++++++++++++++++++++++++++++++++++
> 3 files changed, 324 insertions(+)
> create mode 100644 drivers/thermal/da9062-thermal.c
>
> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> index 2d702ca..da58e54 100644
> --- a/drivers/thermal/Kconfig
> +++ b/drivers/thermal/Kconfig
> @@ -272,6 +272,16 @@ config DB8500_CPUFREQ_COOLING
> bound cpufreq cooling device turns active to set CPU frequency low to
> cool down the CPU.
>
> +config DA9062_THERMAL
> + tristate "DA9062/DA9061 Dialog Semiconductor thermal driver"
> + depends on MFD_DA9062
> + depends on OF
> + help
> + Enable this for the Dialog Semiconductor thermal sensor driver.
> + This will report PMIC junction over-temperature for one thermal trip
> + zone.
> + Compatible with the DA9062 and DA9061 PMICs.
> +
> config INTEL_POWERCLAMP
> tristate "Intel PowerClamp idle injection driver"
> depends on THERMAL
> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> index 10b07c1..0a2b3f2 100644
> --- a/drivers/thermal/Makefile
> +++ b/drivers/thermal/Makefile
> @@ -38,6 +38,7 @@ obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o
> obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o
> obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o
> obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o
> +obj-$(CONFIG_DA9062_THERMAL) += da9062-thermal.o
> obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o
> obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o
> obj-$(CONFIG_INTEL_SOC_DTS_IOSF_CORE) += intel_soc_dts_iosf.o
> diff --git a/drivers/thermal/da9062-thermal.c b/drivers/thermal/da9062-thermal.c
> new file mode 100644
> index 0000000..feeabf6
> --- /dev/null
> +++ b/drivers/thermal/da9062-thermal.c
> @@ -0,0 +1,313 @@
> +/*
> + * Thermal device driver for DA9062 and DA9061
> + * Copyright (C) 2016 Dialog Semiconductor Ltd.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/errno.h>
> +#include <linux/interrupt.h>
> +#include <linux/platform_device.h>
> +#include <linux/workqueue.h>
> +#include <linux/regmap.h>
> +#include <linux/thermal.h>
> +#include <linux/of.h>
> +
> +#include <linux/mfd/da9062/core.h>
> +#include <linux/mfd/da9062/registers.h>
> +
> +#define DA9062_DEFAULT_POLLING_MS_PERIOD 3000
> +#define DA9062_MAX_POLLING_MS_PERIOD 10000
> +#define DA9062_MIN_POLLING_MS_PERIOD 1000
> +
> +#define DA9062_MILLI_CELSIUS(t) ((t)*1000)
> +
> +struct da9062_thermal_config {
> + const char *name;
> +};
> +
> +struct da9062_thermal {
> + struct da9062 *hw;
> + struct delayed_work work;
> + struct thermal_zone_device *zone;
> + enum thermal_device_mode mode;
> + unsigned int polling_period;
> + struct mutex lock;
> + int temperature;
> + int irq;
> + const struct da9062_thermal_config *config;
> + struct device *dev;
> +};
> +
> +static void da9062_thermal_poll_on(struct work_struct *work)
> +{
> + struct da9062_thermal *thermal = container_of(work,
> + struct da9062_thermal,
> + work.work);
> + unsigned int val;
> + int ret;
> +
> + /* clear E_TEMP */
> + ret = regmap_write(thermal->hw->regmap,
> + DA9062AA_EVENT_B,
> + DA9062AA_E_TEMP_MASK);
> + if (ret < 0) {
> + dev_err(thermal->dev,
> + "Cannot clear the TJUNC temperature status\n");
> + goto err_enable_irq;
> + }
> +
> + /* Now read E_TEMP again: it is acting like a status bit.
> + * If over-temperature, then this status will be true.
> + * If not over-temperature, this staus will be false.
> + */
> + ret = regmap_read(thermal->hw->regmap,
> + DA9062AA_EVENT_B,
> + &val);
> + if (ret < 0) {
> + dev_err(thermal->dev,
> + "Cannot check the TJUNC temperature status\n");
> + goto err_enable_irq;
> + } else {
> + if (val & DA9062AA_E_TEMP_MASK) {
> + mutex_lock(&thermal->lock);
> + thermal->temperature = DA9062_MILLI_CELSIUS(125);
> + mutex_unlock(&thermal->lock);
> + thermal_zone_device_update(thermal->zone);
> +
> + schedule_delayed_work(&thermal->work,
> + msecs_to_jiffies(thermal->polling_period));
> + return;
> + } else {
> + mutex_lock(&thermal->lock);
> + thermal->temperature = DA9062_MILLI_CELSIUS(0);
> + mutex_unlock(&thermal->lock);
> + thermal_zone_device_update(thermal->zone);
> + }
> + }
> +
> +err_enable_irq:
> + enable_irq(thermal->irq);
> +}
> +
> +static irqreturn_t da9062_thermal_irq_handler(int irq, void *data)
> +{
> + struct da9062_thermal *thermal = data;
> +
> + disable_irq_nosync(thermal->irq);
> + schedule_delayed_work(&thermal->work, 0);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int da9062_thermal_get_mode(struct thermal_zone_device *z,
> + enum thermal_device_mode *mode)
> +{
> + struct da9062_thermal *thermal = z->devdata;
> + *mode = thermal->mode;
> + return 0;
> +}
> +
> +static int da9062_thermal_get_trip_type(struct thermal_zone_device *z,
> + int trip,
> + enum thermal_trip_type *type)
> +{
> + struct da9062_thermal *thermal = z->devdata;
> +
> + switch (trip) {
> + case 0:
> + *type = THERMAL_TRIP_HOT;

125C is pretty hot. Just a suggestion, do look at THERMAL_TRIP_CRITICAL.

> + break;
> + default:
> + dev_err(thermal->dev,
> + "Driver does not support more than 1 trip-wire\n");
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static int da9062_thermal_get_trip_temp(struct thermal_zone_device *z,
> + int trip,
> + int *temp)
> +{
> + struct da9062_thermal *thermal = z->devdata;
> +
> + switch (trip) {
> + case 0:
> + *temp = DA9062_MILLI_CELSIUS(125);
> + break;
> + default:
> + dev_err(thermal->dev,
> + "Driver does not support more than 1 trip-wire\n");
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static int da9062_thermal_notify(struct thermal_zone_device *z,
> + int trip,
> + enum thermal_trip_type type)
> +{
> + struct da9062_thermal *thermal = z->devdata;
> +
> + switch (type) {
> + case THERMAL_TRIP_HOT:
> + dev_warn(thermal->dev, "Reached HOT (125degC) temperature\n");

Any cooling action? What is done once you reach this high temperature?

> + break;
> + default:
> + break;
> + }
> +
> + return 0;
> +}
> +
> +static int da9062_thermal_get_temp(struct thermal_zone_device *z,
> + int *temp)
> +{
> + struct da9062_thermal *thermal = z->devdata;
> +
> + mutex_lock(&thermal->lock);
> + *temp = thermal->temperature;
> + mutex_unlock(&thermal->lock);
> +
> + return 0;
> +}
> +
> +static struct thermal_zone_device_ops da9062_thermal_ops = {
> + .get_temp = da9062_thermal_get_temp,
> + .get_mode = da9062_thermal_get_mode,
> + .get_trip_type = da9062_thermal_get_trip_type,
> + .get_trip_temp = da9062_thermal_get_trip_temp,
> + .notify = da9062_thermal_notify,
> +};
> +
> +static const struct da9062_thermal_config da9062_config = {
> + .name = "da9062-thermal",
> +};
> +
> +static const struct da9062_thermal_config da9061_config = {
> + .name = "da9061-thermal",
> +};
> +
> +static const struct of_device_id da9062_compatible_reg_id_table[] = {
> + { .compatible = "dlg,da9062-thermal", .data = &da9062_config },
> + { .compatible = "dlg,da9061-thermal", .data = &da9061_config },

Two separate compatible values. Do you have anything different apart
from the name? Why use 2 compatibles when there is absolutely no difference?

> + { },
> +};
> +
> +static int da9062_thermal_probe(struct platform_device *pdev)
> +{
> + struct da9062 *chip = dev_get_drvdata(pdev->dev.parent);
> + struct da9062_thermal *thermal;
> + unsigned int pp_tmp = DA9062_DEFAULT_POLLING_MS_PERIOD;
> + const struct of_device_id *match;
> + int ret = 0;
> +
> + match = of_match_node(da9062_compatible_reg_id_table,
> + pdev->dev.of_node);
> + if (!match)
> + return -ENXIO;
> +
> + if (pdev->dev.of_node) {
> + if (!of_property_read_u32(pdev->dev.of_node,
> + "dlg,tjunc-temp-polling-period-ms",
> + &pp_tmp)) {
> + if (pp_tmp < DA9062_MIN_POLLING_MS_PERIOD ||
> + pp_tmp > DA9062_MAX_POLLING_MS_PERIOD)
> + pp_tmp = DA9062_DEFAULT_POLLING_MS_PERIOD;
> + }
> +
> + dev_dbg(&pdev->dev,
> + "TJUNC temp polling period set at %d ms\n",
> + pp_tmp);
> + }
> +
> + thermal = devm_kzalloc(&pdev->dev, sizeof(struct da9062_thermal),
> + GFP_KERNEL);
> + if (!thermal) {
> + ret = -ENOMEM;
> + goto err;
> + }
> +
> + thermal->config = match->data;
> +
> + INIT_DELAYED_WORK(&thermal->work, da9062_thermal_poll_on);
> + mutex_init(&thermal->lock);

thermal_zone_device_register itself does
INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);

refer: drivers/thermal/thermal_core.c

It does a periodic monitoring of the temperature as well. Do you really
want to have an additional work for monitoring temperature in your
driver also?

> +
> + thermal->zone = thermal_zone_device_register(thermal->config->name,
> + 1, 0, thermal,
> + &da9062_thermal_ops, NULL, 0,
> + 0);
> + if (IS_ERR(thermal->zone)) {
> + dev_err(&pdev->dev, "Cannot register thermal zone device\n");
> + ret = PTR_ERR(thermal->zone);
> + goto err;
> + }
> +
> + ret = platform_get_irq_byname(pdev, "THERMAL");
> + if (ret < 0) {
> + dev_err(&pdev->dev, "Failed to get platform IRQ.\n");
> + goto err_zone;
> + }
> + thermal->irq = ret;
> +
> + ret = request_threaded_irq(thermal->irq, NULL,
> + da9062_thermal_irq_handler,
> + IRQF_TRIGGER_LOW | IRQF_ONESHOT,
> + "THERMAL", thermal);
> + if (ret) {
> + dev_err(&pdev->dev,
> + "Failed to request thermal device IRQ.\n");
> + goto err_zone;
> + }
> +
> + thermal->hw = chip;
> + thermal->polling_period = pp_tmp;
> + thermal->mode = THERMAL_DEVICE_ENABLED;
> + thermal->dev = &pdev->dev;
> +
> + platform_set_drvdata(pdev, thermal);
> + return 0;
> +
> +err_zone:
> + thermal_zone_device_unregister(thermal->zone);
> +err:
> + return ret;
> +}
> +
> +static int da9062_thermal_remove(struct platform_device *pdev)
> +{
> + struct da9062_thermal *thermal = platform_get_drvdata(pdev);
> +
> + free_irq(thermal->irq, thermal);
> + thermal_zone_device_unregister(thermal->zone);
> + cancel_delayed_work_sync(&thermal->work);
> + return 0;
> +}
> +
> +static struct platform_driver da9062_thermal_driver = {
> + .probe = da9062_thermal_probe,
> + .remove = da9062_thermal_remove,
> + .driver = {
> + .name = "da9062-thermal",
> + .of_match_table = da9062_compatible_reg_id_table,
> + },
> +};
> +
> +module_platform_driver(da9062_thermal_driver);
> +
> +MODULE_AUTHOR("Steve Twiss, Dialog Semiconductor");
> +MODULE_DESCRIPTION("Thermal TJUNC device driver for Dialog DA9062 and DA9061");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("platform:da9062-thermal");
>

2016-10-07 14:33:26

by Steve Twiss

[permalink] [raw]
Subject: RE: [PATCH V1 01/10] mfd: da9061: MFD core support

Hi,

On 06 October 2016 17:34, Steve Twiss wrote:
> On 06 October 2016 11:38, Keerthy [mailto:[email protected]], wrote:
> > + int cell_num;
> > No need of cell_num.
>
> > + cell_num = ARRAY_SIZE(da9061_devs);
> > No need of the above assignment
>
> > + cell_num = ARRAY_SIZE(da9062_devs);
> > No need of the above assignment
> >
> > + ret = mfd_add_devices(chip->dev, PLATFORM_DEVID_NONE, cell,
> > + cell_num, NULL, irq_base,
> > Use ARRAY_SIZE(cell) instead if cell_num
>
> Okay. Can do that.

Okay. I cannot do that.
Dropped that change.

drivers/mfd/da9062-core.c: In function 'da9062_i2c_probe':
./include/linux/bug.h:34:45: error: negative width in bit-field '<anonymous>'
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
^
./include/linux/compiler-gcc.h:64:28: note: in expansion of macro 'BUILD_BUG_ON_ZERO'
#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
^
./include/linux/kernel.h:53:59: note: in expansion of macro '__must_be_array'
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
^
drivers/mfd/da9062-core.c:919:10: note: in expansion of macro 'ARRAY_SIZE'
ARRAY_SIZE(cell), NULL, irq_base,
^

2016-10-07 17:49:13

by Steve Twiss

[permalink] [raw]
Subject: RE: [PATCH V1 05/10] thermal: da9062/61: Thermal junction temperature monitoring driver

Hi,

On 07 October 2016 06:29, Keerthy [mailto:[email protected]] wrote:
> On Thursday 06 October 2016 02:13 PM, Steve Twiss wrote:
> > From: Steve Twiss <[email protected]>

[...]

> > +
> > +static int da9062_thermal_get_trip_type(struct thermal_zone_device *z,
> > + int trip,
> > + enum thermal_trip_type *type)
> > +{
> > + struct da9062_thermal *thermal = z->devdata;
> > +
> > + switch (trip) {
> > + case 0:
> > + *type = THERMAL_TRIP_HOT;
>
> 125C is pretty hot. Just a suggestion, do look at THERMAL_TRIP_CRITICAL.
>

Quite warm.
I got this from the Documentation/devicetree/bindings/thermal/thermal.txt
"hot": A trip point to notify emergency
"critical": Hardware not reliable.

The junction temperature supervision characteristics for DA9061 supports three
levels and 125degC is the lowest "warning" level. This warning level is intended
for non-invasive temperature control where the necessary mitigation is under
software control of the system.

The other two levels are hotter than 125degC and it is not possible to intervene
using software. The hardware will automatically power off.

[...]

> > +static int da9062_thermal_notify(struct thermal_zone_device *z,
> > + int trip,
> > + enum thermal_trip_type type)
> > +{
> > + struct da9062_thermal *thermal = z->devdata;
> > +
> > + switch (type) {
> > + case THERMAL_TRIP_HOT:
> > + dev_warn(thermal->dev, "Reached HOT (125degC)
> temperature\n");
>
> Any cooling action? What is done once you reach this high temperature?

There is nothing to do in the device driver. This is just a stub for board specific additions
to mitigate the temperature. There is a similar function in the RCAR thermal driver which
contains a FIXME comment. But, apart from helping with my testing, it doesn't add
anything in the driver. It can be removed.

[...]

> > +static const struct da9062_thermal_config da9062_config = {
> > + .name = "da9062-thermal",
> > +};
> > +
> > +static const struct da9062_thermal_config da9061_config = {
> > + .name = "da9061-thermal",
> > +};
> > +
> > +static const struct of_device_id da9062_compatible_reg_id_table[] = {
> > + { .compatible = "dlg,da9062-thermal", .data = &da9062_config },
> > + { .compatible = "dlg,da9061-thermal", .data = &da9061_config },
>
> Two separate compatible values. Do you have anything different apart
> from the name? Why use 2 compatibles when there is absolutely no
> difference?

Yes.
This was a comment for the watchdog device driver as well. My concern was having
multiple devices (61 and 62) in the same system -- and allowing the driver to report
the hardware difference.

There is discussion going on about this in other threads. Not certain of the final outcome
yet, apart from my existing proposal should be changed.

-- From Guenter Roeck:
-- http://www.spinics.net/lists/linux-watchdog/msg10040.html

[...]

> > + INIT_DELAYED_WORK(&thermal->work, da9062_thermal_poll_on);
> > + mutex_init(&thermal->lock);
>
> thermal_zone_device_register itself does
> INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
>
> refer: drivers/thermal/thermal_core.c
>
> It does a periodic monitoring of the temperature as well. Do you really
> want to have an additional work for monitoring temperature in your
> driver also?

I will take a look at this for V2.

Regards,
Steve

2016-10-08 02:57:47

by Keerthy

[permalink] [raw]
Subject: Re: [PATCH V1 01/10] mfd: da9061: MFD core support



On Friday 07 October 2016 08:02 PM, Steve Twiss wrote:
> Hi,
>
> On 06 October 2016 17:34, Steve Twiss wrote:
>> On 06 October 2016 11:38, Keerthy [mailto:[email protected]], wrote:
>>> + int cell_num;
>>> No need of cell_num.
>>
>>> + cell_num = ARRAY_SIZE(da9061_devs);
>>> No need of the above assignment
>>
>>> + cell_num = ARRAY_SIZE(da9062_devs);
>>> No need of the above assignment
>>>
>>> + ret = mfd_add_devices(chip->dev, PLATFORM_DEVID_NONE, cell,
>>> + cell_num, NULL, irq_base,
>>> Use ARRAY_SIZE(cell) instead if cell_num
>>
>> Okay. Can do that.
>
> Okay. I cannot do that.
> Dropped that change.
>
> drivers/mfd/da9062-core.c: In function 'da9062_i2c_probe':
> ./include/linux/bug.h:34:45: error: negative width in bit-field '<anonymous>'
> #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
> ^
> ./include/linux/compiler-gcc.h:64:28: note: in expansion of macro 'BUILD_BUG_ON_ZERO'
> #define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
> ^
> ./include/linux/kernel.h:53:59: note: in expansion of macro '__must_be_array'
> #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
> ^
> drivers/mfd/da9062-core.c:919:10: note: in expansion of macro 'ARRAY_SIZE'
> ARRAY_SIZE(cell), NULL, irq_base,
> ^

Okay. yes i got it.

>

2016-10-10 13:37:22

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH V1 06/10] Documentation: dt: input: temperature driver

On Thu, Oct 06, 2016 at 09:43:30AM +0100, Steve Twiss wrote:
> From: Steve Twiss <[email protected]>

The subject is wrong.

>
> Add binding information for DA9061 onkey.
>
> This patch updates the compatible string "dlg,da9061-onkey" to support
> DA9061, removes ther reference to KEY_SLEEP (which the driver no longer

s/ther/the/

> supports) and fixes a typo in the example.

Why is KEY_SLEEP being removed?

>
> Signed-off-by: Steve Twiss <[email protected]>
>
> ---
> This patch applies against linux-next and v4.8
>
> Hi,
>
> This patch depends on the acceptance of the main code for the onkey:
> [PATCH V1 3/10] Input: da9061: onkey driver.
>
> Regards,
> Steve Twiss, Dialog Semiconductor Ltd.
>
>
> .../devicetree/bindings/input/da9062-onkey.txt | 19 +++++++++----------
> 1 file changed, 9 insertions(+), 10 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/input/da9062-onkey.txt b/Documentation/devicetree/bindings/input/da9062-onkey.txt
> index ab0e048..ce45436 100644
> --- a/Documentation/devicetree/bindings/input/da9062-onkey.txt
> +++ b/Documentation/devicetree/bindings/input/da9062-onkey.txt
> @@ -1,28 +1,27 @@
> -* Dialog DA9062/63 OnKey Module
> +* Dialog DA9061/62/63 OnKey Module
>
> -This module is part of the DA9062/DA9063. For more details about entire
> -chips see Documentation/devicetree/bindings/mfd/da9062.txt and
> -Documentation/devicetree/bindings/mfd/da9063.txt
> +This module is part of the DA9061/DA9062/DA9063. For more details about entire
> +DA9062 and DA9061 chips see Documentation/devicetree/bindings/mfd/da9062.txt
> +For DA9063 see Documentation/devicetree/bindings/mfd/da9063.txt
>
> -This module provides KEY_POWER, KEY_SLEEP and events.
> +This module provides the KEY_POWER event.
>
> Required properties:
>
> - compatible: should be one of:
> + dlg,da9061-onkey
> dlg,da9062-onkey
> dlg,da9063-onkey
>
> Optional properties:
>
> - - dlg,disable-key-power : Disable power-down using a long key-press. If this
> +- dlg,disable-key-power : Disable power-down using a long key-press. If this
> entry exists the OnKey driver will remove support for the KEY_POWER key
> - press. If this entry does not exist then by default the key-press
> - triggered power down is enabled and the OnKey will support both KEY_POWER
> - and KEY_SLEEP.
> + press when triggered using a long press of the OnKey.
>
> Example:
>
> - pmic0: da9062@58 {
> + pmic0: da9063@58 {
>
> onkey {
> compatible = "dlg,da9063-onkey";
> --
> end-of-patch for PATCH V1
>

2016-10-10 13:38:56

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH V1 08/10] Documentation: dt: thermal: da9062/61 TJUNC temperature binding

On Thu, Oct 06, 2016 at 09:43:31AM +0100, Steve Twiss wrote:
> From: Steve Twiss <[email protected]>
>
> Device tree binding information for DA9062 and DA9061 thermal junction
> temperature monitor.
>
> Binding descriptions for the DA9061 and DA9062 thermal TJUNC supervisor
> device driver, using a single THERMAL_TRIP_HOT trip-wire and allowing for a
> configurable polling period for over-temperature polling.
>
> Signed-off-by: Steve Twiss <[email protected]>
>
> ---
> This patch applies against linux-next and v4.8
>
> Hi,
>
> This patch depends on the acceptance of the main code for the onkey:
> [PATCH V1 5/10] thermal: da9061: TJUNC temperature driver
>
> Regards,
> Steve Twiss, Dialog Semiconductor Ltd.
>
>
> .../devicetree/bindings/thermal/da9062-thermal.txt | 30 ++++++++++++++++++++++
> 1 file changed, 30 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/thermal/da9062-thermal.txt

Acked-by: Rob Herring <[email protected]>

2016-10-10 13:39:49

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH V1 07/10] Documentation: dt: watchdog: da9062/61 Watchdog timer binding

On Thu, Oct 06, 2016 at 09:43:31AM +0100, Steve Twiss wrote:
> From: Steve Twiss <[email protected]>
>
> Add binding information for DA9062 and DA9061 watchdog.
>
> Signed-off-by: Steve Twiss <[email protected]>
>
> ---
> This patch applies against linux-next and v4.8
>
> Hi,
>
> This patch depends on the acceptance of DA9061 watchdog driver:
> [PATCH V1 4/10] watchdog: da9061: watchdog driver
>
> Regards,
> Steve Twiss, Dialog Semiconductor Ltd.
>
>
> Documentation/devicetree/bindings/watchdog/da9062-wdt.txt | 11 +++++++++++
> 1 file changed, 11 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/watchdog/da9062-wdt.txt

Acked-by: Rob Herring <[email protected]>

2016-10-10 13:42:40

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH V1 09/10] Documentation: dt: mfd: da9062/61 MFD binding

On Thu, Oct 06, 2016 at 09:43:31AM +0100, Steve Twiss wrote:
> From: Steve Twiss <[email protected]>
>
> Extend existing DA9062 binding information to include the DA9061 PMIC for
> MFD core and regulators.
>
> Add a da9062-onkey link to the existing onkey binding file.
>
> Add a da9062-thermal link to the new temperature monitoring binding file
> found in [PATCH V1 8/10].
>
> Delete the da9062-watchdog section and replace it with a link to the new
> DA9061/62 binding information file added by [PATCH V1 7/10].
>
> Signed-off-by: Steve Twiss <[email protected]>
>
> ---
> This patch applies against linux-next and v4.8
>
> Hi,
>
> This patch depends on acceptance of the main code for the DA9061 MFD:
>
> - [PATCH V1 1/10] mfd: da9061: MFD core support
>
> and also from the following binding file changes:
>
> - [PATCH V1 6/10] Binding for onkey
> - [PATCH V1 7/10] Binding for watchdog
> - [PATCH V1 8/10] Binding for thermal
>
> Regards,
> Steve Twiss, Dialog Semiconductor Ltd.
>
>
> Documentation/devicetree/bindings/mfd/da9062.txt | 45 +++++++++++++++++-------
> 1 file changed, 33 insertions(+), 12 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/mfd/da9062.txt b/Documentation/devicetree/bindings/mfd/da9062.txt
> index 38802b5..38ba5e2 100644
> --- a/Documentation/devicetree/bindings/mfd/da9062.txt
> +++ b/Documentation/devicetree/bindings/mfd/da9062.txt

[...]

> Example:
> @@ -64,10 +89,6 @@ Example:
> compatible = "dlg,da9062-rtc";
> };
>
> - watchdog {
> - compatible = "dlg,da9062-watchdog";
> - };
> -

I don't understand why this is removed?

> regulators {
> DA9062_BUCK1: buck1 {
> regulator-name = "BUCK1";
> --
> end-of-patch for PATCH V1
>

2016-10-11 11:50:48

by Steve Twiss

[permalink] [raw]
Subject: RE: [PATCH V1 06/10] Documentation: dt: input: temperature driver

Hi,

On 10 October 2016 14:37 Rob Herring wrote:
> On Thu, Oct 06, 2016 at 09:43:30AM +0100, Steve Twiss wrote:
> > From: Steve Twiss <[email protected]>
>
> The subject is wrong.

Copy/paste error -- I will fix that.

> > Add binding information for DA9061 onkey.
> >
> > This patch updates the compatible string "dlg,da9061-onkey" to support
> > DA9061, removes ther reference to KEY_SLEEP (which the driver no longer
>
> s/ther/the/

And this.

> > supports) and fixes a typo in the example.
>
> Why is KEY_SLEEP being removed?

Supporting KEY_SLEEP was not the general convention and the typical solution should have been
for KEY_POWER to support both cases of suspend and S/W power off.
I changed the driver, but failed to update the documentation at that time, so am now updating this
as part of the DA9061.

I will add that information in the next V2 patch e-mail.

Regards,
Steve

2016-10-14 12:26:32

by Steve Twiss

[permalink] [raw]
Subject: RE: [PATCH V1 09/10] Documentation: dt: mfd: da9062/61 MFD binding

Hi Rob,

On 10 October 2016 14:43, Rob Herring wrote:
> On Thu, Oct 06, 2016 at 09:43:31AM +0100, Steve Twiss wrote:
[...]
> > @@ -64,10 +89,6 @@ Example:
> > compatible = "dlg,da9062-rtc";
> > };
> >
> > - watchdog {
> > - compatible = "dlg,da9062-watchdog";
> > - };
> > -
>
> I don't understand why this is removed?

This MFD binding file now contains a link to a separate watchdog binding file.
I moved the example and the binding information into this new watchdog binding
document. I also updated it for DA9061.

+- watchdog: See ../watchdog/da9062-watchdog.txt

I will add this information into the patch description for V2 to make things clearer.

Regards,
Steve

2016-10-14 13:08:50

by Steve Twiss

[permalink] [raw]
Subject: RE: [PATCH V1 05/10] thermal: da9062/61: Thermal junction temperature monitoring driver

An update.

On: 07 October 2016 18:49, Steve Twiss wrote:
> On 07 October 2016 06:29, Keerthy [mailto:[email protected]] wrote:
> > On Thursday 06 October 2016 02:13 PM, Steve Twiss wrote:
> > > From: Steve Twiss <[email protected]>
[...]
> > > +static const struct da9062_thermal_config da9062_config = {
> > > + .name = "da9062-thermal",
> > > +};
> > > +
> > > +static const struct da9062_thermal_config da9061_config = {
> > > + .name = "da9061-thermal",
> > > +};
> > > +
> > > +static const struct of_device_id da9062_compatible_reg_id_table[] = {
> > > + { .compatible = "dlg,da9062-thermal", .data = &da9062_config },
> > > + { .compatible = "dlg,da9061-thermal", .data = &da9061_config },
> >
> > Two separate compatible values. Do you have anything different apart
> > from the name? Why use 2 compatibles when there is absolutely no
> > difference?
>
> Yes.
> This was a comment for the watchdog device driver as well. My concern was having
> multiple devices (61 and 62) in the same system -- and allowing the driver to report
> the hardware difference.
>
> There is discussion going on about this in other threads. Not certain of the
> final outcome yet, apart from my existing proposal should be changed.

An answer to this came from comments by Dmitry Torokhov and Guenter Roeck, who
suggested this: https://lkml.org/lkml/2016/10/7/641

I will take a look at this for V2.

Regards,
Steve

2016-10-20 13:02:48

by Steve Twiss

[permalink] [raw]
Subject: RE: [PATCH V1 05/10] thermal: da9062/61: Thermal junction temperature monitoring driver

On 07 October 2016 06:29 Keerthy wrote:

> On Thursday 06 October 2016 02:13 PM, Steve Twiss wrote:
> > From: Steve Twiss <[email protected]>
> >
> > +static int da9062_thermal_probe(struct platform_device *pdev)
> > +{
> > + struct da9062 *chip = dev_get_drvdata(pdev->dev.parent);
> > + struct da9062_thermal *thermal;
> > + unsigned int pp_tmp = DA9062_DEFAULT_POLLING_MS_PERIOD;
> > + const struct of_device_id *match;
> > + int ret = 0;
> > +
> > + match = of_match_node(da9062_compatible_reg_id_table,
> > + pdev->dev.of_node);
> > + if (!match)
> > + return -ENXIO;
> > +
> > + if (pdev->dev.of_node) {
> > + if (!of_property_read_u32(pdev->dev.of_node,
> > + "dlg,tjunc-temp-polling-period-ms",
> > + &pp_tmp)) {
> > + if (pp_tmp < DA9062_MIN_POLLING_MS_PERIOD ||
> > + pp_tmp > DA9062_MAX_POLLING_MS_PERIOD)
> > + pp_tmp = DA9062_DEFAULT_POLLING_MS_PERIOD;
> > + }
> > +
> > + dev_dbg(&pdev->dev,
> > + "TJUNC temp polling period set at %d ms\n",
> > + pp_tmp);
> > + }
> > +
> > + thermal = devm_kzalloc(&pdev->dev, sizeof(struct da9062_thermal),
> > + GFP_KERNEL);
> > + if (!thermal) {
> > + ret = -ENOMEM;
> > + goto err;
> > + }
> > +
> > + thermal->config = match->data;
> > +
> > + INIT_DELAYED_WORK(&thermal->work, da9062_thermal_poll_on);
> > + mutex_init(&thermal->lock);
>
> thermal_zone_device_register itself does
> INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
>
> refer: drivers/thermal/thermal_core.c
>
> It does a periodic monitoring of the temperature as well. Do you really
> want to have an additional work for monitoring temperature in your
> driver also?

The thermal triggering mechanism is interrupt based and happens when the
temperature rises above a given threshold level. The component cannot
return an exact temperature, it only has knowledge if the temperature is
above or below a given threshold value. A status bit must be polled to
detect when the temperature falls below that threshold level again.

If I was to use the core's polling_delay it would request get_temp() every
x milliseconds. This would work: I could test the status bit to decide if
the temperature was above or below the threshold, and enable or disable the
interrupt accordingly. But during normal operation, when the temperature
is in the normal range, I would be polling through I2C every x milliseconds
instead of just waiting for an IRQ trigger event before starting my polling
operations to detect when the temperature level fell below the threshold.

Since an over-temperature is supposed to be a very rare event, I decided to
go with the IRQ based trigger and then kick-off a separate work-queue to
poll the status bit and detect when the temperature dropped below the
threshold level. This seemed a more efficient way of handling this.

I have looked through thermal core, and there doesn't seem to be an obvious
way of toggling on/off thermal core polling when I need to poll the
temperature through get_temp(). So, I was going to stick with this method for
PATCH V2.

Regards,
Steve

2016-10-20 14:21:37

by Steve Twiss

[permalink] [raw]
Subject: RE: [PATCH V1 05/10] thermal: da9062/61: Thermal junction temperature monitoring driver

On 20 October 2016 14:03 Steve Twiss wrote:

> On 07 October 2016 06:29 Keerthy wrote:
> > On Thursday 06 October 2016 02:13 PM, Steve Twiss wrote:
> > > From: Steve Twiss <[email protected]>
> > >
> > > + INIT_DELAYED_WORK(&thermal->work, da9062_thermal_poll_on);
> > > + mutex_init(&thermal->lock);
> >
> > thermal_zone_device_register itself does
> > INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
> >
> > refer: drivers/thermal/thermal_core.c
> >
> > It does a periodic monitoring of the temperature as well. Do you really
> > want to have an additional work for monitoring temperature in your
> > driver also?
>
> The thermal triggering mechanism is interrupt based and happens when the
> temperature rises above a given threshold level. The component cannot
> return an exact temperature, it only has knowledge if the temperature is
> above or below a given threshold value. A status bit must be polled to
> detect when the temperature falls below that threshold level again.
>
> If I was to use the core's polling_delay it would request get_temp() every
> x milliseconds. This would work: I could test the status bit to decide if
> the temperature was above or below the threshold, and enable or disable
> the interrupt accordingly. But during normal operation, when the temperature
> is in the normal range, I would be polling through I2C every x milliseconds
> instead of just waiting for an IRQ trigger event before starting my polling
> operations to detect when the temperature level fell below the threshold.
>
> Since an over-temperature is supposed to be a very rare event, I decided to
> go with the IRQ based trigger and then kick-off a separate work-queue to
> poll the status bit and detect when the temperature dropped below the
> threshold level. This seemed a more efficient way of handling this.
>
> I have looked through thermal core, and there doesn't seem to be an
> obvious way of toggling on/off thermal core polling when I need to poll the
> temperature through get_temp(). So, I was going to stick with this method
> for PATCH V2.

Ok. There doesn't seem to be any formal way to do this in the thermal core,
but after a second look, it seems like I can hijack the polling_delay value and
turn the polling on and off from my device driver. There is no API to do this,
but it seems to be possible.

I start with polling off, wait for an over-temperature IRQ trigger and tweak
the polling_delay value, say, like this:

static irqreturn_t da9062_thermal_irq_handler(int irq, void *data) {
struct da9062_thermal *thermal = data;
disable_irq_nosync(thermal->irq);
thermal->zone->polling_delay = 3000;
thermal_zone_device_update(thermal->zone);
return IRQ_HANDLED;
}

Then when polling starts and get_temp() is called, I can re-enable the IRQ again
if the temperature has dropped.
At that point I can also turn off the thermal core polling by re-writing the
polling_delay. Like this:

static int da9062_thermal_get_temp(struct thermal_zone_device *z,
int *temp)
{
struct da9062_thermal *thermal = z->devdata;
...
/* if temp has dropped */
thermal->zone->polling_delay = 0;
enable_irq(thermal->irq);
}

I'm not certain if this is acceptable, accessing the thermal core like this.
I will send this patch separately as a RFC I think.

Regards,
Steve