mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 03:27:44 -04:00
mfd: da9063: Add Dialog DA9063 core driver
This is MFD module providing access to registers and interrupts of DA906x series PMIC. It is used by other functional modules, registered as MFD cells. Driver uses regmap with paging to access extended register list. Register map is divided into two pages, where the second page is used during initialisation. This module provides support to following functional cells: - Regulators - RTC - HWMON - OnKey (power key misc input device) - Vibration (force-feedback input device) - Watchdog - LEDs Signed-off-by: Krystian Garbaciak <[email protected]> Signed-off-by: Philipp Zabel <[email protected]> Reviewed-by: Mark Brown <[email protected]> Signed-off-by: Samuel Ortiz <[email protected]>
This commit is contained in:
parent
36ec66e033
commit
8e685483b0
6 changed files with 492 additions and 0 deletions
|
|
@ -139,6 +139,18 @@ config MFD_DA9055
|
|||
This driver can be built as a module. If built as a module it will be
|
||||
called "da9055"
|
||||
|
||||
config MFD_DA9063
|
||||
bool "Dialog Semiconductor DA9063 PMIC Support"
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
select REGMAP_IRQ
|
||||
depends on I2C=y && GENERIC_HARDIRQS
|
||||
help
|
||||
Say yes here for support for the Dialog Semiconductor DA9063 PMIC.
|
||||
This includes the I2C driver and core APIs.
|
||||
Additional drivers must be enabled in order to use the functionality
|
||||
of the device.
|
||||
|
||||
config MFD_MC13783
|
||||
tristate
|
||||
|
||||
|
|
|
|||
|
|
@ -107,6 +107,9 @@ obj-$(CONFIG_MFD_LP8788) += lp8788.o lp8788-irq.o
|
|||
da9055-objs := da9055-core.o da9055-i2c.o
|
||||
obj-$(CONFIG_MFD_DA9055) += da9055.o
|
||||
|
||||
da9063-objs := da9063-core.o da9063-i2c.o
|
||||
obj-$(CONFIG_MFD_DA9063) += da9063.o
|
||||
|
||||
obj-$(CONFIG_MFD_MAX77686) += max77686.o max77686-irq.o
|
||||
obj-$(CONFIG_MFD_MAX77693) += max77693.o max77693-irq.o
|
||||
obj-$(CONFIG_MFD_MAX8907) += max8907.o
|
||||
|
|
|
|||
129
drivers/mfd/da9063-core.c
Normal file
129
drivers/mfd/da9063-core.c
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* da9063-core.c: Device access for Dialog DA9063 modules
|
||||
*
|
||||
* Copyright 2012 Dialog Semiconductors Ltd.
|
||||
* Copyright 2013 Philipp Zabel, Pengutronix
|
||||
*
|
||||
* Author: Krystian Garbaciak <krystian.garbaciak@diasemi.com>,
|
||||
* Michal Hajduk <michal.hajduk@diasemi.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <linux/mfd/da9063/core.h>
|
||||
#include <linux/mfd/da9063/pdata.h>
|
||||
#include <linux/mfd/da9063/registers.h>
|
||||
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
|
||||
static struct mfd_cell da9063_devs[] = {
|
||||
{
|
||||
.name = DA9063_DRVNAME_REGULATORS,
|
||||
},
|
||||
{
|
||||
.name = DA9063_DRVNAME_LEDS,
|
||||
},
|
||||
{
|
||||
.name = DA9063_DRVNAME_WATCHDOG,
|
||||
},
|
||||
{
|
||||
.name = DA9063_DRVNAME_HWMON,
|
||||
},
|
||||
{
|
||||
.name = DA9063_DRVNAME_ONKEY,
|
||||
},
|
||||
{
|
||||
.name = DA9063_DRVNAME_RTC,
|
||||
},
|
||||
{
|
||||
.name = DA9063_DRVNAME_VIBRATION,
|
||||
},
|
||||
};
|
||||
|
||||
int da9063_device_init(struct da9063 *da9063, unsigned int irq)
|
||||
{
|
||||
struct da9063_pdata *pdata = da9063->dev->platform_data;
|
||||
int model, revision;
|
||||
int ret;
|
||||
|
||||
if (pdata) {
|
||||
da9063->flags = pdata->flags;
|
||||
da9063->irq_base = pdata->irq_base;
|
||||
} else {
|
||||
da9063->flags = 0;
|
||||
da9063->irq_base = 0;
|
||||
}
|
||||
da9063->chip_irq = irq;
|
||||
|
||||
if (pdata && pdata->init != NULL) {
|
||||
ret = pdata->init(da9063);
|
||||
if (ret != 0) {
|
||||
dev_err(da9063->dev,
|
||||
"Platform initialization failed.\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = regmap_read(da9063->regmap, DA9063_REG_CHIP_ID, &model);
|
||||
if (ret < 0) {
|
||||
dev_err(da9063->dev, "Cannot read chip model id.\n");
|
||||
return -EIO;
|
||||
}
|
||||
if (model != PMIC_DA9063) {
|
||||
dev_err(da9063->dev, "Invalid chip model id: 0x%02x\n", model);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = regmap_read(da9063->regmap, DA9063_REG_CHIP_VARIANT, &revision);
|
||||
if (ret < 0) {
|
||||
dev_err(da9063->dev, "Cannot read chip revision id.\n");
|
||||
return -EIO;
|
||||
}
|
||||
revision >>= DA9063_CHIP_VARIANT_SHIFT;
|
||||
if (revision != 3) {
|
||||
dev_err(da9063->dev, "Unknown chip revision: %d\n", revision);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
da9063->model = model;
|
||||
da9063->revision = revision;
|
||||
|
||||
dev_info(da9063->dev,
|
||||
"Device detected (model-ID: 0x%02X rev-ID: 0x%02X)\n",
|
||||
model, revision);
|
||||
|
||||
ret = mfd_add_devices(da9063->dev, -1, da9063_devs,
|
||||
ARRAY_SIZE(da9063_devs), NULL, da9063->irq_base,
|
||||
NULL);
|
||||
if (ret)
|
||||
dev_err(da9063->dev, "Cannot add MFD cells\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void da9063_device_exit(struct da9063 *da9063)
|
||||
{
|
||||
mfd_remove_devices(da9063->dev);
|
||||
}
|
||||
|
||||
MODULE_DESCRIPTION("PMIC driver for Dialog DA9063");
|
||||
MODULE_AUTHOR("Krystian Garbaciak <[email protected]>, Michal Hajduk <[email protected]>");
|
||||
MODULE_LICENSE("GPL");
|
||||
182
drivers/mfd/da9063-i2c.c
Normal file
182
drivers/mfd/da9063-i2c.c
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
/* da9063-i2c.c: Interrupt support for Dialog DA9063
|
||||
*
|
||||
* Copyright 2012 Dialog Semiconductor Ltd.
|
||||
* Copyright 2013 Philipp Zabel, Pengutronix
|
||||
*
|
||||
* Author: Krystian Garbaciak <krystian.garbaciak@diasemi.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/da9063/core.h>
|
||||
#include <linux/mfd/da9063/pdata.h>
|
||||
#include <linux/mfd/da9063/registers.h>
|
||||
|
||||
static const struct regmap_range da9063_readable_ranges[] = {
|
||||
{
|
||||
.range_min = DA9063_REG_PAGE_CON,
|
||||
.range_max = DA9063_REG_SECOND_D,
|
||||
}, {
|
||||
.range_min = DA9063_REG_SEQ,
|
||||
.range_max = DA9063_REG_ID_32_31,
|
||||
}, {
|
||||
.range_min = DA9063_REG_SEQ_A,
|
||||
.range_max = DA9063_REG_AUTO3_LOW,
|
||||
}, {
|
||||
.range_min = DA9063_REG_T_OFFSET,
|
||||
.range_max = DA9063_REG_GP_ID_19,
|
||||
}, {
|
||||
.range_min = DA9063_REG_CHIP_ID,
|
||||
.range_max = DA9063_REG_CHIP_VARIANT,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regmap_range da9063_writeable_ranges[] = {
|
||||
{
|
||||
.range_min = DA9063_REG_PAGE_CON,
|
||||
.range_max = DA9063_REG_PAGE_CON,
|
||||
}, {
|
||||
.range_min = DA9063_REG_FAULT_LOG,
|
||||
.range_max = DA9063_REG_VSYS_MON,
|
||||
}, {
|
||||
.range_min = DA9063_REG_COUNT_S,
|
||||
.range_max = DA9063_REG_ALARM_Y,
|
||||
}, {
|
||||
.range_min = DA9063_REG_SEQ,
|
||||
.range_max = DA9063_REG_ID_32_31,
|
||||
}, {
|
||||
.range_min = DA9063_REG_SEQ_A,
|
||||
.range_max = DA9063_REG_AUTO3_LOW,
|
||||
}, {
|
||||
.range_min = DA9063_REG_CONFIG_I,
|
||||
.range_max = DA9063_REG_MON_REG_4,
|
||||
}, {
|
||||
.range_min = DA9063_REG_GP_ID_0,
|
||||
.range_max = DA9063_REG_GP_ID_19,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regmap_range da9063_volatile_ranges[] = {
|
||||
{
|
||||
.range_min = DA9063_REG_STATUS_A,
|
||||
.range_max = DA9063_REG_EVENT_D,
|
||||
}, {
|
||||
.range_min = DA9063_REG_CONTROL_F,
|
||||
.range_max = DA9063_REG_CONTROL_F,
|
||||
}, {
|
||||
.range_min = DA9063_REG_ADC_MAN,
|
||||
.range_max = DA9063_REG_ADC_MAN,
|
||||
}, {
|
||||
.range_min = DA9063_REG_ADC_RES_L,
|
||||
.range_max = DA9063_REG_SECOND_D,
|
||||
}, {
|
||||
.range_min = DA9063_REG_MON_REG_5,
|
||||
.range_max = DA9063_REG_MON_REG_6,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regmap_access_table da9063_readable_table = {
|
||||
.yes_ranges = da9063_readable_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(da9063_readable_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table da9063_writeable_table = {
|
||||
.yes_ranges = da9063_writeable_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(da9063_writeable_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table da9063_volatile_table = {
|
||||
.yes_ranges = da9063_volatile_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(da9063_volatile_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_range_cfg da9063_range_cfg[] = {
|
||||
{
|
||||
.range_min = DA9063_REG_PAGE_CON,
|
||||
.range_max = DA9063_REG_CHIP_VARIANT,
|
||||
.selector_reg = DA9063_REG_PAGE_CON,
|
||||
.selector_mask = 1 << DA9063_I2C_PAGE_SEL_SHIFT,
|
||||
.selector_shift = DA9063_I2C_PAGE_SEL_SHIFT,
|
||||
.window_start = 0,
|
||||
.window_len = 256,
|
||||
}
|
||||
};
|
||||
|
||||
static struct regmap_config da9063_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.ranges = da9063_range_cfg,
|
||||
.num_ranges = ARRAY_SIZE(da9063_range_cfg),
|
||||
.max_register = DA9063_REG_CHIP_VARIANT,
|
||||
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
|
||||
.rd_table = &da9063_readable_table,
|
||||
.wr_table = &da9063_writeable_table,
|
||||
.volatile_table = &da9063_volatile_table,
|
||||
};
|
||||
|
||||
static int da9063_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct da9063 *da9063;
|
||||
int ret;
|
||||
|
||||
da9063 = devm_kzalloc(&i2c->dev, sizeof(struct da9063), GFP_KERNEL);
|
||||
if (da9063 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(i2c, da9063);
|
||||
da9063->dev = &i2c->dev;
|
||||
da9063->chip_irq = i2c->irq;
|
||||
|
||||
da9063->regmap = devm_regmap_init_i2c(i2c, &da9063_regmap_config);
|
||||
if (IS_ERR(da9063->regmap)) {
|
||||
ret = PTR_ERR(da9063->regmap);
|
||||
dev_err(da9063->dev, "Failed to allocate register map: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return da9063_device_init(da9063, i2c->irq);
|
||||
}
|
||||
|
||||
static int da9063_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
struct da9063 *da9063 = i2c_get_clientdata(i2c);
|
||||
|
||||
da9063_device_exit(da9063);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id da9063_i2c_id[] = {
|
||||
{"da9063", PMIC_DA9063},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, da9063_i2c_id);
|
||||
|
||||
static struct i2c_driver da9063_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "da9063",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = da9063_i2c_probe,
|
||||
.remove = da9063_i2c_remove,
|
||||
.id_table = da9063_i2c_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(da9063_i2c_driver);
|
||||
Loading…
Reference in a new issue