Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2896434c authored by Ashish Jangam's avatar Ashish Jangam Committed by Samuel Ortiz
Browse files

mfd: DA9055 core driver



This is the DA9055 MFD core driver that instantiate all the dependent
component drivers and provides them the device access via I2C.

This patch is functionally tested on Samsung SMDK6410.

Signed-off-by: default avatarDavid Dajun Chen <dchen@diasemi.com>
Signed-off-by: default avatarAshish Jangam <ashish.jangam@kpitcummins.com>
Signed-off-by: default avatarSamuel Ortiz <sameo@linux.intel.com>
parent 5863eabb
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -430,6 +430,23 @@ config MFD_DA9052_I2C
	  for accessing the device, additional drivers must be enabled in
	  order to use the functionality of the device.

config MFD_DA9055
	bool "Dialog Semiconductor DA9055 PMIC Support"
	select REGMAP_I2C
	select REGMAP_IRQ
	select PMIC_DA9055
	select MFD_CORE
	depends on I2C=y
	help
	  Say yes here for support of Dialog Semiconductor DA9055. This is
	  a Power Management IC. This driver provides common support for
	  accessing the device as well as the I2C interface to the chip itself.
	  Additional drivers must be enabled in order to use the functionality
	  of the device.

	  This driver can be built as a module. If built as a module it will be
	  called "da9055"

config PMIC_ADP5520
	bool "Analog Devices ADP5520/01 MFD PMIC Core Support"
	depends on I2C=y
+3 −0
Original line number Diff line number Diff line
@@ -91,6 +91,9 @@ obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o

obj-$(CONFIG_MFD_LP8788)	+= lp8788.o lp8788-irq.o

da9055-objs			:= da9055-core.o da9055-i2c.o
obj-$(CONFIG_MFD_DA9055)	+= da9055.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
+423 −0
Original line number Diff line number Diff line
/*
 * Device access for Dialog DA9055 PMICs.
 *
 * Copyright(c) 2012 Dialog Semiconductor Ltd.
 *
 * Author: David Dajun Chen <dchen@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/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 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,
	},
};

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 struct mfd_cell da9055_devs[] = {
	{
		.of_compatible = "dialog,da9055-gpio",
		.name = "da9055-gpio",
	},
	{
		.of_compatible = "dialog,da9055-regulator",
		.name = "da9055-regulator",
		.id = 1,
	},
	{
		.of_compatible = "dialog,da9055-regulator",
		.name = "da9055-regulator",
		.id = 2,
	},
	{
		.of_compatible = "dialog,da9055-regulator",
		.name = "da9055-regulator",
		.id = 3,
	},
	{
		.of_compatible = "dialog,da9055-regulator",
		.name = "da9055-regulator",
		.id = 4,
	},
	{
		.of_compatible = "dialog,da9055-regulator",
		.name = "da9055-regulator",
		.id = 5,
	},
	{
		.of_compatible = "dialog,da9055-regulator",
		.name = "da9055-regulator",
		.id = 6,
	},
	{
		.of_compatible = "dialog,da9055-regulator",
		.name = "da9055-regulator",
		.id = 7,
		.resources = &da9055_ld05_6_resource,
		.num_resources = 1,
	},
	{
		.of_compatible = "dialog,da9055-regulator",
		.name = "da9055-regulator",
		.resources = &da9055_ld05_6_resource,
		.num_resources = 1,
		.id = 8,
	},
	{
		.of_compatible = "dialog,da9055-onkey",
		.name = "da9055-onkey",
		.resources = &da9055_onkey_resource,
		.num_resources = 1,
	},
	{
		.of_compatible = "dialog,da9055-rtc",
		.name = "da9055-rtc",
		.resources = da9055_rtc_resource,
		.num_resources = ARRAY_SIZE(da9055_rtc_resource),
	},
	{
		.of_compatible = "dialog,da9055-hwmon",
		.name = "da9055-hwmon",
		.resources = &da9055_hwmon_resource,
		.num_resources = 1,
	},
	{
		.of_compatible = "dialog,da9055-watchdog",
		.name = "da9055-watchdog",
	},
};

static 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 __devinit da9055_device_init(struct da9055 *da9055)
{
	struct da9055_pdata *pdata = da9055->dev->platform_data;
	int ret;

	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 = regmap_add_irq_chip(da9055->regmap, da9055->chip_irq,
				  IRQF_TRIGGER_HIGH | 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 __devexit 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>");
+93 −0
Original line number Diff line number Diff line
 /* I2C access for DA9055 PMICs.
 *
 * Copyright(c) 2012 Dialog Semiconductor Ltd.
 *
 * Author: David Dajun Chen <dchen@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/module.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/err.h>

#include <linux/mfd/da9055/core.h>

static int __devinit da9055_i2c_probe(struct i2c_client *i2c,
				      const struct i2c_device_id *id)
{
	struct da9055 *da9055;
	int ret;

	da9055 = devm_kzalloc(&i2c->dev, sizeof(struct da9055), GFP_KERNEL);
	if (!da9055)
		return -ENOMEM;

	da9055->regmap = devm_regmap_init_i2c(i2c, &da9055_regmap_config);
	if (IS_ERR(da9055->regmap)) {
		ret = PTR_ERR(da9055->regmap);
		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
			ret);
		return ret;
	}

	da9055->dev = &i2c->dev;
	da9055->chip_irq = i2c->irq;

	i2c_set_clientdata(i2c, da9055);

	return da9055_device_init(da9055);
}

static int __devexit da9055_i2c_remove(struct i2c_client *i2c)
{
	struct da9055 *da9055 = i2c_get_clientdata(i2c);

	da9055_device_exit(da9055);

	return 0;
}

static struct i2c_device_id da9055_i2c_id[] = {
	{"da9055-pmic", 0},
	{ }
};

static struct i2c_driver da9055_i2c_driver = {
	.probe = da9055_i2c_probe,
	.remove = __devexit_p(da9055_i2c_remove),
	.id_table = da9055_i2c_id,
	.driver = {
		.name = "da9055",
		.owner = THIS_MODULE,
	},
};

static int __init da9055_i2c_init(void)
{
	int ret;

	ret = i2c_add_driver(&da9055_i2c_driver);
	if (ret != 0) {
		pr_err("DA9055 I2C registration failed %d\n", ret);
		return ret;
	}

	return 0;
}
subsys_initcall(da9055_i2c_init);

static void __exit da9055_i2c_exit(void)
{
	i2c_del_driver(&da9055_i2c_driver);
}
module_exit(da9055_i2c_exit);

MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
MODULE_DESCRIPTION("I2C driver for Dialog DA9055 PMIC");
MODULE_LICENSE("GPL");
+94 −0
Original line number Diff line number Diff line
/*
 * da9055 declarations for DA9055 PMICs.
 *
 * Copyright(c) 2012 Dialog Semiconductor Ltd.
 *
 * Author: David Dajun Chen <dchen@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.
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#ifndef __DA9055_CORE_H
#define __DA9055_CORE_H

#include <linux/interrupt.h>
#include <linux/regmap.h>

/*
 * PMIC IRQ
 */
