All of lore.kernel.org
 help / color / mirror / Atom feed
From: Vincent Pelletier <plr.vincent@gmail.com>
To: Jean Delvare <jdelvare@suse.com>,
	Guenter Roeck <linux@roeck-us.net>,
	Jonathan Corbet <corbet@lwn.net>,
	Support Opensource <support.opensource@diasemi.com>,
	Lee Jones <lee.jones@linaro.org>,
	linux-hwmon@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	"Opensource [Steve Twiss]" <stwiss.opensource@diasemi.com>
Subject: [PATCH 2/3] hwmon: da9063: HWMON driver
Date: Tue,  6 Jul 2021 14:34:48 +0000	[thread overview]
Message-ID: <dff04323fc1b0177c1c08d3670333a839af4c268.1625581991.git.plr.vincent@gmail.com> (raw)
In-Reply-To: <850a353432cd676f96889cede291232abf58918d.1625581991.git.plr.vincent@gmail.com>

From: "Opensource [Steve Twiss]" <stwiss.opensource@diasemi.com>

Add the HWMON driver for DA9063

Signed-off-by: Opensource [Steve Twiss] <stwiss.opensource@diasemi.com>

Simplify and modernise the code a bit.
Fix logic inversion in detecting conversion end.
Drop support for ADCIN: these are multi-purpose channels and must not
be reconfigured unless explicitly authorised by the board description.

Signed-off-by: Vincent Pelletier <plr.vincent@gmail.com>
---
Changes in v2:
- drop of_match_table: this should be meaningless in such sub-function
  driver (at least judging by other sub-function drivers for the da9063)
- sort includes
- switch to devm_hwmon_device_register_with_info
- registers.h changes moved to patch 1
- add SPDX header

This patch depends on patch 1/3.
Originally submitted by Steve Twiss in 2014:
  https://marc.info/?l=linux-kernel&m=139560868309857&w=2

 drivers/hwmon/Kconfig        |  10 ++
 drivers/hwmon/Makefile       |   1 +
 drivers/hwmon/da9063-hwmon.c | 275 +++++++++++++++++++++++++++++++++++
 3 files changed, 286 insertions(+)
 create mode 100644 drivers/hwmon/da9063-hwmon.c

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 87624902ea80..17244cfaa855 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -515,6 +515,16 @@ config SENSORS_DA9055
 	  This driver can also be built as a module. If so, the module
 	  will be called da9055-hwmon.
 
+config SENSORS_DA9063
+	tristate "Dialog Semiconductor DA9063"
+	depends on MFD_DA9063
+	help
+	  If you say yes here you get support for the hardware
+	  monitoring features of the DA9063 Power Management IC.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called da9063-hwmon.
+
 config SENSORS_I5K_AMB
 	tristate "FB-DIMM AMB temperature sensor on Intel 5000 series chipsets"
 	depends on PCI
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 59e78bc212cf..6855711ed9ec 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -60,6 +60,7 @@ obj-$(CONFIG_SENSORS_CORSAIR_CPRO) += corsair-cpro.o
 obj-$(CONFIG_SENSORS_CORSAIR_PSU) += corsair-psu.o
 obj-$(CONFIG_SENSORS_DA9052_ADC)+= da9052-hwmon.o
 obj-$(CONFIG_SENSORS_DA9055)+= da9055-hwmon.o
+obj-$(CONFIG_SENSORS_DA9063)	+= da9063-hwmon.o
 obj-$(CONFIG_SENSORS_DELL_SMM)	+= dell-smm-hwmon.o
 obj-$(CONFIG_SENSORS_DME1737)	+= dme1737.o
 obj-$(CONFIG_SENSORS_DRIVETEMP)	+= drivetemp.o
