9
0
Fork 0

mfd: da9063: add da9063 watchdog and system restart driver

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
This commit is contained in:
Philipp Zabel 2015-06-11 15:48:43 +02:00 committed by Sascha Hauer
parent 4a7534bf07
commit 96786e4dad
3 changed files with 174 additions and 0 deletions

View File

@ -4,6 +4,10 @@ config MFD_ACT8846
depends on I2C
bool "ACT8846 driver"
config MFD_DA9063
depends on I2C
bool "DA9063 PMIC driver"
config MFD_LP3972
depends on I2C
bool "LP3972 driver"

View File

@ -1,4 +1,5 @@
obj-$(CONFIG_MFD_ACT8846) += act8846.o
obj-$(CONFIG_MFD_DA9063) += da9063.o
obj-$(CONFIG_MFD_LP3972) += lp3972.o
obj-$(CONFIG_MFD_MC13XXX) += mc13xxx.o
obj-$(CONFIG_MFD_MC34704) += mc34704.o

169
drivers/mfd/da9063.c Normal file
View File

@ -0,0 +1,169 @@
/*
* Copyright (C) 2015 Pengutronix, Philipp Zabel <p.zabel@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 <driver.h>
#include <restart.h>
#include <init.h>
#include <i2c/i2c.h>
#include <malloc.h>
#include <notifier.h>
#include <reset_source.h>
#include <watchdog.h>
struct da9063 {
struct restart_handler restart;
struct watchdog wd;
struct i2c_client *client;
struct device_d *dev;
};
/* System Control and Event Registers */
#define DA9063_REG_FAULT_LOG 0x05
#define DA9063_REG_CONTROL_D 0x11
#define DA9063_REG_CONTROL_F 0x13
/* DA9063_REG_FAULT_LOG (addr=0x05) */
#define DA9063_TWD_ERROR 0x01
#define DA9063_POR 0x02
#define DA9063_NSHUTDOWN 0x40
/* DA9063_REG_CONTROL_D (addr=0x11) */
#define DA9063_TWDSCALE_MASK 0x07
/* DA9063_REG_CONTROL_F (addr=0x13) */
#define DA9063_SHUTDOWN 0x02
static int da9063_watchdog_set_timeout(struct watchdog *wd, unsigned timeout)
{
struct da9063 *priv = container_of(wd, struct da9063, wd);
struct device_d *dev = priv->dev;
unsigned int 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 = i2c_read_reg(priv->client, DA9063_REG_CONTROL_D, &val, 1);
if (ret < 0)
return ret;
val &= ~DA9063_TWDSCALE_MASK;
val |= scale;
ret = i2c_write_reg(priv->client, DA9063_REG_CONTROL_D, &val, 1);
if (ret < 0)
return ret;
return 0;
}
static void da9063_detect_reset_source(struct da9063 *priv)
{
int ret;
u8 val;
unsigned int priority;
enum reset_src_type type;
ret = i2c_read_reg(priv->client, DA9063_REG_FAULT_LOG, &val, 1);
if (ret < 0)
return;
/* Write one to clear */
i2c_write_reg(priv->client, DA9063_REG_FAULT_LOG, &val, 1);
if (val & DA9063_TWD_ERROR)
type = RESET_WDG;
else if (val & DA9063_POR)
type = RESET_POR;
else if (val & DA9063_NSHUTDOWN)
type = RESET_RST;
else
return;
priority = of_get_reset_source_priority(priv->dev->device_node);
reset_source_set_priority(type, priority);
}
static void da9063_restart(struct restart_handler *rst)
{
struct da9063 *priv = container_of(rst, struct da9063, restart);
u8 val = DA9063_SHUTDOWN;
i2c_write_reg(priv->client, DA9063_REG_CONTROL_F, &val, 1);
}
static int da9063_probe(struct device_d *dev)
{
struct da9063 *priv = NULL;
int ret;
priv = xzalloc(sizeof(struct da9063));
priv->wd.priority = of_get_watchdog_priority(dev->device_node);
priv->wd.set_timeout = da9063_watchdog_set_timeout;
priv->wd.dev = dev;
priv->client = to_i2c_client(dev);
priv->dev = dev;
ret = watchdog_register(&priv->wd);
if (ret)
goto on_error;
da9063_detect_reset_source(priv);
priv->restart.priority = of_get_restart_priority(dev->device_node);
priv->restart.name = "da9063";
priv->restart.restart = &da9063_restart;
restart_handler_register(&priv->restart);
return 0;
on_error:
if (priv)
free(priv);
return ret;
}
static struct platform_device_id da9063_id[] = {
{ "da9063", },
{ }
};
static struct driver_d da9063_driver = {
.name = "da9063",
.probe = da9063_probe,
.id_table = da9063_id,
};
static int da9063_init(void)
{
return i2c_driver_register(&da9063_driver);
}
device_initcall(da9063_init);