#define DA9055_IRQ_ALARM	0x01
#define DA9055_IRQ_TICK		0x02
#define DA9055_IRQ_NONKEY	0x00
#define DA9055_IRQ_REGULATOR	0x0B
#define DA9055_IRQ_HWMON	0x03

struct da9055_pdata;

struct da9055 {
	struct regmap *regmap;
	struct regmap_irq_chip_data *irq_data;
	struct device *dev;
	struct i2c_client *i2c_client;

	int irq_base;
	int chip_irq;
};

/* Device I/O */
static inline int da9055_reg_read(struct da9055 *da9055, unsigned char reg)
{
	int val, ret;

	ret = regmap_read(da9055->regmap, reg, &val);
	if (ret < 0)
		return ret;

	return val;
}

static inline int da9055_reg_write(struct da9055 *da9055, unsigned char reg,
				    unsigned char val)
{
	return regmap_write(da9055->regmap, reg, val);
}

static inline int da9055_group_read(struct da9055 *da9055, unsigned char reg,
				     unsigned reg_cnt, unsigned char *val)
{
	return regmap_bulk_read(da9055->regmap, reg, val, reg_cnt);
}

static inline int da9055_group_write(struct da9055 *da9055, unsigned char reg,
				      unsigned reg_cnt, unsigned char *val)
{
	return regmap_raw_write(da9055->regmap, reg, val, reg_cnt);
}

static inline int da9055_reg_update(struct da9055 *da9055, unsigned char reg,
				     unsigned char bit_mask,
				     unsigned char reg_val)
{
	return regmap_update_bits(da9055->regmap, reg, bit_mask, reg_val);
}

/* Generic Device API */
int da9055_device_init(struct da9055 *da9055);
void da9055_device_exit(struct da9055 *da9055);

extern struct regmap_config da9055_regmap_config;

#endif /* __DA9055_CORE_H */
Loading