diff --git a/drivers/hwmon/da9063-hwmon.c b/drivers/hwmon/da9063-hwmon.c
new file mode 100644
index 000000000000..f020be5d5d6b
--- /dev/null
+++ b/drivers/hwmon/da9063-hwmon.c
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* da9063-hwmon.c - Hardware monitor support for DA9063
+ * Copyright (C) 2014 Dialog Semiconductor Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mfd/da9063/core.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#define DA9063_ADC_RES	(1 << (DA9063_ADC_RES_L_BITS + DA9063_ADC_RES_M_BITS))
+#define DA9063_ADC_MAX	(DA9063_ADC_RES - 1)
+#define DA9063_2V5	2500
+#define DA9063_5V0	5000
+#define DA9063_5V5	5500
+#define DA9063_TJUNC_M	-398
+#define DA9063_TJUNC_O	330000
+#define DA9063_VBBAT_M	2048
+
+enum da9063_adc {
+	DA9063_CHAN_VSYS = DA9063_ADC_MUX_VSYS,
+	DA9063_CHAN_ADCIN1 = DA9063_ADC_MUX_ADCIN1,
+	DA9063_CHAN_ADCIN2 = DA9063_ADC_MUX_ADCIN2,
+	DA9063_CHAN_ADCIN3 = DA9063_ADC_MUX_ADCIN3,
+	DA9063_CHAN_TJUNC = DA9063_ADC_MUX_T_SENSE,
+	DA9063_CHAN_VBBAT = DA9063_ADC_MUX_VBBAT,
+	DA9063_CHAN_LDO_G1 = DA9063_ADC_MUX_LDO_G1,
+	DA9063_CHAN_LDO_G2 = DA9063_ADC_MUX_LDO_G2,
+	DA9063_CHAN_LDO_G3 = DA9063_ADC_MUX_LDO_G3
+};
+
+struct da9063_hwmon {
+	struct da9063 *da9063;
+	struct mutex hwmon_mutex;
+	struct completion adc_ready;
+	signed char tjunc_offset;
+};
+
+static int da9063_adc_manual_read(struct da9063_hwmon *hwmon, int channel)
+{
+	int ret;
+	unsigned char val;
+	unsigned char data[2];
+	int adc_man;
+
+	mutex_lock(&hwmon->hwmon_mutex);
+
+	init_completion(&hwmon->adc_ready);
+
+	val = (channel & DA9063_ADC_MUX_MASK) | DA9063_ADC_MAN;
+	ret = regmap_update_bits(hwmon->da9063->regmap, DA9063_REG_ADC_MAN,
+				 DA9063_ADC_MUX_MASK | DA9063_ADC_MAN, val);
+	if (ret < 0)
+		goto err_mread;
+
+	ret = wait_for_completion_timeout(&hwmon->adc_ready,
+					  msecs_to_jiffies(1000));
+	if (ret == 0) {
+		ret = -ETIMEDOUT;
+		goto err_mread;
+	}
+
+	ret = regmap_read(hwmon->da9063->regmap, DA9063_REG_ADC_MAN, &adc_man);
+	if (ret < 0)
+		goto err_mread;
+
+	/* data value is not ready */
+	if (adc_man & DA9063_ADC_MAN) {
+		ret = -EINVAL;
+		goto err_mread;
+	}
+
+	ret = regmap_bulk_read(hwmon->da9063->regmap,
+			       DA9063_REG_ADC_RES_L, data, 2);
+	if (ret < 0)
+		goto err_mread;
+
+	ret = (data[0] & DA9063_ADC_RES_L_MASK) >> DA9063_ADC_RES_L_SHIFT;
+	ret |= data[1] << DA9063_ADC_RES_L_BITS;
+err_mread:
+	mutex_unlock(&hwmon->hwmon_mutex);
+	return ret;
+}
+
+static irqreturn_t da9063_hwmon_irq_handler(int irq, void *irq_data)
+{
+	struct da9063_hwmon *hwmon = irq_data;
+
+	complete(&hwmon->adc_ready);
+	return IRQ_HANDLED;
+}
+
+static umode_t da9063_is_visible(const void *drvdata, enum
+				 hwmon_sensor_types type, u32 attr, int channel)
+{
+	return 0444;
+}
+
+static const enum da9063_adc da9063_in_index[] = {
+	DA9063_CHAN_VSYS, DA9063_CHAN_VBBAT
+};
+
+static const enum da9063_adc da9063_temp_index[] = {
+	DA9063_CHAN_TJUNC
+};
+
+static int da9063_read(struct device *dev, enum hwmon_sensor_types type,
+		       u32 attr, int channel, long *val)
+{
+	struct da9063_hwmon *hwmon = dev_get_drvdata(dev);
+	enum da9063_adc adc_channel;
+	int tmp;
+
+	switch (type) {
+	case hwmon_in:
+		if (attr != hwmon_in_input)
+			return -EOPNOTSUPP;
+		adc_channel = da9063_in_index[channel];
+		break;
+	case hwmon_temp:
+		if (attr != hwmon_temp_input)
+			return -EOPNOTSUPP;
+		adc_channel = da9063_temp_index[channel];
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	tmp = da9063_adc_manual_read(hwmon, adc_channel);
+	if (tmp < 0)
+		return tmp;
+
+	switch (adc_channel) {
+	case DA9063_CHAN_VSYS:
+		*val = ((DA9063_5V5 - DA9063_2V5) * tmp) / DA9063_ADC_MAX +
+			DA9063_2V5;
+		break;
+	case DA9063_CHAN_TJUNC:
+		tmp -= hwmon->tjunc_offset;
+		*val = DA9063_TJUNC_M * tmp + DA9063_TJUNC_O;
+		break;
+	case DA9063_CHAN_VBBAT:
+		*val = (DA9063_5V0 * tmp) / DA9063_ADC_MAX;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const char * const da9063_in_name[] = {
+	"VSYS", "VBBAT"
+};
+
+static const char * const da9063_temp_name[] = {
+	"TJUNC"
+};
+
+static int da9063_read_string(struct device *dev, enum hwmon_sensor_types type,
+			      u32 attr, int channel, const char **str)
+{
+	switch (type) {
+	case hwmon_in:
+		if (attr != hwmon_in_label)
+			return -EOPNOTSUPP;
+		*str = da9063_in_name[channel];
+		break;
+	case hwmon_temp:
+		if (attr != hwmon_temp_label)
+			return -EOPNOTSUPP;
+		*str = da9063_temp_name[channel];
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static const struct hwmon_ops da9063_ops = {
+	.is_visible = da9063_is_visible,
+	.read = da9063_read,
+	.read_string = da9063_read_string,
+};
+
+static const struct hwmon_channel_info *da9063_channel_info[] = {
+	HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
+	HWMON_CHANNEL_INFO(in,
+			   HWMON_I_INPUT | HWMON_I_LABEL,
+			   HWMON_I_INPUT | HWMON_I_LABEL),
+	HWMON_CHANNEL_INFO(temp,
+			   HWMON_T_INPUT | HWMON_T_LABEL),
+	NULL
+};
+
+static const struct hwmon_chip_info da9063_chip_info = {
+	.ops = &da9063_ops,
+	.info = da9063_channel_info,
+};
+
+static int da9063_hwmon_probe(struct platform_device *pdev)
+{
+	struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent);
+	struct da9063_hwmon *hwmon;
+	struct device *hwmon_dev;
+	int irq;
+	int ret;
+
+	hwmon = devm_kzalloc(&pdev->dev, sizeof(struct da9063_hwmon),
+			     GFP_KERNEL);
+	if (!hwmon)
+		return -ENOMEM;
+
+	mutex_init(&hwmon->hwmon_mutex);
+	init_completion(&hwmon->adc_ready);
+	hwmon->da9063 = da9063;
+
+	irq = platform_get_irq_byname(pdev, DA9063_DRVNAME_HWMON);
+	if (irq < 0)
+		return irq;
+
+	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+					da9063_hwmon_irq_handler,
+					IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+					"HWMON", hwmon);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to request IRQ.\n");
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, hwmon);
+
+	/* set trim temperature offset to value read at startup */
+	hwmon->tjunc_offset = (signed char)hwmon->da9063->t_offset;
+
+	hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, "da9063",
+							 hwmon,
+							 &da9063_chip_info,
+							 NULL);
+
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static struct platform_driver da9063_hwmon_driver = {
+	.probe = da9063_hwmon_probe,
+	.driver = {
+		.name = DA9063_DRVNAME_HWMON,
+	},
+};
+module_platform_driver(da9063_hwmon_driver);
+
+MODULE_DESCRIPTION("Hardware monitor support device driver for Dialog DA9063");
+MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DA9063_DRVNAME_HWMON);
-- 
2.32.0


  reply	other threads:[~2021-07-06 14:44 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-07-06 14:34 [PATCH 1/3] mfd: da9063: Add HWMON dependencies Vincent Pelletier
2021-07-06 14:34 ` Vincent Pelletier [this message]
2021-07-06 17:42   ` [PATCH 2/3] hwmon: da9063: HWMON driver Guenter Roeck
2021-07-07  0:20     ` Vincent Pelletier
2021-07-07  0:58       ` Guenter Roeck
2021-07-07 23:28         ` Vincent Pelletier
2021-07-06 14:34 ` [PATCH 3/3] Documentation: hwmon: New information for DA9063 Vincent Pelletier
2021-07-06 17:28   ` Guenter Roeck
2021-07-06 17:28 ` [PATCH 1/3] mfd: da9063: Add HWMON dependencies Guenter Roeck
  -- strict thread matches above, loose matches on Subject: below --
2021-07-06  0:01 Vincent Pelletier
2021-07-06  0:01 ` [PATCH 2/3] hwmon: da9063: HWMON driver Vincent Pelletier
2021-07-06  0:28   ` Guenter Roeck

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=dff04323fc1b0177c1c08d3670333a839af4c268.1625581991.git.plr.vincent@gmail.com \
    --to=plr.vincent@gmail.com \
    --cc=corbet@lwn.net \
    --cc=jdelvare@suse.com \
    --cc=lee.jones@linaro.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-hwmon@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@roeck-us.net \
    --cc=stwiss.opensource@diasemi.com \
    --cc=support.opensource@diasemi.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.