mirror of
https://github.com/torvalds/linux.git
synced 2024-12-22 10:56:40 +00:00
2874c5fd28
Based on 1 normalized pattern(s): 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 extracted by the scancode license scanner the SPDX license identifier GPL-2.0-or-later has been chosen to replace the boilerplate/reference in 3029 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Allison Randal <allison@lohutok.net> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190527070032.746973796@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
425 lines
9.5 KiB
C
425 lines
9.5 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Device access for Dialog DA9055 PMICs.
|
|
*
|
|
* Copyright(c) 2012 Dialog Semiconductor Ltd.
|
|
*
|
|
* Author: David Dajun Chen <dchen@diasemi.com>
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/device.h>
|
|
#include <linux/input.h>
|
|
#include <linux/irq.h>
|
|
#include <linux/mutex.h>
|
|
|
|
#include <linux/mfd/core.h>
|
|
#include <linux/mfd/da9055/core.h>
|
|
#include <linux/mfd/da9055/pdata.h>
|
|
#include <linux/mfd/da9055/reg.h>
|
|
|
|
#define DA9055_IRQ_NONKEY_MASK 0x01
|
|
#define DA9055_IRQ_ALM_MASK 0x02
|
|
#define DA9055_IRQ_TICK_MASK 0x04
|
|
#define DA9055_IRQ_ADC_MASK 0x08
|
|
#define DA9055_IRQ_BUCK_ILIM_MASK 0x08
|
|
|
|
static bool da9055_register_readable(struct device *dev, unsigned int reg)
|
|
{
|
|
switch (reg) {
|
|
case DA9055_REG_STATUS_A:
|
|
case DA9055_REG_STATUS_B:
|
|
case DA9055_REG_EVENT_A:
|
|
case DA9055_REG_EVENT_B:
|
|
case DA9055_REG_EVENT_C:
|
|
case DA9055_REG_IRQ_MASK_A:
|
|
case DA9055_REG_IRQ_MASK_B:
|
|
case DA9055_REG_IRQ_MASK_C:
|
|
|
|
case DA9055_REG_CONTROL_A:
|
|
case DA9055_REG_CONTROL_B:
|
|
case DA9055_REG_CONTROL_C:
|
|
case DA9055_REG_CONTROL_D:
|
|
case DA9055_REG_CONTROL_E:
|
|
|
|
case DA9055_REG_ADC_MAN:
|
|
case DA9055_REG_ADC_CONT:
|
|
case DA9055_REG_VSYS_MON:
|
|
case DA9055_REG_ADC_RES_L:
|
|
case DA9055_REG_ADC_RES_H:
|
|
case DA9055_REG_VSYS_RES:
|
|
case DA9055_REG_ADCIN1_RES:
|
|
case DA9055_REG_ADCIN2_RES:
|
|
case DA9055_REG_ADCIN3_RES:
|
|
|
|
case DA9055_REG_COUNT_S:
|
|
case DA9055_REG_COUNT_MI:
|
|
case DA9055_REG_COUNT_H:
|
|
case DA9055_REG_COUNT_D:
|
|
case DA9055_REG_COUNT_MO:
|
|
case DA9055_REG_COUNT_Y:
|
|
case DA9055_REG_ALARM_H:
|
|
case DA9055_REG_ALARM_D:
|
|
case DA9055_REG_ALARM_MI:
|
|
case DA9055_REG_ALARM_MO:
|
|
case DA9055_REG_ALARM_Y:
|
|
|
|
case DA9055_REG_GPIO0_1:
|
|
case DA9055_REG_GPIO2:
|
|
case DA9055_REG_GPIO_MODE0_2:
|
|
|
|
case DA9055_REG_BCORE_CONT:
|
|
case DA9055_REG_BMEM_CONT:
|
|
case DA9055_REG_LDO1_CONT:
|
|
case DA9055_REG_LDO2_CONT:
|
|
case DA9055_REG_LDO3_CONT:
|
|
case DA9055_REG_LDO4_CONT:
|
|
case DA9055_REG_LDO5_CONT:
|
|
case DA9055_REG_LDO6_CONT:
|
|
case DA9055_REG_BUCK_LIM:
|
|
case DA9055_REG_BCORE_MODE:
|
|
case DA9055_REG_VBCORE_A:
|
|
case DA9055_REG_VBMEM_A:
|
|
case DA9055_REG_VLDO1_A:
|
|
case DA9055_REG_VLDO2_A:
|
|
case DA9055_REG_VLDO3_A:
|
|
case DA9055_REG_VLDO4_A:
|
|
case DA9055_REG_VLDO5_A:
|
|
case DA9055_REG_VLDO6_A:
|
|
case DA9055_REG_VBCORE_B:
|
|
case DA9055_REG_VBMEM_B:
|
|
case DA9055_REG_VLDO1_B:
|
|
case DA9055_REG_VLDO2_B:
|
|
case DA9055_REG_VLDO3_B:
|
|
case DA9055_REG_VLDO4_B:
|
|
case DA9055_REG_VLDO5_B:
|
|
case DA9055_REG_VLDO6_B:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static bool da9055_register_writeable(struct device *dev, unsigned int reg)
|
|
{
|
|
switch (reg) {
|
|
case DA9055_REG_STATUS_A:
|
|
case DA9055_REG_STATUS_B:
|
|
case DA9055_REG_EVENT_A:
|
|
case DA9055_REG_EVENT_B:
|
|
case DA9055_REG_EVENT_C:
|
|
case DA9055_REG_IRQ_MASK_A:
|
|
case DA9055_REG_IRQ_MASK_B:
|
|
case DA9055_REG_IRQ_MASK_C:
|
|
|
|
case DA9055_REG_CONTROL_A:
|
|
case DA9055_REG_CONTROL_B:
|
|
case DA9055_REG_CONTROL_C:
|
|
case DA9055_REG_CONTROL_D:
|
|
case DA9055_REG_CONTROL_E:
|
|
|
|
case DA9055_REG_ADC_MAN:
|
|
case DA9055_REG_ADC_CONT:
|
|
case DA9055_REG_VSYS_MON:
|
|
case DA9055_REG_ADC_RES_L:
|
|
case DA9055_REG_ADC_RES_H:
|
|
case DA9055_REG_VSYS_RES:
|
|
case DA9055_REG_ADCIN1_RES:
|
|
case DA9055_REG_ADCIN2_RES:
|
|
case DA9055_REG_ADCIN3_RES:
|
|
|
|
case DA9055_REG_COUNT_S:
|
|
case DA9055_REG_COUNT_MI:
|
|
case DA9055_REG_COUNT_H:
|
|
case DA9055_REG_COUNT_D:
|
|
case DA9055_REG_COUNT_MO:
|
|
case DA9055_REG_COUNT_Y:
|
|
case DA9055_REG_ALARM_H:
|
|
case DA9055_REG_ALARM_D:
|
|
case DA9055_REG_ALARM_MI:
|
|
case DA9055_REG_ALARM_MO:
|
|
case DA9055_REG_ALARM_Y:
|
|
|
|
case DA9055_REG_GPIO0_1:
|
|
case DA9055_REG_GPIO2:
|
|
case DA9055_REG_GPIO_MODE0_2:
|
|
|
|
case DA9055_REG_BCORE_CONT:
|
|
case DA9055_REG_BMEM_CONT:
|
|
case DA9055_REG_LDO1_CONT:
|
|
case DA9055_REG_LDO2_CONT:
|
|
case DA9055_REG_LDO3_CONT:
|
|
case DA9055_REG_LDO4_CONT:
|
|
case DA9055_REG_LDO5_CONT:
|
|
case DA9055_REG_LDO6_CONT:
|
|
case DA9055_REG_BUCK_LIM:
|
|
case DA9055_REG_BCORE_MODE:
|
|
case DA9055_REG_VBCORE_A:
|
|
case DA9055_REG_VBMEM_A:
|
|
case DA9055_REG_VLDO1_A:
|
|
case DA9055_REG_VLDO2_A:
|
|
case DA9055_REG_VLDO3_A:
|
|
case DA9055_REG_VLDO4_A:
|
|
case DA9055_REG_VLDO5_A:
|
|
case DA9055_REG_VLDO6_A:
|
|
case DA9055_REG_VBCORE_B:
|
|
case DA9055_REG_VBMEM_B:
|
|
case DA9055_REG_VLDO1_B:
|
|
case DA9055_REG_VLDO2_B:
|
|
case DA9055_REG_VLDO3_B:
|
|
case DA9055_REG_VLDO4_B:
|
|
case DA9055_REG_VLDO5_B:
|
|
case DA9055_REG_VLDO6_B:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static bool da9055_register_volatile(struct device *dev, unsigned int reg)
|
|
{
|
|
switch (reg) {
|
|
case DA9055_REG_STATUS_A:
|
|
case DA9055_REG_STATUS_B:
|
|
case DA9055_REG_EVENT_A:
|
|
case DA9055_REG_EVENT_B:
|
|
case DA9055_REG_EVENT_C:
|
|
|
|
case DA9055_REG_CONTROL_A:
|
|
case DA9055_REG_CONTROL_E:
|
|
|
|
case DA9055_REG_ADC_MAN:
|
|
case DA9055_REG_ADC_RES_L:
|
|
case DA9055_REG_ADC_RES_H:
|
|
case DA9055_REG_VSYS_RES:
|
|
case DA9055_REG_ADCIN1_RES:
|
|
case DA9055_REG_ADCIN2_RES:
|
|
case DA9055_REG_ADCIN3_RES:
|
|
|
|
case DA9055_REG_COUNT_S:
|
|
case DA9055_REG_COUNT_MI:
|
|
case DA9055_REG_COUNT_H:
|
|
case DA9055_REG_COUNT_D:
|
|
case DA9055_REG_COUNT_MO:
|
|
case DA9055_REG_COUNT_Y:
|
|
case DA9055_REG_ALARM_MI:
|
|
|
|
case DA9055_REG_BCORE_CONT:
|
|
case DA9055_REG_BMEM_CONT:
|
|
case DA9055_REG_LDO1_CONT:
|
|
case DA9055_REG_LDO2_CONT:
|
|
case DA9055_REG_LDO3_CONT:
|
|
case DA9055_REG_LDO4_CONT:
|
|
case DA9055_REG_LDO5_CONT:
|
|
case DA9055_REG_LDO6_CONT:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static const struct regmap_irq da9055_irqs[] = {
|
|
[DA9055_IRQ_NONKEY] = {
|
|
.reg_offset = 0,
|
|
.mask = DA9055_IRQ_NONKEY_MASK,
|
|
},
|
|
[DA9055_IRQ_ALARM] = {
|
|
.reg_offset = 0,
|
|
.mask = DA9055_IRQ_ALM_MASK,
|
|
},
|
|
[DA9055_IRQ_TICK] = {
|
|
.reg_offset = 0,
|
|
.mask = DA9055_IRQ_TICK_MASK,
|
|
},
|
|
[DA9055_IRQ_HWMON] = {
|
|
.reg_offset = 0,
|
|
.mask = DA9055_IRQ_ADC_MASK,
|
|
},
|
|
[DA9055_IRQ_REGULATOR] = {
|
|
.reg_offset = 1,
|
|
.mask = DA9055_IRQ_BUCK_ILIM_MASK,
|
|
},
|
|
};
|
|
|
|
const struct regmap_config da9055_regmap_config = {
|
|
.reg_bits = 8,
|
|
.val_bits = 8,
|
|
|
|
.cache_type = REGCACHE_RBTREE,
|
|
|
|
.max_register = DA9055_MAX_REGISTER_CNT,
|
|
.readable_reg = da9055_register_readable,
|
|
.writeable_reg = da9055_register_writeable,
|
|
.volatile_reg = da9055_register_volatile,
|
|
};
|
|
EXPORT_SYMBOL_GPL(da9055_regmap_config);
|
|
|
|
static struct resource da9055_onkey_resource = {
|
|
.name = "ONKEY",
|
|
.start = DA9055_IRQ_NONKEY,
|
|
.end = DA9055_IRQ_NONKEY,
|
|
.flags = IORESOURCE_IRQ,
|
|
};
|
|
|
|
static struct resource da9055_rtc_resource[] = {
|
|
{
|
|
.name = "ALM",
|
|
.start = DA9055_IRQ_ALARM,
|
|
.end = DA9055_IRQ_ALARM,
|
|
.flags = IORESOURCE_IRQ,
|
|
},
|
|
{
|
|
.name = "TICK",
|
|
.start = DA9055_IRQ_TICK,
|
|
.end = DA9055_IRQ_TICK,
|
|
.flags = IORESOURCE_IRQ,
|
|
},
|
|
};
|
|
|
|
static struct resource da9055_hwmon_resource = {
|
|
.name = "HWMON",
|
|
.start = DA9055_IRQ_HWMON,
|
|
.end = DA9055_IRQ_HWMON,
|
|
.flags = IORESOURCE_IRQ,
|
|
};
|
|
|
|
static struct resource da9055_ld05_6_resource = {
|
|
.name = "REGULATOR",
|
|
.start = DA9055_IRQ_REGULATOR,
|
|
.end = DA9055_IRQ_REGULATOR,
|
|
.flags = IORESOURCE_IRQ,
|
|
};
|
|
|
|
static const struct mfd_cell da9055_devs[] = {
|
|
{
|
|
.of_compatible = "dlg,da9055-gpio",
|
|
.name = "da9055-gpio",
|
|
},
|
|
{
|
|
.of_compatible = "dlg,da9055-regulator",
|
|
.name = "da9055-regulator",
|
|
.id = 1,
|
|
},
|
|
{
|
|
.of_compatible = "dlg,da9055-regulator",
|
|
.name = "da9055-regulator",
|
|
.id = 2,
|
|
},
|
|
{
|
|
.of_compatible = "dlg,da9055-regulator",
|
|
.name = "da9055-regulator",
|
|
.id = 3,
|
|
},
|
|
{
|
|
.of_compatible = "dlg,da9055-regulator",
|
|
.name = "da9055-regulator",
|
|
.id = 4,
|
|
},
|
|
{
|
|
.of_compatible = "dlg,da9055-regulator",
|
|
.name = "da9055-regulator",
|
|
.id = 5,
|
|
},
|
|
{
|
|
.of_compatible = "dlg,da9055-regulator",
|
|
.name = "da9055-regulator",
|
|
.id = 6,
|
|
},
|
|
{
|
|
.of_compatible = "dlg,da9055-regulator",
|
|
.name = "da9055-regulator",
|
|
.id = 7,
|
|
.resources = &da9055_ld05_6_resource,
|
|
.num_resources = 1,
|
|
},
|
|
{
|
|
.of_compatible = "dlg,da9055-regulator",
|
|
.name = "da9055-regulator",
|
|
.resources = &da9055_ld05_6_resource,
|
|
.num_resources = 1,
|
|
.id = 8,
|
|
},
|
|
{
|
|
.of_compatible = "dlg,da9055-onkey",
|
|
.name = "da9055-onkey",
|
|
.resources = &da9055_onkey_resource,
|
|
.num_resources = 1,
|
|
},
|
|
{
|
|
.of_compatible = "dlg,da9055-rtc",
|
|
.name = "da9055-rtc",
|
|
.resources = da9055_rtc_resource,
|
|
.num_resources = ARRAY_SIZE(da9055_rtc_resource),
|
|
},
|
|
{
|
|
.of_compatible = "dlg,da9055-hwmon",
|
|
.name = "da9055-hwmon",
|
|
.resources = &da9055_hwmon_resource,
|
|
.num_resources = 1,
|
|
},
|
|
{
|
|
.of_compatible = "dlg,da9055-watchdog",
|
|
.name = "da9055-watchdog",
|
|
},
|
|
};
|
|
|
|
static const struct regmap_irq_chip da9055_regmap_irq_chip = {
|
|
.name = "da9055_irq",
|
|
.status_base = DA9055_REG_EVENT_A,
|
|
.mask_base = DA9055_REG_IRQ_MASK_A,
|
|
.ack_base = DA9055_REG_EVENT_A,
|
|
.num_regs = 3,
|
|
.irqs = da9055_irqs,
|
|
.num_irqs = ARRAY_SIZE(da9055_irqs),
|
|
};
|
|
|
|
int da9055_device_init(struct da9055 *da9055)
|
|
{
|
|
struct da9055_pdata *pdata = dev_get_platdata(da9055->dev);
|
|
int ret;
|
|
uint8_t clear_events[3] = {0xFF, 0xFF, 0xFF};
|
|
|
|
if (pdata && pdata->init != NULL)
|
|
pdata->init(da9055);
|
|
|
|
if (!pdata || !pdata->irq_base)
|
|
da9055->irq_base = -1;
|
|
else
|
|
da9055->irq_base = pdata->irq_base;
|
|
|
|
ret = da9055_group_write(da9055, DA9055_REG_EVENT_A, 3, clear_events);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
ret = regmap_add_irq_chip(da9055->regmap, da9055->chip_irq,
|
|
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
|
da9055->irq_base, &da9055_regmap_irq_chip,
|
|
&da9055->irq_data);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
da9055->irq_base = regmap_irq_chip_get_base(da9055->irq_data);
|
|
|
|
ret = mfd_add_devices(da9055->dev, -1,
|
|
da9055_devs, ARRAY_SIZE(da9055_devs),
|
|
NULL, da9055->irq_base, NULL);
|
|
if (ret)
|
|
goto err;
|
|
|
|
return 0;
|
|
|
|
err:
|
|
mfd_remove_devices(da9055->dev);
|
|
return ret;
|
|
}
|
|
|
|
void da9055_device_exit(struct da9055 *da9055)
|
|
{
|
|
regmap_del_irq_chip(da9055->chip_irq, da9055->irq_data);
|
|
mfd_remove_devices(da9055->dev);
|
|
}
|
|
|
|
MODULE_DESCRIPTION("Core support for the DA9055 PMIC");
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
|