* [PATCH] mfd: da9053: add basic da9053 driver
@ 2015-01-29 15:43 Michael Grzeschik
2015-01-30 7:53 ` Sascha Hauer
0 siblings, 1 reply; 2+ messages in thread
From: Michael Grzeschik @ 2015-01-29 15:43 UTC (permalink / raw)
To: barebox
From: Jan Luebbe <jlu@pengutronix.de>
Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
---
drivers/mfd/Kconfig | 4 +
drivers/mfd/Makefile | 1 +
drivers/mfd/da9053.c | 360 +++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 365 insertions(+)
create mode 100644 drivers/mfd/da9053.c
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 3af904d..3d230f1 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -4,6 +4,10 @@ config MFD_ACT8846
depends on I2C
bool "ACT8846 driver"
+config MFD_DA9053
+ depends on I2C
+ bool "DA9053 PMIC driver"
+
config MFD_LP3972
depends on I2C
bool "LP3972 driver"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 49b9e35..2899dde 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -1,4 +1,5 @@
obj-$(CONFIG_MFD_ACT8846) += act8846.o
+obj-$(CONFIG_MFD_DA9053) += da9053.o
obj-$(CONFIG_MFD_LP3972) += lp3972.o
obj-$(CONFIG_MFD_MC13XXX) += mc13xxx.o
obj-$(CONFIG_MFD_MC34704) += mc34704.o
diff --git a/drivers/mfd/da9053.c b/drivers/mfd/da9053.c
new file mode 100644
index 0000000..4bce8cc
--- /dev/null
+++ b/drivers/mfd/da9053.c
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2013 Jan Luebbe <jlu@pengutronix.de>
+ *
+ * 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 <common.h>
+#include <init.h>
+#include <driver.h>
+#include <xfuncs.h>
+#include <errno.h>
+#include <watchdog.h>
+#include <linux/err.h>
+
+#include <i2c/i2c.h>
+
+#include <asm/byteorder.h>
+
+#define DRIVERNAME "da9053"
+
+/* STATUS REGISTERS */
+#define DA9053_STATUS_A_REG 1
+#define DA9053_STATUS_B_REG 2
+#define DA9053_STATUS_C_REG 3
+#define DA9053_STATUS_D_REG 4
+
+/* PARK REGISTER */
+#define DA9053_PARK_REGISTER DA9053_STATUS_D_REG
+
+/* EVENT REGISTERS */
+#define DA9053_EVENT_A_REG 5
+#define DA9053_EVENT_B_REG 6
+#define DA9053_EVENT_C_REG 7
+#define DA9053_EVENT_D_REG 8
+#define DA9053_FAULTLOG_REG 9
+
+/* IRQ REGISTERS */
+#define DA9053_IRQ_MASK_A_REG 10
+#define DA9053_IRQ_MASK_B_REG 11
+#define DA9053_IRQ_MASK_C_REG 12
+#define DA9053_IRQ_MASK_D_REG 13
+
+/* CONTROL REGISTERS */
+#define DA9053_CONTROL_A_REG 14
+#define DA9053_CONTROL_B_REG 15
+#define DA9053_CONTROL_C_REG 16
+#define DA9053_CONTROL_D_REG 17
+
+#define DA9053_PDDIS_REG 18
+#define DA9053_INTERFACE_REG 19
+#define DA9053_RESET_REG 20
+
+/* FAULT LOG REGISTER BITS */
+#define DA9053_FAULTLOG_WAITSET 0X80
+#define DA9053_FAULTLOG_NSDSET 0X40
+#define DA9053_FAULTLOG_KEYSHUT 0X20
+#define DA9053_FAULTLOG_TEMPOVER 0X08
+#define DA9053_FAULTLOG_VDDSTART 0X04
+#define DA9053_FAULTLOG_VDDFAULT 0X02
+#define DA9053_FAULTLOG_TWDERROR 0X01
+
+/* CONTROL REGISTER B BITS */
+#define DA9053_CONTROLB_SHUTDOWN 0X80
+#define DA9053_CONTROLB_DEEPSLEEP 0X40
+#define DA9053_CONTROLB_WRITEMODE 0X20
+#define DA9053_CONTROLB_BBATEN 0X10
+#define DA9053_CONTROLB_OTPREADEN 0X08
+#define DA9053_CONTROLB_AUTOBOOT 0X04
+#define DA9053_CONTROLB_ACTDIODE 0X02
+#define DA9053_CONTROLB_BUCKMERGE 0X01
+
+/* CONTROL REGISTER D BITS */
+#define DA9053_CONTROLD_WATCHDOG 0X80
+#define DA9053_CONTROLD_ACCDETEN 0X40
+#define DA9053_CONTROLD_GPI1415SD 0X20
+#define DA9053_CONTROLD_NONKEYSD 0X10
+#define DA9053_CONTROLD_KEEPACTEN 0X08
+#define DA9053_CONTROLD_TWDSCALE 0X07
+
+struct da9053_priv {
+ struct cdev cdev;
+ struct watchdog wd;
+ struct i2c_client *client;
+ unsigned int param_shutdown;
+ unsigned int param_faultlog;
+};
+
+#define cdev_to_da9053_priv(x) container_of(x, struct da9053_priv, cdev)
+#define wd_to_da9053_priv(x) container_of(x, struct da9053_priv, wd)
+
+static int da9053_reg_read(struct da9053_priv *da9053, u32 reg, u8 *val)
+{
+ int ret;
+
+ ret = i2c_read_reg(da9053->client, reg, val, 1);
+
+ return ret == 1 ? 0 : ret;
+}
+
+static int da9053_reg_write(struct da9053_priv *da9053, u32 reg, u8 val)
+{
+ int ret;
+
+ ret = i2c_write_reg(da9053->client, reg, &val, 1);
+
+ return ret == 1 ? 0 : ret;
+}
+
+static int da9053_park(struct da9053_priv *da9053)
+{
+ int ret;
+ u8 val;
+
+ ret = i2c_read_reg(da9053->client, DA9053_PARK_REGISTER, &val, 1);
+
+ return ret == 1 ? 0 : ret;
+}
+
+static ssize_t da9053_read(struct cdev *cdev, void *_buf, size_t count, loff_t offset, ulong flags)
+{
+ struct da9053_priv *da9053 = cdev_to_da9053_priv(cdev);
+ u8 *buf = _buf;
+ size_t i = count;
+ int err;
+
+ while (i) {
+ err = da9053_reg_read(da9053, offset, buf);
+ if (err) {
+ da9053_park(da9053);
+ return (ssize_t)err;
+ }
+ buf++;
+ i--;
+ offset++;
+ }
+
+ if (da9053_park(da9053) < 0)
+ return -EIO;
+
+ return count;
+}
+
+static int da9053_enable_multiwrite(struct da9053_priv *da9053)
+{
+ int ret;
+ u8 val;
+
+ ret = da9053_reg_read(da9053, DA9053_CONTROL_B_REG, &val);
+ if (ret < 0)
+ return ret;
+
+ if (val & DA9053_CONTROLB_WRITEMODE) {
+ val &= ~DA9053_CONTROLB_WRITEMODE;
+ ret = da9053_reg_write(da9053, DA9053_CONTROL_B_REG, val);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = da9053_park(da9053);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct file_operations da9053_fops = {
+ .lseek = dev_lseek_default,
+ .read = da9053_read,
+};
+
+static int da9053_set_faultlog(struct param_d *param, void *priv)
+{
+ struct da9053_priv *da9053 = priv;
+ int ret;
+ u8 val;
+
+ val = da9053->param_faultlog & 0xff;
+ if (val) {
+ ret = da9053_reg_write(da9053, DA9053_FAULTLOG_REG, val);
+ if (ret < 0)
+ return ret;
+
+ ret = da9053_park(da9053);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int da9053_get_faultlog(struct param_d *param, void *priv)
+{
+ struct da9053_priv *da9053 = priv;
+ int ret;
+ u8 val;
+
+ ret = da9053_reg_read(da9053, DA9053_FAULTLOG_REG, &val);
+ if (ret < 0)
+ return ret;
+
+ ret = da9053_park(da9053);
+ if (ret < 0)
+ return ret;
+
+ da9053->param_faultlog = val;
+
+ return 0;
+}
+
+static int da9053_set_shutdown(struct param_d *param, void *priv)
+{
+ struct da9053_priv *da9053 = priv;
+ int ret;
+ u8 val;
+
+ if (da9053->param_shutdown) {
+ ret = da9053_reg_read(da9053, DA9053_CONTROL_B_REG, &val);
+ if (ret < 0)
+ return ret;
+
+ val |= DA9053_CONTROLB_SHUTDOWN;
+ ret = da9053_reg_write(da9053, DA9053_CONTROL_B_REG, val);
+ if (ret < 0)
+ return ret;
+
+ ret = da9053_park(da9053);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int da9053_set_timeout(struct watchdog *wd, unsigned timeout)
+{
+ struct da9053_priv *da9053 = wd_to_da9053_priv(wd);
+ struct device_d *dev = da9053->cdev.dev;
+ unsigned scale = 0;
+ int ret;
+ u8 val;
+
+ if (timeout > 131)
+ return -EINVAL;
+
+ if (timeout) {
+ timeout *= 1000; /* convert to ms */
+ scale = 0;
+ while (timeout > (2048 << scale) && scale <= 6)
+ scale++;
+ dev_dbg(dev, "calculated TWDSCALE=%u (req=%ims calc=%ims)\n",
+ scale, timeout, 2048 << scale);
+ scale++; /* scale 0 disables the WD */
+ }
+
+ ret = da9053_reg_read(da9053, DA9053_CONTROL_D_REG, &val);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(dev, "read watchdog (val=0x%02x)\n", val);
+
+ if (scale && scale == (val & DA9053_CONTROLD_TWDSCALE)) {
+ /* trigger WD */
+ val |= DA9053_CONTROLD_WATCHDOG;
+ ret = da9053_reg_write(da9053, DA9053_CONTROL_D_REG, val);
+ if (ret < 0)
+ return ret;
+ dev_dbg(dev, "triggered watchdog (val=0x%02x)\n", val);
+ } else {
+ /* disable WD first */
+ val &= ~DA9053_CONTROLD_TWDSCALE;
+ ret = da9053_reg_write(da9053, DA9053_CONTROL_D_REG, val);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(dev, "disabled watchdog (val=0x%02x)\n", val);
+ if (scale) {
+ /* park before waiting */
+ ret = da9053_park(da9053);
+ if (ret < 0)
+ return ret;
+
+ /* wait required time */
+ udelay(150);
+
+ /* enable WD with new timeout */
+ val |= scale;
+ ret = da9053_reg_write(da9053, DA9053_CONTROL_D_REG, val);
+ if (ret < 0)
+ return ret;
+ dev_dbg(dev, "enabled watchdog (val=0x%02x)\n", val);
+ }
+ }
+
+ ret = da9053_park(da9053);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int da9053_probe(struct device_d *dev)
+{
+ struct da9053_priv *da9053;
+ struct param_d *p;
+ int ret;
+
+ da9053 = xzalloc(sizeof(struct da9053_priv));
+ dev->priv = da9053;
+ da9053->cdev.name = DRIVERNAME;
+ da9053->client = to_i2c_client(dev);
+ da9053->cdev.size = 128;
+ da9053->cdev.dev = dev;
+ da9053->cdev.ops = &da9053_fops;
+ da9053->wd.set_timeout = da9053_set_timeout;
+
+ ret = da9053_enable_multiwrite(da9053);
+ if (ret < 0)
+ return ret;
+
+ p = dev_add_param_int(dev, "faultlog", da9053_set_faultlog, da9053_get_faultlog,
+ &da9053->param_faultlog, "0x%02x", da9053);
+ if (IS_ERR(p))
+ return PTR_ERR(p);
+
+ p = dev_add_param_bool(dev, "shutdown", da9053_set_shutdown, NULL,
+ &da9053->param_shutdown, da9053);
+ if (IS_ERR(p))
+ return PTR_ERR(p);
+
+ devfs_create(&da9053->cdev);
+
+ ret = watchdog_register(&da9053->wd);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static struct driver_d da9053_driver = {
+ .name = DRIVERNAME,
+ .probe = da9053_probe,
+};
+
+static int da9053_init(void)
+{
+ i2c_driver_register(&da9053_driver);
+ return 0;
+}
+
+device_initcall(da9053_init);
--
2.1.4
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH] mfd: da9053: add basic da9053 driver
2015-01-29 15:43 [PATCH] mfd: da9053: add basic da9053 driver Michael Grzeschik
@ 2015-01-30 7:53 ` Sascha Hauer
0 siblings, 0 replies; 2+ messages in thread
From: Sascha Hauer @ 2015-01-30 7:53 UTC (permalink / raw)
To: Michael Grzeschik; +Cc: barebox
On Thu, Jan 29, 2015 at 04:43:17PM +0100, Michael Grzeschik wrote:
> From: Jan Luebbe <jlu@pengutronix.de>
>
> Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
> ---
> drivers/mfd/Kconfig | 4 +
> drivers/mfd/Makefile | 1 +
> drivers/mfd/da9053.c | 360 +++++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 365 insertions(+)
> create mode 100644 drivers/mfd/da9053.c
>
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 3af904d..3d230f1 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -4,6 +4,10 @@ config MFD_ACT8846
> depends on I2C
> bool "ACT8846 driver"
>
> +config MFD_DA9053
> + depends on I2C
> + bool "DA9053 PMIC driver"
You either need a "depends on WATCHDOG" or a if
(IS_ENABLED(CONFIG_WATCHDOG) in your code.
What do the "shutdown" and "faultlog" parameters do? At least a comment
in the code, better in the documentation would be good.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2015-01-30 7:53 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-29 15:43 [PATCH] mfd: da9053: add basic da9053 driver Michael Grzeschik
2015-01-30 7:53 ` Sascha Hauer
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox