bd7181x: Add driver copied directly from vendor
NOTE: THIS WILL NOT BUILD, SEE NEXT COMMITpull/10/head
parent
fba76239ff
commit
c9ca7510b0
|
@ -741,6 +741,12 @@ config GPIO_ADNP
|
||||||
enough to represent all pins, but the driver will assume a
|
enough to represent all pins, but the driver will assume a
|
||||||
register layout for 64 pins (8 registers).
|
register layout for 64 pins (8 registers).
|
||||||
|
|
||||||
|
config GPIO_BD7181X
|
||||||
|
tristate "BD7181X GPO"
|
||||||
|
depends on MFD_BD7181X
|
||||||
|
help
|
||||||
|
Say yes here to access the GPO signals of bd71815/bd71817 chip from ROHM.
|
||||||
|
|
||||||
config GPIO_MAX7300
|
config GPIO_MAX7300
|
||||||
tristate "Maxim MAX7300 GPIO expander"
|
tristate "Maxim MAX7300 GPIO expander"
|
||||||
select GPIO_MAX730X
|
select GPIO_MAX730X
|
||||||
|
|
|
@ -34,6 +34,7 @@ obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o
|
||||||
obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o
|
obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o
|
||||||
obj-$(CONFIG_GPIO_AXP209) += gpio-axp209.o
|
obj-$(CONFIG_GPIO_AXP209) += gpio-axp209.o
|
||||||
obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
|
obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
|
||||||
|
obj-$(CONFIG_GPIO_BD7181X) += gpio-bd7181x.o
|
||||||
obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
|
obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
|
||||||
obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
|
obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
|
||||||
obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
|
obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
|
||||||
|
|
|
@ -0,0 +1,201 @@
|
||||||
|
/*
|
||||||
|
* gpio-bd7181x.c
|
||||||
|
* @file Access to GPOs on ROHM BD7181XMWV chip
|
||||||
|
*
|
||||||
|
* Copyright 2014 Embest Technology Co. Ltd. Inc.
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
#define DEBUG
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/kthread.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
|
#include <linux/gpio.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
|
||||||
|
#include <linux/mfd/bd7181x.h>
|
||||||
|
|
||||||
|
/** @brief bd7181x gpio chip core data */
|
||||||
|
static struct gpio_chip bd7181xgpo_chip;
|
||||||
|
|
||||||
|
/** @brief get gpo output value
|
||||||
|
* @param chip pointer to core data
|
||||||
|
* @param offset gpo number, start from 0
|
||||||
|
* @retval 0 success
|
||||||
|
* @retval negative error number
|
||||||
|
*/
|
||||||
|
static int bd7181xgpo_get(struct gpio_chip *chip, unsigned offset)
|
||||||
|
{
|
||||||
|
struct bd7181x *bd7181x = dev_get_drvdata(chip->dev->parent);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
ret = bd7181x_reg_read(bd7181x, BD7181X_REG_GPO);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return (ret >> offset) & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief set gpo direction as output
|
||||||
|
* @param chip pointer to core data
|
||||||
|
* @param offset gpo number, start from 0
|
||||||
|
* @param value output value when set direction out
|
||||||
|
* @retval 0 success
|
||||||
|
*/
|
||||||
|
static int bd7181xgpo_direction_out(struct gpio_chip *chip, unsigned offset,
|
||||||
|
int value)
|
||||||
|
{
|
||||||
|
/* This only drives GPOs, and can't change direction */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief set gpo output value
|
||||||
|
* @param chip pointer to core data
|
||||||
|
* @param offset gpo number, start from 0
|
||||||
|
* @param value output value, not zero as high level, 0 as low level
|
||||||
|
* @retval 0 success
|
||||||
|
* @retval negative error number
|
||||||
|
*/
|
||||||
|
static void bd7181xgpo_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||||
|
{
|
||||||
|
struct bd7181x *bd7181x = dev_get_drvdata(chip->dev->parent);
|
||||||
|
int ret;
|
||||||
|
u8 gpoctl;
|
||||||
|
|
||||||
|
ret = bd7181x_reg_read(bd7181x, BD7181X_REG_GPO);
|
||||||
|
if (ret < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
gpoctl = ret | (1 << offset);
|
||||||
|
else
|
||||||
|
gpoctl = ret & ~(1 << offset);
|
||||||
|
|
||||||
|
bd7181x_reg_write(bd7181x, BD7181X_REG_GPO, gpoctl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief bd7181x gpio chip core data */
|
||||||
|
static struct gpio_chip bd7181xgpo_chip = {
|
||||||
|
.label = "bd7181x", ///< gpio chip name
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.get = bd7181xgpo_get,
|
||||||
|
.direction_output = bd7181xgpo_direction_out,
|
||||||
|
.set = bd7181xgpo_set,
|
||||||
|
.can_sleep = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------*/
|
||||||
|
#ifdef CONFIG_OF
|
||||||
|
/** @brief retrive gpo platform data from device tree
|
||||||
|
* @param pdev platfrom device pointer
|
||||||
|
* @return pointer to platform data
|
||||||
|
* @retval NULL error
|
||||||
|
*/
|
||||||
|
static struct bd7181x_gpo_plat_data *of_gpio_bd7181x(
|
||||||
|
struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct bd7181x_gpo_plat_data *platform_data;
|
||||||
|
struct device_node *np, *gpio_np;
|
||||||
|
|
||||||
|
platform_data = devm_kzalloc(&pdev->dev, sizeof(*platform_data), GFP_KERNEL);
|
||||||
|
if (!platform_data) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
np = of_node_get(pdev->dev.parent->of_node);
|
||||||
|
gpio_np = of_find_node_by_name(np, "gpo");
|
||||||
|
if (!gpio_np) {
|
||||||
|
dev_err(&pdev->dev, "gpio node not found\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdev->dev.of_node = gpio_np;
|
||||||
|
|
||||||
|
if (of_property_read_u32(gpio_np, "rohm,mode", &platform_data->mode)) {
|
||||||
|
platform_data->mode = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return platform_data;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @brief probe bd7181x gpo device
|
||||||
|
* @param pdev platfrom device pointer
|
||||||
|
* @retval 0 success
|
||||||
|
* @retval negative error number
|
||||||
|
*/
|
||||||
|
static int gpo_bd7181x_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct bd7181x_gpo_plat_data *pdata = pdev->dev.platform_data;
|
||||||
|
struct device *mfd_dev = pdev->dev.parent;
|
||||||
|
struct bd7181x *bd7181x = dev_get_drvdata(mfd_dev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF
|
||||||
|
pdata = of_gpio_bd7181x(pdev);
|
||||||
|
#endif
|
||||||
|
if (pdata && pdata->gpio_base > 0)
|
||||||
|
bd7181xgpo_chip.base = pdata->gpio_base;
|
||||||
|
else
|
||||||
|
bd7181xgpo_chip.base = -1;
|
||||||
|
|
||||||
|
bd7181xgpo_chip.ngpio = 2; /* bd71815/bd71817 have 2 GPO */
|
||||||
|
|
||||||
|
bd7181xgpo_chip.dev = &pdev->dev;
|
||||||
|
|
||||||
|
ret = gpiochip_add(&bd7181xgpo_chip);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret);
|
||||||
|
bd7181xgpo_chip.ngpio = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pdata && pdata->mode != -1UL) {
|
||||||
|
bd7181x_update_bits(bd7181x, BD7181X_REG_GPO, 0x70, pdata->mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief remove bd7181x gpo device
|
||||||
|
* @param pdev platfrom device pointer
|
||||||
|
* @retval 0 success
|
||||||
|
* @retval negative error number
|
||||||
|
*/
|
||||||
|
static int gpo_bd7181x_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
return gpiochip_remove(&bd7181xgpo_chip);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note: this hardware lives inside an I2C-based multi-function device. */
|
||||||
|
MODULE_ALIAS("platform:bd7181x-gpo");
|
||||||
|
|
||||||
|
/** @brief bd7181x gpo driver core data */
|
||||||
|
static struct platform_driver gpo_bd7181x_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "bd7181x-gpo",
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
},
|
||||||
|
.probe = gpo_bd7181x_probe,
|
||||||
|
.remove = gpo_bd7181x_remove,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(gpo_bd7181x_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Peter Yang <yanglsh@embest-tech.com>");
|
||||||
|
MODULE_DESCRIPTION("GPO interface for BD71815/BD71817");
|
||||||
|
MODULE_LICENSE("GPL");
|
|
@ -1810,6 +1810,14 @@ config MFD_STM32_TIMERS
|
||||||
for PWM and IIO Timer. This driver allow to share the
|
for PWM and IIO Timer. This driver allow to share the
|
||||||
registers between the others drivers.
|
registers between the others drivers.
|
||||||
|
|
||||||
|
config MFD_BD7181X
|
||||||
|
bool "BD71815/BD71817 Power Management chip"
|
||||||
|
depends on I2C=y
|
||||||
|
select MFD_CORE
|
||||||
|
help
|
||||||
|
if you say yes here you get support for the BD71815/BD71817
|
||||||
|
Power Management chips.
|
||||||
|
|
||||||
config MFD_BD71837
|
config MFD_BD71837
|
||||||
bool "BD71837 Power Management chip"
|
bool "BD71837 Power Management chip"
|
||||||
depends on I2C=y
|
depends on I2C=y
|
||||||
|
|
|
@ -231,4 +231,5 @@ obj-$(CONFIG_MFD_SUN4I_GPADC) += sun4i-gpadc.o
|
||||||
obj-$(CONFIG_MFD_STM32_LPTIMER) += stm32-lptimer.o
|
obj-$(CONFIG_MFD_STM32_LPTIMER) += stm32-lptimer.o
|
||||||
obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o
|
obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o
|
||||||
obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o
|
obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o
|
||||||
|
obj-$(CONFIG_MFD_BD7181X) += bd7181x.o
|
||||||
obj-$(CONFIG_MFD_BD71837) += bd71837.o
|
obj-$(CONFIG_MFD_BD71837) += bd71837.o
|
||||||
|
|
|
@ -0,0 +1,389 @@
|
||||||
|
/*
|
||||||
|
* @file bd7181x.c -- RoHM BD7181X/BD71817 mfd driver
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @author: Tony Luo <luofc@embedinfo.com>
|
||||||
|
* Copyright 2014 Embest Technology Co. Ltd. Inc.
|
||||||
|
*/
|
||||||
|
#define DEBUG
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/moduleparam.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/i2c.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
|
#include <linux/irqdomain.h>
|
||||||
|
#include <linux/gpio.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
|
#include <linux/of_gpio.h>
|
||||||
|
#include <linux/mfd/core.h>
|
||||||
|
#include <linux/mfd/bd7181x.h>
|
||||||
|
|
||||||
|
/** @brief bd7181x irq resource */
|
||||||
|
static struct resource rtc_resources[] = {
|
||||||
|
{
|
||||||
|
.start = BD7181X_IRQ_ALARM_12,
|
||||||
|
.end = BD7181X_IRQ_ALARM_12,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct resource power_resources[] = {
|
||||||
|
// irq# 0
|
||||||
|
{
|
||||||
|
.start = BD7181X_IRQ_DCIN_03,
|
||||||
|
.end = BD7181X_IRQ_DCIN_03,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
},
|
||||||
|
// irq# 1
|
||||||
|
{
|
||||||
|
.start = BD7181X_IRQ_BAT_MON_08,
|
||||||
|
.end = BD7181X_IRQ_BAT_MON_08,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
},
|
||||||
|
// irq# 2
|
||||||
|
{
|
||||||
|
.start = BD7181X_IRQ_TEMPERATURE_11,
|
||||||
|
.end = BD7181X_IRQ_TEMPERATURE_11,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief bd7181x multi function cells */
|
||||||
|
static struct mfd_cell bd7181x_mfd_cells[] = {
|
||||||
|
{
|
||||||
|
.name = "bd7181x-pmic",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "bd7181x-power",
|
||||||
|
.num_resources = ARRAY_SIZE(power_resources),
|
||||||
|
.resources = &power_resources[0],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "bd7181x-gpo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "bd7181x-rtc",
|
||||||
|
.num_resources = ARRAY_SIZE(rtc_resources),
|
||||||
|
.resources = &rtc_resources[0],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief bd7181x irqs */
|
||||||
|
static const struct regmap_irq bd7181x_irqs[] = {
|
||||||
|
[BD7181X_IRQ_BUCK_01] = {
|
||||||
|
.mask = BD7181X_INT_EN_01_BUCKAST_MASK,
|
||||||
|
.reg_offset = 1,
|
||||||
|
},
|
||||||
|
[BD7181X_IRQ_DCIN_02] = {
|
||||||
|
.mask = BD7181X_INT_EN_02_DCINAST_MASK,
|
||||||
|
.reg_offset = 2,
|
||||||
|
},
|
||||||
|
[BD7181X_IRQ_DCIN_03] = {
|
||||||
|
.mask = BD7181X_INT_EN_03_DCINAST_MASK,
|
||||||
|
.reg_offset = 3,
|
||||||
|
},
|
||||||
|
[BD7181X_IRQ_VSYS_04] = {
|
||||||
|
.mask = BD7181X_INT_EN_04_VSYSAST_MASK,
|
||||||
|
.reg_offset = 4,
|
||||||
|
},
|
||||||
|
[BD7181X_IRQ_CHARGE_05] = {
|
||||||
|
.mask = BD7181X_INT_EN_05_CHGAST_MASK,
|
||||||
|
.reg_offset = 5,
|
||||||
|
},
|
||||||
|
[BD7181X_IRQ_BAT_06] = {
|
||||||
|
.mask = BD7181X_INT_EN_06_BATAST_MASK,
|
||||||
|
.reg_offset = 6,
|
||||||
|
},
|
||||||
|
[BD7181X_IRQ_BAT_MON_07] = {
|
||||||
|
.mask = BD7181X_INT_EN_07_BMONAST_MASK,
|
||||||
|
.reg_offset = 7,
|
||||||
|
},
|
||||||
|
[BD7181X_IRQ_BAT_MON_08] = {
|
||||||
|
.mask = BD7181X_INT_EN_08_BMONAST_MASK,
|
||||||
|
.reg_offset = 8,
|
||||||
|
},
|
||||||
|
[BD7181X_IRQ_BAT_MON_09] = {
|
||||||
|
.mask = BD7181X_INT_EN_09_BMONAST_MASK,
|
||||||
|
.reg_offset = 9,
|
||||||
|
},
|
||||||
|
[BD7181X_IRQ_BAT_MON_10] = {
|
||||||
|
.mask = BD7181X_INT_EN_10_BMONAST_MASK,
|
||||||
|
.reg_offset = 10,
|
||||||
|
},
|
||||||
|
[BD7181X_IRQ_TEMPERATURE_11] = {
|
||||||
|
.mask = BD7181X_INT_EN_11_TMPAST_MASK,
|
||||||
|
.reg_offset = 11,
|
||||||
|
},
|
||||||
|
[BD7181X_IRQ_ALARM_12] = {
|
||||||
|
.mask = BD7181X_INT_EN_12_ALMAST_MASK,
|
||||||
|
.reg_offset = 12,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief bd7181x irq chip definition */
|
||||||
|
static struct regmap_irq_chip bd7181x_irq_chip = {
|
||||||
|
.name = "bd7181x",
|
||||||
|
.irqs = bd7181x_irqs,
|
||||||
|
.num_irqs = ARRAY_SIZE(bd7181x_irqs),
|
||||||
|
.num_regs = 13,
|
||||||
|
.irq_reg_stride = 1,
|
||||||
|
.status_base = BD7181X_REG_INT_STAT,
|
||||||
|
.mask_base = BD7181X_REG_INT_EN_01 - 1,
|
||||||
|
.mask_invert = true,
|
||||||
|
// .ack_base = BD7181X_REG_INT_STAT_00,
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief bd7181x irq initialize
|
||||||
|
* @param bd7181x bd7181x device to init
|
||||||
|
* @param bdinfo platform init data
|
||||||
|
* @retval 0 probe success
|
||||||
|
* @retval negative error number
|
||||||
|
*/
|
||||||
|
static int bd7181x_irq_init(struct bd7181x *bd7181x, struct bd7181x_board* bdinfo) {
|
||||||
|
int irq;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!bdinfo) {
|
||||||
|
dev_warn(bd7181x->dev, "No interrupt support, no pdata\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
irq = gpio_to_irq(bdinfo->gpio_intr);
|
||||||
|
|
||||||
|
bd7181x->chip_irq = irq;
|
||||||
|
printk("bd7181x->chip_irq=%d \n", bd7181x->chip_irq);
|
||||||
|
ret = regmap_add_irq_chip(bd7181x->regmap, bd7181x->chip_irq,
|
||||||
|
IRQF_ONESHOT | IRQF_TRIGGER_FALLING, bdinfo->irq_base,
|
||||||
|
&bd7181x_irq_chip, &bd7181x->irq_data);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_warn(bd7181x->dev, "Failed to add irq_chip %d\n", ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief bd7181x irq initialize
|
||||||
|
* @param bd7181x bd7181x device to init
|
||||||
|
* @retval 0 probe success
|
||||||
|
* @retval negative error number
|
||||||
|
*/
|
||||||
|
static int bd7181x_irq_exit(struct bd7181x *bd7181x)
|
||||||
|
{
|
||||||
|
if (bd7181x->chip_irq > 0)
|
||||||
|
regmap_del_irq_chip(bd7181x->chip_irq, bd7181x->irq_data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief check whether volatile register
|
||||||
|
* @param dev kernel device pointer
|
||||||
|
* @param reg register index
|
||||||
|
*/
|
||||||
|
static bool is_volatile_reg(struct device *dev, unsigned int reg)
|
||||||
|
{
|
||||||
|
// struct bd7181x *bd7181x = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Caching all regulator registers.
|
||||||
|
*/
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief regmap configures */
|
||||||
|
static const struct regmap_config bd7181x_regmap_config = {
|
||||||
|
.reg_bits = 8,
|
||||||
|
.val_bits = 8,
|
||||||
|
.volatile_reg = is_volatile_reg,
|
||||||
|
.max_register = BD7181X_MAX_REGISTER - 1,
|
||||||
|
.cache_type = REGCACHE_RBTREE,
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF
|
||||||
|
static struct of_device_id bd7181x_of_match[] = {
|
||||||
|
{ .compatible = "rohm,bd71815", .data = (void *)0},
|
||||||
|
{ .compatible = "rohm,bd71817", .data = (void *)1},
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, bd7181x_of_match);
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief parse device tree data of bd7181x
|
||||||
|
* @param client client object provided by system
|
||||||
|
* @param chip_id return chip id back to caller
|
||||||
|
* @return board initialize data
|
||||||
|
*/
|
||||||
|
static struct bd7181x_board *bd7181x_parse_dt(struct i2c_client *client,
|
||||||
|
int *chip_id)
|
||||||
|
{
|
||||||
|
struct device_node *np = client->dev.of_node;
|
||||||
|
struct bd7181x_board *board_info;
|
||||||
|
unsigned int prop;
|
||||||
|
const struct of_device_id *match;
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
|
match = of_match_device(bd7181x_of_match, &client->dev);
|
||||||
|
if (!match) {
|
||||||
|
dev_err(&client->dev, "Failed to find matching dt id\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*chip_id = (int)match->data;
|
||||||
|
|
||||||
|
board_info = devm_kzalloc(&client->dev, sizeof(*board_info),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!board_info) {
|
||||||
|
dev_err(&client->dev, "Failed to allocate pdata\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
board_info->gpio_intr = of_get_named_gpio(np, "gpio_intr", 0);
|
||||||
|
if (!gpio_is_valid(board_info->gpio_intr)) {
|
||||||
|
dev_err(&client->dev, "no pmic intr pin available\n");
|
||||||
|
goto err_intr;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = of_property_read_u32(np, "irq_base", &prop);
|
||||||
|
if (!r) {
|
||||||
|
board_info->irq_base = prop;
|
||||||
|
} else {
|
||||||
|
board_info->irq_base = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return board_info;
|
||||||
|
|
||||||
|
err_intr:
|
||||||
|
devm_kfree(&client->dev, board_info);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static inline
|
||||||
|
struct bd7181x_board *bd7181x_parse_dt(struct i2c_client *client,
|
||||||
|
int *chip_id)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @brief probe bd7181x device
|
||||||
|
* @param i2c client object provided by system
|
||||||
|
* @param id chip id
|
||||||
|
* @retval 0 probe success
|
||||||
|
* @retval negative error number
|
||||||
|
*/
|
||||||
|
static int bd7181x_i2c_probe(struct i2c_client *i2c,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct bd7181x *bd7181x;
|
||||||
|
struct bd7181x_board *pmic_plat_data;
|
||||||
|
struct bd7181x_board *of_pmic_plat_data = NULL;
|
||||||
|
int chip_id = id->driver_data;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
pmic_plat_data = dev_get_platdata(&i2c->dev);
|
||||||
|
|
||||||
|
if (!pmic_plat_data && i2c->dev.of_node) {
|
||||||
|
pmic_plat_data = bd7181x_parse_dt(i2c, &chip_id);
|
||||||
|
of_pmic_plat_data = pmic_plat_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pmic_plat_data)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
bd7181x = kzalloc(sizeof(struct bd7181x), GFP_KERNEL);
|
||||||
|
if (bd7181x == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
bd7181x->of_plat_data = of_pmic_plat_data;
|
||||||
|
i2c_set_clientdata(i2c, bd7181x);
|
||||||
|
bd7181x->dev = &i2c->dev;
|
||||||
|
bd7181x->i2c_client = i2c;
|
||||||
|
bd7181x->id = chip_id;
|
||||||
|
mutex_init(&bd7181x->io_mutex);
|
||||||
|
|
||||||
|
bd7181x->regmap = devm_regmap_init_i2c(i2c, &bd7181x_regmap_config);
|
||||||
|
if (IS_ERR(bd7181x->regmap)) {
|
||||||
|
ret = PTR_ERR(bd7181x->regmap);
|
||||||
|
dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = bd7181x_reg_read(bd7181x, BD7181X_REG_DEVICE);
|
||||||
|
if(ret < 0) {
|
||||||
|
dev_err(bd7181x->dev, "%s(): Read BD7181X_REG_DEVICE failed!\n", __func__);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
dev_info(bd7181x->dev, "BD7181x: Device ID=0x%X\n", ret);
|
||||||
|
|
||||||
|
bd7181x_irq_init(bd7181x, of_pmic_plat_data);
|
||||||
|
|
||||||
|
ret = mfd_add_devices(bd7181x->dev, -1,
|
||||||
|
bd7181x_mfd_cells, ARRAY_SIZE(bd7181x_mfd_cells),
|
||||||
|
NULL, 0,
|
||||||
|
regmap_irq_get_domain(bd7181x->irq_data));
|
||||||
|
if (ret < 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
err:
|
||||||
|
mfd_remove_devices(bd7181x->dev);
|
||||||
|
kfree(bd7181x);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief remove bd7181x device
|
||||||
|
* @param i2c client object provided by system
|
||||||
|
* @return 0
|
||||||
|
*/
|
||||||
|
static int bd7181x_i2c_remove(struct i2c_client *i2c)
|
||||||
|
{
|
||||||
|
struct bd7181x *bd7181x = i2c_get_clientdata(i2c);
|
||||||
|
|
||||||
|
bd7181x_irq_exit(bd7181x);
|
||||||
|
mfd_remove_devices(bd7181x->dev);
|
||||||
|
kfree(bd7181x);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct i2c_device_id bd7181x_i2c_id[] = {
|
||||||
|
{ "bd71815", 0 },
|
||||||
|
{ "bd71817", 1 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, bd7181x_i2c_id);
|
||||||
|
|
||||||
|
|
||||||
|
static struct i2c_driver bd7181x_i2c_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "bd7181x",
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.of_match_table = of_match_ptr(bd7181x_of_match),
|
||||||
|
},
|
||||||
|
.probe = bd7181x_i2c_probe,
|
||||||
|
.remove = bd7181x_i2c_remove,
|
||||||
|
.id_table = bd7181x_i2c_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init bd7181x_i2c_init(void)
|
||||||
|
{
|
||||||
|
return i2c_add_driver(&bd7181x_i2c_driver);
|
||||||
|
}
|
||||||
|
/* init early so consumer devices can complete system boot */
|
||||||
|
subsys_initcall(bd7181x_i2c_init);
|
||||||
|
|
||||||
|
static void __exit bd7181x_i2c_exit(void)
|
||||||
|
{
|
||||||
|
i2c_del_driver(&bd7181x_i2c_driver);
|
||||||
|
}
|
||||||
|
module_exit(bd7181x_i2c_exit);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Tony Luo <luofc@embest-tech.com>");
|
||||||
|
MODULE_AUTHOR("Peter Yang <yanglsh@embest-tech.com>");
|
||||||
|
MODULE_DESCRIPTION("BD71815/BD71817 chip multi-function driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
|
@ -29,6 +29,12 @@ config APM_POWER
|
||||||
Say Y here to enable support APM status emulation using
|
Say Y here to enable support APM status emulation using
|
||||||
battery class devices.
|
battery class devices.
|
||||||
|
|
||||||
|
config BD7181X_POWER
|
||||||
|
tristate "ROHM BD71815/BD71817 Charger for Battery and Adapter Power"
|
||||||
|
depends on MFD_BD7181X
|
||||||
|
help
|
||||||
|
Say Y to enable support for the BD71815/BD71817 charger.
|
||||||
|
|
||||||
config GENERIC_ADC_BATTERY
|
config GENERIC_ADC_BATTERY
|
||||||
tristate "Generic battery support using IIO"
|
tristate "Generic battery support using IIO"
|
||||||
depends on IIO
|
depends on IIO
|
||||||
|
|
|
@ -10,6 +10,7 @@ obj-$(CONFIG_GENERIC_ADC_BATTERY) += generic-adc-battery.o
|
||||||
|
|
||||||
obj-$(CONFIG_PDA_POWER) += pda_power.o
|
obj-$(CONFIG_PDA_POWER) += pda_power.o
|
||||||
obj-$(CONFIG_APM_POWER) += apm_power.o
|
obj-$(CONFIG_APM_POWER) += apm_power.o
|
||||||
|
obj-$(CONFIG_BD7181X_POWER) += bd7181x-power.o
|
||||||
obj-$(CONFIG_AXP20X_POWER) += axp20x_usb_power.o
|
obj-$(CONFIG_AXP20X_POWER) += axp20x_usb_power.o
|
||||||
obj-$(CONFIG_MAX8925_POWER) += max8925_power.o
|
obj-$(CONFIG_MAX8925_POWER) += max8925_power.o
|
||||||
obj-$(CONFIG_WM831X_BACKUP) += wm831x_backup.o
|
obj-$(CONFIG_WM831X_BACKUP) += wm831x_backup.o
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -171,6 +171,12 @@ config REGULATOR_BCM590XX
|
||||||
BCM590xx PMUs. This will enable support for the software
|
BCM590xx PMUs. This will enable support for the software
|
||||||
controllable LDO/Switching regulators.
|
controllable LDO/Switching regulators.
|
||||||
|
|
||||||
|
config REGULATOR_BD7181X
|
||||||
|
tristate "RoHM BD71815/BD71817 Power Regulator"
|
||||||
|
depends on MFD_BD7181X
|
||||||
|
help
|
||||||
|
This driver supports BD71815/BD71817 voltage regulator chips.
|
||||||
|
|
||||||
config REGULATOR_BD9571MWV
|
config REGULATOR_BD9571MWV
|
||||||
tristate "ROHM BD9571MWV Regulators"
|
tristate "ROHM BD9571MWV Regulators"
|
||||||
depends on MFD_BD9571MWV
|
depends on MFD_BD9571MWV
|
||||||
|
|
|
@ -26,6 +26,7 @@ obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o
|
||||||
obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o
|
obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o
|
||||||
obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o
|
obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o
|
||||||
obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o
|
obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o
|
||||||
|
obj-$(CONFIG_REGULATOR_BD7181X) += bd7181x-regulator.o
|
||||||
obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o
|
obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o
|
||||||
obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
|
obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
|
||||||
obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o
|
obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o
|
||||||
|
|
|
@ -0,0 +1,791 @@
|
||||||
|
/*
|
||||||
|
* @file bd7181x-regulator.c RoHM BD71815/BD71817 regulator driver
|
||||||
|
*
|
||||||
|
* Copyright 2014 Embest Technology Co. Ltd. Inc.
|
||||||
|
*
|
||||||
|
* @author Tony Luo <luofc@embedinfo.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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define DEBUG
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/regulator/driver.h>
|
||||||
|
#include <linux/regulator/machine.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/gpio.h>
|
||||||
|
#include <linux/mfd/bd7181x.h>
|
||||||
|
#include <linux/regulator/of_regulator.h>
|
||||||
|
|
||||||
|
#define BD7181X_VOL_OFFSET 0
|
||||||
|
#define BD7181X_STANDBY_OFFSET 0
|
||||||
|
#define BD7181X_DVS_BUCK_NUM 2
|
||||||
|
#define BD7181X_DVS_HIGH_LOW 2
|
||||||
|
|
||||||
|
struct bd7181x_buck_dvs {
|
||||||
|
int i2c_dvs_enable;
|
||||||
|
u32 voltage[BD7181X_DVS_HIGH_LOW];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bd7181x_regulator {
|
||||||
|
struct regulator_desc desc;
|
||||||
|
unsigned char stby_reg;
|
||||||
|
unsigned char stby_mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief bd7181x regulator type */
|
||||||
|
struct bd7181x_pmic {
|
||||||
|
struct bd7181x_regulator descs[BD7181X_REGULATOR_CNT]; /**< regulator description to system */
|
||||||
|
struct bd7181x *mfd; /**< parent device */
|
||||||
|
struct device *dev; /**< regulator kernel device */
|
||||||
|
struct regulator_dev *rdev[BD7181X_REGULATOR_CNT]; /**< regulator device of system */
|
||||||
|
struct bd7181x_buck_dvs buck_dvs[BD7181X_DVS_BUCK_NUM]; /**< buck1/2 dvs */
|
||||||
|
};
|
||||||
|
|
||||||
|
static const int bd7181x_wled_currents[] = {
|
||||||
|
// 0x00
|
||||||
|
10, 20, 30, 50,
|
||||||
|
70, 100, 200, 300,
|
||||||
|
500, 700, 1000, 2000,
|
||||||
|
3000, 4000, 5000, 6000,
|
||||||
|
// 0x10
|
||||||
|
7000, 8000, 9000, 10000,
|
||||||
|
11000, 12000, 13000, 14000,
|
||||||
|
15000, 16000, 17000, 18000,
|
||||||
|
19000, 20000, 21000, 22000,
|
||||||
|
// 0x20
|
||||||
|
23000, 24000, 25000,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* BUCK1/2
|
||||||
|
* BUCK1RAMPRATE[1:0] BUCK1 DVS ramp rate setting
|
||||||
|
* 00: 10.00mV/usec 10mV 1uS
|
||||||
|
* 01: 5.00mV/usec 10mV 2uS
|
||||||
|
* 10: 2.50mV/usec 10mV 4uS
|
||||||
|
* 11: 1.25mV/usec 10mV 8uS
|
||||||
|
*/
|
||||||
|
static int bd7181x_buck12_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
|
||||||
|
{
|
||||||
|
struct bd7181x_pmic *pmic = rdev_get_drvdata(rdev);
|
||||||
|
struct bd7181x *mfd = pmic->mfd;
|
||||||
|
int id = rdev->desc->id;
|
||||||
|
unsigned int ramp_value = BUCK1_RAMPRATE_10P00MV;
|
||||||
|
|
||||||
|
switch (ramp_delay) {
|
||||||
|
case 1 ... 1250:
|
||||||
|
ramp_value = BUCK1_RAMPRATE_1P25MV;
|
||||||
|
break;
|
||||||
|
case 1251 ... 2500:
|
||||||
|
ramp_value = BUCK1_RAMPRATE_2P50MV;
|
||||||
|
break;
|
||||||
|
case 2501 ... 5000:
|
||||||
|
ramp_value = BUCK1_RAMPRATE_5P00MV;
|
||||||
|
break;
|
||||||
|
case 5001 ... 10000:
|
||||||
|
ramp_value = BUCK1_RAMPRATE_10P00MV;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ramp_value = BUCK1_RAMPRATE_10P00MV;
|
||||||
|
dev_err(pmic->dev, "%s: ramp_delay: %d not supported, setting 10000mV//us\n",
|
||||||
|
rdev->desc->name, ramp_delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
return regmap_update_bits(mfd->regmap, BD7181X_REG_BUCK1_MODE + id*0x1,
|
||||||
|
BUCK1_RAMPRATE_MASK, ramp_value << 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bd7181x_led_set_current_limit(struct regulator_dev *rdev,
|
||||||
|
int min_uA, int max_uA)
|
||||||
|
{
|
||||||
|
struct bd7181x_pmic* pmic = rdev_get_drvdata(rdev);
|
||||||
|
struct bd7181x* mfd = pmic->mfd;
|
||||||
|
u8 addr;
|
||||||
|
// int id = rdev_get_id(rdev);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
addr = BD7181X_REG_LED_DIMM;
|
||||||
|
|
||||||
|
for (i = ARRAY_SIZE(bd7181x_wled_currents) - 1 ; i >= 0; i--) {
|
||||||
|
if (bd7181x_wled_currents[i] >= min_uA &&
|
||||||
|
bd7181x_wled_currents[i] <= max_uA)
|
||||||
|
return bd7181x_update_bits(mfd, addr, 0x3F, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bd7181x_led_get_current_limit(struct regulator_dev *rdev)
|
||||||
|
{
|
||||||
|
struct bd7181x_pmic* pmic = rdev_get_drvdata(rdev);
|
||||||
|
struct bd7181x* mfd = pmic->mfd;
|
||||||
|
// int id = rdev_get_id(rdev);
|
||||||
|
u8 addr;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
addr = BD7181X_REG_LED_DIMM;
|
||||||
|
|
||||||
|
r = bd7181x_reg_read(mfd, addr);
|
||||||
|
if (r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = r & 0x3F;
|
||||||
|
|
||||||
|
return (r < ARRAY_SIZE(bd7181x_wled_currents)) ?
|
||||||
|
bd7181x_wled_currents[r] : -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bd7181x_buck12_get_voltage_sel(struct regulator_dev *rdev)
|
||||||
|
{
|
||||||
|
struct bd7181x_pmic *pmic = rdev_get_drvdata(rdev);
|
||||||
|
int rid = rdev_get_id(rdev);
|
||||||
|
struct bd7181x *bd7181x = pmic->mfd;
|
||||||
|
int ret, val;
|
||||||
|
u8 regh = BD7181X_REG_BUCK1_VOLT_H + rid*0x2,
|
||||||
|
regl = BD7181X_REG_BUCK1_VOLT_L + rid*0x2;
|
||||||
|
|
||||||
|
ret = bd7181x_reg_read(bd7181x, regh);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
val = ret;
|
||||||
|
if((!(val & BUCK1_STBY_DVS)) && (!(val & BUCK1_DVSSEL))) {
|
||||||
|
ret = bd7181x_reg_read(bd7181x, regl);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
val = ret & BUCK1_L_MASK;
|
||||||
|
} else {
|
||||||
|
val &= BUCK1_H_MASK;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For Buck 1/2.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static int bd7181x_buck12_set_voltage_sel(struct regulator_dev *rdev, unsigned sel)
|
||||||
|
{
|
||||||
|
struct bd7181x_pmic *pmic = rdev_get_drvdata(rdev);
|
||||||
|
int rid = rdev_get_id(rdev);
|
||||||
|
struct bd7181x *bd7181x = pmic->mfd;
|
||||||
|
int ret, val;
|
||||||
|
u8 regh = BD7181X_REG_BUCK1_VOLT_H + rid*0x2,
|
||||||
|
regl = BD7181X_REG_BUCK1_VOLT_L + rid*0x2;
|
||||||
|
|
||||||
|
ret = bd7181x_reg_read(bd7181x, regh);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
val = ret;
|
||||||
|
if((!(val & BUCK1_STBY_DVS)) && (!(val & BUCK1_DVSSEL))) {
|
||||||
|
ret = bd7181x_reg_write(bd7181x, regl, sel & BUCK1_L_MASK);
|
||||||
|
} else {
|
||||||
|
val = (val & 0xC0) | (sel & BUCK1_H_MASK);
|
||||||
|
ret = bd7181x_reg_write(bd7181x, regh, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct regulator_ops bd7181x_ldo_regulator_ops = {
|
||||||
|
.enable = regulator_enable_regmap,
|
||||||
|
.disable = regulator_disable_regmap,
|
||||||
|
.is_enabled = regulator_is_enabled_regmap,
|
||||||
|
.list_voltage = regulator_list_voltage_linear,
|
||||||
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||||
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct regulator_ops bd7181x_fixed_regulator_ops = {
|
||||||
|
.enable = regulator_enable_regmap,
|
||||||
|
.disable = regulator_disable_regmap,
|
||||||
|
.is_enabled = regulator_is_enabled_regmap,
|
||||||
|
.list_voltage = regulator_list_voltage_linear,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct regulator_ops bd7181x_buck_regulator_ops = {
|
||||||
|
.enable = regulator_enable_regmap,
|
||||||
|
.disable = regulator_disable_regmap,
|
||||||
|
.is_enabled = regulator_is_enabled_regmap,
|
||||||
|
.list_voltage = regulator_list_voltage_linear,
|
||||||
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||||
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||||
|
.set_voltage_time_sel = regulator_set_voltage_time_sel,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct regulator_ops bd7181x_buck12_regulator_ops = {
|
||||||
|
.enable = regulator_enable_regmap,
|
||||||
|
.disable = regulator_disable_regmap,
|
||||||
|
.is_enabled = regulator_is_enabled_regmap,
|
||||||
|
.list_voltage = regulator_list_voltage_linear,
|
||||||
|
.set_voltage_sel = bd7181x_buck12_set_voltage_sel,
|
||||||
|
.get_voltage_sel = bd7181x_buck12_get_voltage_sel,
|
||||||
|
.set_voltage_time_sel = regulator_set_voltage_time_sel,
|
||||||
|
.set_ramp_delay = bd7181x_buck12_set_ramp_delay,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct regulator_ops bd7181x_led_regulator_ops = {
|
||||||
|
.enable = regulator_enable_regmap,
|
||||||
|
.disable = regulator_disable_regmap,
|
||||||
|
.is_enabled = regulator_is_enabled_regmap,
|
||||||
|
.list_voltage = regulator_list_voltage_table,
|
||||||
|
.map_voltage = regulator_map_voltage_ascend,
|
||||||
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||||
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||||
|
.set_current_limit = bd7181x_led_set_current_limit,
|
||||||
|
.get_current_limit = bd7181x_led_get_current_limit,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BD7181X_FIXED_REG(_name, ereg, emsk, voltage) \
|
||||||
|
[BD7181X_ ## _name] = { \
|
||||||
|
.desc = { \
|
||||||
|
.name = #_name, \
|
||||||
|
.n_voltages = 1, \
|
||||||
|
.ops = &bd7181x_fixed_regulator_ops, \
|
||||||
|
.type = REGULATOR_VOLTAGE, \
|
||||||
|
.id = BD7181X_ ## _name, \
|
||||||
|
.owner = THIS_MODULE, \
|
||||||
|
.min_uV = (voltage), \
|
||||||
|
.enable_reg = (ereg), \
|
||||||
|
.enable_mask = (emsk), \
|
||||||
|
}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BD7181X_BUCK_REG(_name, base, ereg, min, max, step) \
|
||||||
|
[BD7181X_ ## _name] = { \
|
||||||
|
.desc = { \
|
||||||
|
.name = #_name,\
|
||||||
|
.n_voltages = ((max) - (min)) / (step) + 1, \
|
||||||
|
.ops = &bd7181x_buck_regulator_ops, \
|
||||||
|
.type = REGULATOR_VOLTAGE, \
|
||||||
|
.id = BD7181X_ ## _name, \
|
||||||
|
.owner = THIS_MODULE, \
|
||||||
|
.min_uV = (min), \
|
||||||
|
.uV_step = (step), \
|
||||||
|
.vsel_reg = (base) + BD7181X_VOL_OFFSET, \
|
||||||
|
.vsel_mask = 0x3f, \
|
||||||
|
.enable_reg = (ereg), \
|
||||||
|
.enable_mask = 0x04, \
|
||||||
|
}, \
|
||||||
|
.stby_reg = (base) + BD7181X_STANDBY_OFFSET, \
|
||||||
|
.stby_mask = 0x3f, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BD7181X_BUCK12_REG(_name, base, ereg, min, max, step) \
|
||||||
|
[BD7181X_ ## _name] = { \
|
||||||
|
.desc = { \
|
||||||
|
.name = #_name,\
|
||||||
|
.n_voltages = ((max) - (min)) / (step) + 1, \
|
||||||
|
.ops = &bd7181x_buck12_regulator_ops, \
|
||||||
|
.type = REGULATOR_VOLTAGE, \
|
||||||
|
.id = BD7181X_ ## _name, \
|
||||||
|
.owner = THIS_MODULE, \
|
||||||
|
.min_uV = (min), \
|
||||||
|
.uV_step = (step), \
|
||||||
|
.vsel_reg = (base) + BD7181X_VOL_OFFSET, \
|
||||||
|
.vsel_mask = 0x3f, \
|
||||||
|
.enable_reg = (ereg), \
|
||||||
|
.enable_mask = 0x04, \
|
||||||
|
}, \
|
||||||
|
.stby_reg = (base) + BD7181X_STANDBY_OFFSET, \
|
||||||
|
.stby_mask = 0x3f, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BD7181X_LED_REG(_name, base, mask, ereg, emsk, voltages) \
|
||||||
|
[BD7181X_ ## _name] = { \
|
||||||
|
.desc = { \
|
||||||
|
.name = #_name, \
|
||||||
|
.n_voltages = ARRAY_SIZE(voltages), \
|
||||||
|
.ops = &bd7181x_led_regulator_ops, \
|
||||||
|
.type = REGULATOR_CURRENT, \
|
||||||
|
.id = BD7181X_ ## _name, \
|
||||||
|
.owner = THIS_MODULE, \
|
||||||
|
.volt_table = voltages, \
|
||||||
|
.vsel_reg = (base), \
|
||||||
|
.vsel_mask = (mask), \
|
||||||
|
.enable_reg = (ereg), \
|
||||||
|
.enable_mask = (emsk), \
|
||||||
|
}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BD7181X_LDO_REG(_name, base, ereg, emsk, min, max, step) \
|
||||||
|
[BD7181X_ ## _name] = { \
|
||||||
|
.desc = { \
|
||||||
|
.name = #_name, \
|
||||||
|
.n_voltages = ((max) - (min)) / (step) + 1, \
|
||||||
|
.ops = &bd7181x_ldo_regulator_ops, \
|
||||||
|
.type = REGULATOR_VOLTAGE, \
|
||||||
|
.id = BD7181X_ ## _name, \
|
||||||
|
.owner = THIS_MODULE, \
|
||||||
|
.min_uV = (min), \
|
||||||
|
.uV_step = (step), \
|
||||||
|
.vsel_reg = (base), \
|
||||||
|
.vsel_mask = 0x3f, \
|
||||||
|
.enable_reg = (ereg), \
|
||||||
|
.enable_mask = (emsk), \
|
||||||
|
}, \
|
||||||
|
.stby_reg = (base), \
|
||||||
|
.stby_mask = 0x20, \
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct bd7181x_regulator bd7181x_regulators[] = {
|
||||||
|
BD7181X_BUCK12_REG(BUCK1, BD7181X_REG_BUCK1_VOLT_H, BD7181X_REG_BUCK1_MODE, 800000, 2000000, 25000),
|
||||||
|
BD7181X_BUCK12_REG(BUCK2, BD7181X_REG_BUCK2_VOLT_H, BD7181X_REG_BUCK2_MODE, 800000, 2000000, 25000),
|
||||||
|
BD7181X_BUCK_REG(BUCK3, BD7181X_REG_BUCK3_VOLT, BD7181X_REG_BUCK3_MODE, 1200000, 2700000, 50000),
|
||||||
|
BD7181X_BUCK_REG(BUCK4, BD7181X_REG_BUCK4_VOLT, BD7181X_REG_BUCK4_MODE, 1100000, 1850000, 25000),
|
||||||
|
BD7181X_BUCK_REG(BUCK5, BD7181X_REG_BUCK5_VOLT, BD7181X_REG_BUCK5_MODE, 1800000, 3300000, 50000),
|
||||||
|
BD7181X_LDO_REG(LDO1, BD7181X_REG_LDO1_VOLT, BD7181X_REG_LDO_MODE1, 0x40, 800000, 3300000, 50000),
|
||||||
|
BD7181X_LDO_REG(LDO2, BD7181X_REG_LDO2_VOLT, BD7181X_REG_LDO_MODE2, 0x04, 800000, 3300000, 50000),
|
||||||
|
BD7181X_LDO_REG(LDO3, BD7181X_REG_LDO3_VOLT, BD7181X_REG_LDO_MODE2, 0x40, 800000, 3300000, 50000),
|
||||||
|
BD7181X_LDO_REG(LDO4, BD7181X_REG_LDO4_VOLT, BD7181X_REG_LDO_MODE3, 0x04, 800000, 3300000, 50000),
|
||||||
|
BD7181X_LDO_REG(LDO5, BD7181X_REG_LDO5_VOLT_H,BD7181X_REG_LDO_MODE3,0x40, 800000, 3300000, 50000),
|
||||||
|
BD7181X_FIXED_REG(LDODVREF, BD7181X_REG_LDO_MODE4, 0x40, 3000000),
|
||||||
|
BD7181X_FIXED_REG(LDOLPSR, BD7181X_REG_LDO_MODE4, 0x04, 1800000),
|
||||||
|
BD7181X_LED_REG(WLED, BD7181X_REG_LED_DIMM, 0x3F, BD7181X_REG_LED_CTRL, 0x04, bd7181x_wled_currents),
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF
|
||||||
|
|
||||||
|
static struct of_regulator_match bd7181x_matches[] = {
|
||||||
|
{ .name = "buck1", },
|
||||||
|
{ .name = "buck2", },
|
||||||
|
{ .name = "buck3", },
|
||||||
|
{ .name = "buck4", },
|
||||||
|
{ .name = "buck5", },
|
||||||
|
{ .name = "ldo1", },
|
||||||
|
{ .name = "ldo2", },
|
||||||
|
{ .name = "ldo3", },
|
||||||
|
{ .name = "ldo4", },
|
||||||
|
{ .name = "ldo5", },
|
||||||
|
{ .name = "dvref", },
|
||||||
|
{ .name = "lpsr", },
|
||||||
|
{ .name = "wled", },
|
||||||
|
};
|
||||||
|
|
||||||
|
/**@brief parse bd7181x regulator device tree
|
||||||
|
* @param pdev platform device of bd7181x regulator
|
||||||
|
* @param bd7181x_reg_matches return regualtor matches
|
||||||
|
* @retval 0 parse success
|
||||||
|
* @retval NULL parse fail
|
||||||
|
*/
|
||||||
|
static int bd7181x_parse_dt_reg_data(
|
||||||
|
struct platform_device *pdev,
|
||||||
|
struct of_regulator_match **reg_matches)
|
||||||
|
{
|
||||||
|
// struct bd7181x *bd7181x = dev_get_drvdata(pdev->dev.parent);
|
||||||
|
struct device_node *np, *regulators;
|
||||||
|
struct of_regulator_match *matches;
|
||||||
|
int ret, count;
|
||||||
|
|
||||||
|
np = of_node_get(pdev->dev.parent->of_node);
|
||||||
|
regulators = of_find_node_by_name(np, "regulators");
|
||||||
|
if (!regulators) {
|
||||||
|
dev_err(&pdev->dev, "regulator node not found\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = ARRAY_SIZE(bd7181x_matches);
|
||||||
|
matches = bd7181x_matches;
|
||||||
|
|
||||||
|
ret = of_regulator_match(&pdev->dev, regulators, matches, count);
|
||||||
|
of_node_put(regulators);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
|
||||||
|
ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
*reg_matches = matches;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static inline int bd7181x_parse_dt_reg_data(
|
||||||
|
struct platform_device *pdev,
|
||||||
|
struct of_regulator_match **reg_matches)
|
||||||
|
{
|
||||||
|
*reg_matches = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @brief out32k mode constants */
|
||||||
|
static const char* out32k_modes[] = {"open_drain", "cmos"};
|
||||||
|
|
||||||
|
/** @brief retrive out32k output mode */
|
||||||
|
static ssize_t show_mode(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct bd7181x_pmic *pmic = dev_get_drvdata(dev);
|
||||||
|
int o;
|
||||||
|
|
||||||
|
o = bd7181x_reg_read(pmic->mfd, BD7181X_REG_OUT32K);
|
||||||
|
o = (o & OUT32K_MODE) != 0;
|
||||||
|
|
||||||
|
return sprintf(buf, "%s\n", out32k_modes[o]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief set out32k output mode */
|
||||||
|
static ssize_t set_mode(struct device *dev, struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct bd7181x_pmic *pmic = dev_get_drvdata(dev);
|
||||||
|
int o, r;
|
||||||
|
|
||||||
|
if (strncmp(buf, out32k_modes[0], strlen(out32k_modes[0])) == 0) {
|
||||||
|
o = 0;
|
||||||
|
} else {
|
||||||
|
o = OUT32K_MODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = bd7181x_update_bits(pmic->mfd, BD7181X_REG_OUT32K, OUT32K_MODE, o);
|
||||||
|
if (r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief retrive out32k output value */
|
||||||
|
static ssize_t show_value(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct bd7181x_pmic *pmic = dev_get_drvdata(dev);
|
||||||
|
int o;
|
||||||
|
|
||||||
|
o = bd7181x_reg_read(pmic->mfd, BD7181X_REG_OUT32K);
|
||||||
|
o = (o & OUT32K_EN) != 0;
|
||||||
|
|
||||||
|
return sprintf(buf, "%d\n", o);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief set o output value */
|
||||||
|
static ssize_t set_value(struct device *dev, struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct bd7181x_pmic *pmic = dev_get_drvdata(dev);
|
||||||
|
int o, r;
|
||||||
|
|
||||||
|
if (sscanf(buf, "%d", &o) < 1) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (o != 0) {
|
||||||
|
o = OUT32K_EN;
|
||||||
|
}
|
||||||
|
r = bd7181x_update_bits(pmic->mfd, BD7181X_REG_OUT32K, OUT32K_EN, o);
|
||||||
|
if (r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief list all supported modes */
|
||||||
|
static ssize_t available_modes(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
int i, r;
|
||||||
|
|
||||||
|
r = 0;
|
||||||
|
for (i = 0; i < ARRAY_SIZE(out32k_modes) && r >= 0; i++) {
|
||||||
|
r += sprintf(buf + r, "%s ", out32k_modes[i]);
|
||||||
|
}
|
||||||
|
r += sprintf(buf + r, "\n");
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief list all supported values */
|
||||||
|
static ssize_t available_values(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
return sprintf(buf, "0 1 \n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief retrive dvssel output value */
|
||||||
|
static ssize_t show_dvssel(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct bd7181x_pmic *pmic = dev_get_drvdata(dev);
|
||||||
|
int value, index = 0, i;
|
||||||
|
|
||||||
|
for (i = 0; i < BD7181X_DVS_BUCK_NUM; i++) {
|
||||||
|
value = bd7181x_reg_read(pmic->mfd, BD7181X_REG_BUCK1_VOLT_H + i*0x2);
|
||||||
|
if(value < 0)
|
||||||
|
return value;
|
||||||
|
value = (value & BUCK1_DVSSEL) != 0;
|
||||||
|
index += sprintf(buf+index, "BUCK%i: %d\n", i, value);
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief set o output value */
|
||||||
|
static ssize_t set_dvssel(struct device *dev, struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct bd7181x_pmic *pmic = dev_get_drvdata(dev);
|
||||||
|
int devsel1, devsel2, ret;
|
||||||
|
|
||||||
|
if (sscanf(buf, "%d %d", &devsel1, &devsel2) < 1) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = bd7181x_update_bits(pmic->mfd, BD7181X_REG_BUCK1_VOLT_H, BUCK1_DVSSEL, devsel1<<7);
|
||||||
|
if(ret < 0)
|
||||||
|
return ret;
|
||||||
|
ret = bd7181x_update_bits(pmic->mfd, BD7181X_REG_BUCK2_VOLT_H, BUCK2_DVSSEL, devsel2<<7);
|
||||||
|
if(ret < 0)
|
||||||
|
return ret;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR(out32k_mode, S_IWUSR | S_IRUGO, show_mode, set_mode);
|
||||||
|
static DEVICE_ATTR(out32k_value, S_IWUSR | S_IRUGO, show_value, set_value);
|
||||||
|
static DEVICE_ATTR(available_mode, S_IWUSR | S_IRUGO, available_modes, NULL);
|
||||||
|
static DEVICE_ATTR(available_value, S_IWUSR | S_IRUGO, available_values, NULL);
|
||||||
|
static DEVICE_ATTR(dvssel, S_IWUSR | S_IRUGO, show_dvssel, set_dvssel);
|
||||||
|
|
||||||
|
/** @brief device sysfs attribute table, about o */
|
||||||
|
static struct attribute *gpo_attributes[] = {
|
||||||
|
&dev_attr_out32k_mode.attr,
|
||||||
|
&dev_attr_out32k_value.attr,
|
||||||
|
&dev_attr_available_mode.attr,
|
||||||
|
&dev_attr_available_value.attr,
|
||||||
|
&dev_attr_dvssel.attr,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group gpo_attr_group = {
|
||||||
|
.attrs = gpo_attributes,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------*/
|
||||||
|
#ifdef CONFIG_OF
|
||||||
|
/** @brief buck1/2 dvs enable/voltage from device tree
|
||||||
|
* @param pdev platfrom device pointer
|
||||||
|
* @param buck_dvs pointer
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
static void of_bd7181x_buck_dvs(struct platform_device *pdev, struct bd7181x_buck_dvs *buck_dvs)
|
||||||
|
{
|
||||||
|
struct device_node *pmic_np;
|
||||||
|
|
||||||
|
pmic_np = of_node_get(pdev->dev.parent->of_node);
|
||||||
|
if (!pmic_np) {
|
||||||
|
dev_err(&pdev->dev, "could not find pmic sub-node\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (of_get_property(pmic_np, "bd7181x,pmic-buck1-uses-i2c-dvs", NULL)) {
|
||||||
|
buck_dvs[0].i2c_dvs_enable = 1;
|
||||||
|
if (of_property_read_u32_array(pmic_np,
|
||||||
|
"bd7181x,pmic-buck1-dvs-voltage",
|
||||||
|
&buck_dvs[0].voltage[0], 2)) {
|
||||||
|
dev_err(&pdev->dev, "buck1 voltages not specified\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (of_get_property(pmic_np, "bd7181x,pmic-buck2-uses-i2c-dvs", NULL)) {
|
||||||
|
buck_dvs[1].i2c_dvs_enable = 1;
|
||||||
|
if (of_property_read_u32_array(pmic_np,
|
||||||
|
"bd7181x,pmic-buck2-dvs-voltage",
|
||||||
|
&buck_dvs[1].voltage[0], 2)) {
|
||||||
|
dev_err(&pdev->dev, "buck2 voltages not specified\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static void of_bd7181x_buck_dvs(struct platform_device *pdev, struct bd7181x_buck_dvs *buck_dvs)
|
||||||
|
{
|
||||||
|
buck_dvs[0].i2c_dvs_enable = 0;
|
||||||
|
buck_dvs[0].voltage[0] = BUCK1_H_DEFAULT;
|
||||||
|
buck_dvs[0].voltage[1] = BUCK1_L_DEFAULT;
|
||||||
|
buck_dvs[1].i2c_dvs_enable = 0;
|
||||||
|
buck_dvs[1].voltage[0] = BUCK1_H_DEFAULT;
|
||||||
|
buck_dvs[1].voltage[1] = BUCK1_L_DEFAULT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int bd7181x_buck12_dvs_init(struct bd7181x_pmic *pmic)
|
||||||
|
{
|
||||||
|
struct bd7181x *bd7181x = pmic->mfd;
|
||||||
|
struct bd7181x_buck_dvs *buck_dvs = &pmic->buck_dvs[0];
|
||||||
|
int i, ret, val, selector = 0;
|
||||||
|
u8 regh, regl;
|
||||||
|
|
||||||
|
for(i = 0; i < BD7181X_DVS_BUCK_NUM; i++, buck_dvs++) {
|
||||||
|
regh = BD7181X_REG_BUCK1_VOLT_H + i*0x2;
|
||||||
|
regl = BD7181X_REG_BUCK1_VOLT_L + i*0x2;
|
||||||
|
val = BUCK1_DVSSEL;
|
||||||
|
if(buck_dvs->i2c_dvs_enable) {
|
||||||
|
dev_info(pmic->dev, "Buck%d: I2C DVS Enabled !\n", i);
|
||||||
|
val &= ~BUCK1_STBY_DVS;
|
||||||
|
}
|
||||||
|
dev_info(pmic->dev, "Buck%d: DVS High-Low[%d - %d].\n", i, buck_dvs->voltage[0], buck_dvs->voltage[1]);
|
||||||
|
selector = regulator_map_voltage_iterate(pmic->rdev[i], buck_dvs->voltage[0], buck_dvs->voltage[0]);
|
||||||
|
if(selector < 0) {
|
||||||
|
dev_err(pmic->dev, "%s(): not found selector for voltage [%d]\n", __func__, buck_dvs->voltage[0]);
|
||||||
|
} else {
|
||||||
|
ret = bd7181x_reg_write(bd7181x, regh, val | (selector & BUCK1_H_MASK));
|
||||||
|
if(ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
selector = regulator_map_voltage_iterate(pmic->rdev[i], buck_dvs->voltage[1], buck_dvs->voltage[1]);
|
||||||
|
if(selector < 0) {
|
||||||
|
dev_err(pmic->dev, "%s(): not found selector for voltage [%d]\n", __func__, buck_dvs->voltage[1]);
|
||||||
|
} else {
|
||||||
|
ret = bd7181x_reg_write(bd7181x, regl, val | (selector & BUCK1_L_MASK));
|
||||||
|
if(ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**@brief probe bd7181x regulator device
|
||||||
|
@param pdev bd7181x regulator platform device
|
||||||
|
@retval 0 success
|
||||||
|
@retval negative fail
|
||||||
|
*/
|
||||||
|
static __init int bd7181x_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct bd7181x_pmic *pmic;
|
||||||
|
struct bd7181x_board *pdata;
|
||||||
|
struct regulator_config config = {};
|
||||||
|
struct bd7181x *bd7181x = dev_get_drvdata(pdev->dev.parent);
|
||||||
|
struct of_regulator_match *matches = NULL;
|
||||||
|
int i, err;
|
||||||
|
|
||||||
|
pmic = kzalloc(sizeof(*pmic), GFP_KERNEL);
|
||||||
|
if (!pmic) {
|
||||||
|
dev_err(&pdev->dev, "Memory allocation failed for pmic\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(pmic->descs, bd7181x_regulators, sizeof(pmic->descs));
|
||||||
|
|
||||||
|
pmic->dev = &pdev->dev;
|
||||||
|
pmic->mfd = bd7181x;
|
||||||
|
platform_set_drvdata(pdev, pmic);
|
||||||
|
|
||||||
|
bd7181x_clear_bits(pmic->mfd, BD7181X_REG_PWRCTRL, RESTARTEN); // Disable to go to ship-mode
|
||||||
|
bd7181x_clear_bits(pmic->mfd, BD7181X_REG_GPO, RESTARTEN); // Turn OFF the green LED
|
||||||
|
bd7181x_set_bits(pmic->mfd, BD7181X_REG_CHG_SET1, CHG_EN); // Enable charger
|
||||||
|
|
||||||
|
pdata = dev_get_platdata(bd7181x->dev);
|
||||||
|
if (!pdata && bd7181x->dev->of_node) {
|
||||||
|
bd7181x_parse_dt_reg_data(pdev, &matches);
|
||||||
|
if (matches == NULL) {
|
||||||
|
dev_err(&pdev->dev, "Platform data not found\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get buck dvs parameters */
|
||||||
|
of_bd7181x_buck_dvs(pdev, &pmic->buck_dvs[0]);
|
||||||
|
|
||||||
|
for (i = 0; i < BD7181X_REGULATOR_CNT; i++) {
|
||||||
|
struct regulator_init_data *init_data;
|
||||||
|
struct regulator_desc *desc;
|
||||||
|
struct regulator_dev *rdev;
|
||||||
|
|
||||||
|
desc = &pmic->descs[i].desc;
|
||||||
|
desc->name = bd7181x_matches[i].name;
|
||||||
|
|
||||||
|
if (pdata) {
|
||||||
|
init_data = pdata->init_data[i];
|
||||||
|
} else {
|
||||||
|
init_data = matches[i].init_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
config.dev = pmic->dev;
|
||||||
|
config.init_data = init_data;
|
||||||
|
config.driver_data = pmic;
|
||||||
|
config.regmap = bd7181x->regmap;
|
||||||
|
config.of_node = matches[i].of_node;
|
||||||
|
|
||||||
|
rdev = regulator_register(desc, &config);
|
||||||
|
if (IS_ERR(rdev)) {
|
||||||
|
dev_err(bd7181x->dev,
|
||||||
|
"failed to register %s regulator\n",
|
||||||
|
desc->name);
|
||||||
|
err = PTR_ERR(rdev);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
pmic->rdev[i] = rdev;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = sysfs_create_group(&pdev->dev.kobj, &gpo_attr_group);
|
||||||
|
if (err != 0) {
|
||||||
|
dev_err(&pdev->dev, "Failed to create attribute group: %d\n", err);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Init buck12 dvs */
|
||||||
|
err = bd7181x_buck12_dvs_init(pmic);
|
||||||
|
if (err != 0) {
|
||||||
|
dev_err(&pdev->dev, "Failed to buck12 dvs: %d\n", err);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err:
|
||||||
|
while (--i >= 0)
|
||||||
|
regulator_unregister(pmic->rdev[i]);
|
||||||
|
|
||||||
|
kfree(pmic);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**@brief remove bd7181x regulator device
|
||||||
|
@param pdev bd7181x regulator platform device
|
||||||
|
@return 0
|
||||||
|
*/
|
||||||
|
static int __exit bd7181x_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct bd7181x_pmic *pmic = platform_get_drvdata(pdev);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
sysfs_remove_group(&pdev->dev.kobj, &gpo_attr_group);
|
||||||
|
|
||||||
|
for (i = 0; i < BD7181X_REGULATOR_CNT; i++)
|
||||||
|
regulator_unregister(pmic->rdev[i]);
|
||||||
|
|
||||||
|
kfree(pmic);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver bd7181x_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "bd7181x-pmic",
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
},
|
||||||
|
.probe = bd7181x_probe,
|
||||||
|
.remove = bd7181x_remove,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**@brief module initialize function */
|
||||||
|
static int __init bd7181x_init(void)
|
||||||
|
{
|
||||||
|
return platform_driver_register(&bd7181x_driver);
|
||||||
|
}
|
||||||
|
subsys_initcall(bd7181x_init);
|
||||||
|
|
||||||
|
/**@brief module deinitialize function */
|
||||||
|
static void __exit bd7181x_cleanup(void)
|
||||||
|
{
|
||||||
|
platform_driver_unregister(&bd7181x_driver);
|
||||||
|
}
|
||||||
|
module_exit(bd7181x_cleanup);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Tony Luo <luofc@embedinfo.com>");
|
||||||
|
MODULE_DESCRIPTION("BD71815/BD71817 voltage regulator driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
|
MODULE_ALIAS("platform:bd7181x-pmic");
|
|
@ -631,6 +631,15 @@ config RTC_DRV_S5M
|
||||||
This driver can also be built as a module. If so, the module
|
This driver can also be built as a module. If so, the module
|
||||||
will be called rtc-s5m.
|
will be called rtc-s5m.
|
||||||
|
|
||||||
|
config RTC_DRV_BD7181X
|
||||||
|
tristate "BD71815/BD71817 RTC"
|
||||||
|
depends on RTC_CLASS && MFD_BD7181X
|
||||||
|
help
|
||||||
|
If you say yes here you get support for the RTC on the
|
||||||
|
RoHM BD71815/BD71817 chips.
|
||||||
|
|
||||||
|
This driver can also be built as a module.
|
||||||
|
|
||||||
endif # I2C
|
endif # I2C
|
||||||
|
|
||||||
comment "SPI RTC drivers"
|
comment "SPI RTC drivers"
|
||||||
|
|
|
@ -37,6 +37,7 @@ obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
|
||||||
obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
|
obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
|
||||||
obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
|
obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
|
||||||
obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o
|
obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o
|
||||||
|
obj-$(CONFIG_RTC_DRV_BD7181X) += rtc-bd7181x.o
|
||||||
obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o
|
obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o
|
||||||
obj-$(CONFIG_RTC_DRV_BRCMSTB) += rtc-brcmstb-waketimer.o
|
obj-$(CONFIG_RTC_DRV_BRCMSTB) += rtc-brcmstb-waketimer.o
|
||||||
obj-$(CONFIG_RTC_DRV_BQ32K) += rtc-bq32k.o
|
obj-$(CONFIG_RTC_DRV_BQ32K) += rtc-bq32k.o
|
||||||
|
|
|
@ -0,0 +1,417 @@
|
||||||
|
/*
|
||||||
|
* @file RoHM BD71815/BD71817 Real Time Clock interface
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Embest Technology Co. Ltd. Inc.
|
||||||
|
*
|
||||||
|
* @author Peter Yang <yanglsh@embest-tech.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.
|
||||||
|
*/
|
||||||
|
#define DEBUG
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/rtc.h>
|
||||||
|
#include <linux/bcd.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/mfd/bd7181x.h>
|
||||||
|
|
||||||
|
/** @brief bd7181x rtc struct */
|
||||||
|
struct bd7181x_rtc {
|
||||||
|
struct rtc_device *rtc; /**< system rtc device */
|
||||||
|
int irq; /**< rtc irq */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* @brief Total number of RTC registers needed to set time*/
|
||||||
|
// #define NUM_TIME_REGS (BD7181X_REG_YEAR - BD7181X_REG_SEC + 1)
|
||||||
|
|
||||||
|
/**@brief enable or disable rtc alarm irq
|
||||||
|
* @param dev rtc device of system
|
||||||
|
* @param enabled enable if non-zero
|
||||||
|
* @retval 0 success
|
||||||
|
* @retval negative error number
|
||||||
|
*/
|
||||||
|
static int bd7181x_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
|
||||||
|
{
|
||||||
|
struct bd7181x *mfd = dev_get_drvdata(dev->parent);
|
||||||
|
u8 val = 0;
|
||||||
|
|
||||||
|
if (enabled)
|
||||||
|
val = ALM0;
|
||||||
|
|
||||||
|
return regmap_write(mfd->regmap, BD7181X_REG_INT_EN_12, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**@brief bd7181x rtc time convert to linux time
|
||||||
|
* @param tm linux rtc time
|
||||||
|
* @param hw_rtc bd7181x rtc time
|
||||||
|
* @return argument tm
|
||||||
|
*/
|
||||||
|
static struct rtc_time* hw_to_rtc_time(struct rtc_time* tm, const struct bd7181x_rtc_alarm* hw_rtc) {
|
||||||
|
u8 hour;
|
||||||
|
|
||||||
|
tm->tm_sec = bcd2bin(hw_rtc->sec);
|
||||||
|
tm->tm_min = bcd2bin(hw_rtc->min);
|
||||||
|
hour = hw_rtc->hour & ~HOUR_24HOUR;
|
||||||
|
tm->tm_hour = bcd2bin(hour);
|
||||||
|
tm->tm_mday = bcd2bin(hw_rtc->day);
|
||||||
|
tm->tm_mon = bcd2bin(hw_rtc->month) - 1;
|
||||||
|
tm->tm_year = bcd2bin(hw_rtc->year) + 100;
|
||||||
|
return tm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**@brief linux time convert bd7181x rtc time
|
||||||
|
* @param hw_rtc bd7181x rtc time
|
||||||
|
* @param tm linux rtc time
|
||||||
|
* @return argument hw_rtc
|
||||||
|
*/
|
||||||
|
static struct bd7181x_rtc_alarm* rtc_time_to_hw(struct bd7181x_rtc_alarm* hw_rtc, const struct rtc_time* tm) {
|
||||||
|
hw_rtc->sec = bin2bcd(tm->tm_sec);
|
||||||
|
hw_rtc->min = bin2bcd(tm->tm_min);
|
||||||
|
hw_rtc->hour = HOUR_24HOUR | bin2bcd(tm->tm_hour);
|
||||||
|
hw_rtc->day = bin2bcd(tm->tm_mday);
|
||||||
|
hw_rtc->month = bin2bcd(tm->tm_mon + 1);
|
||||||
|
hw_rtc->year = bin2bcd(tm->tm_year - 100);
|
||||||
|
|
||||||
|
return hw_rtc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gets current bd7181x RTC time and date parameters.
|
||||||
|
*
|
||||||
|
* The RTC's time/alarm representation is not what gmtime(3) requires
|
||||||
|
* Linux to use:
|
||||||
|
*
|
||||||
|
* - Months are 1..12 vs Linux 0-11
|
||||||
|
* - Years are 0..99 vs Linux 1900..N (we assume 21st century)
|
||||||
|
*/
|
||||||
|
/**@brief read date/time from bd7181x rtc
|
||||||
|
* @param dev rtc device of system
|
||||||
|
* @param tm date/time store target
|
||||||
|
* @retval 0 success
|
||||||
|
* @retval negative error number
|
||||||
|
*/
|
||||||
|
static int bd7181x_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||||
|
{
|
||||||
|
struct bd7181x_rtc_alarm rtc_data[1];
|
||||||
|
struct bd7181x *mfd = dev_get_drvdata(dev->parent);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = regmap_bulk_read(mfd->regmap, BD7181X_REG_SEC, rtc_data, sizeof rtc_data);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(dev, "reading from RTC failed with err:%d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
hw_to_rtc_time(tm, rtc_data);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**@brief write date/time to bd7181x rtc
|
||||||
|
* @param dev rtc device of system
|
||||||
|
* @param tm date/time source
|
||||||
|
* @retval 0 success
|
||||||
|
* @retval negative error number
|
||||||
|
*/
|
||||||
|
static int bd7181x_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||||
|
{
|
||||||
|
struct bd7181x_rtc_alarm rtc_data[1];
|
||||||
|
struct bd7181x *mfd = dev_get_drvdata(dev->parent);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
rtc_time_to_hw(rtc_data, tm);
|
||||||
|
|
||||||
|
/* update all the time registers in one shot */
|
||||||
|
ret = regmap_bulk_write(mfd->regmap, BD7181X_REG_SEC, rtc_data, sizeof rtc_data);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(dev, "rtc_set_time error %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**@brief Gets current bd7181x RTC alarm time.
|
||||||
|
* @param dev rtc device of system
|
||||||
|
* @param alm alarm date/time store target
|
||||||
|
* @retval 0 success
|
||||||
|
* @retval negative error number
|
||||||
|
*/
|
||||||
|
static int bd7181x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||||
|
{
|
||||||
|
struct bd7181x_rtc_alarm rtc_data[1];
|
||||||
|
u32 int_val;
|
||||||
|
struct bd7181x *mfd = dev_get_drvdata(dev->parent);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = regmap_bulk_read(mfd->regmap, BD7181X_REG_ALM0_SEC, rtc_data, sizeof rtc_data);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(dev, "rtc_read_alarm error %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
hw_to_rtc_time(&alm->time, rtc_data);
|
||||||
|
|
||||||
|
ret = regmap_read(mfd->regmap, BD7181X_REG_INT_EN_12, &int_val);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (int_val & ALM0)
|
||||||
|
alm->enabled = 1;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**@brief Set current bd7181x RTC alarm time
|
||||||
|
* @param dev rtc device of system
|
||||||
|
* @param alm alarm date/time to set
|
||||||
|
* @retval 0 success
|
||||||
|
* @retval negative error number
|
||||||
|
*/
|
||||||
|
static int bd7181x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||||
|
{
|
||||||
|
struct bd7181x_rtc_alarm rtc_data[1];
|
||||||
|
struct bd7181x *mfd = dev_get_drvdata(dev->parent);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
// printk("%s() L%d\n", __func__, __LINE__);
|
||||||
|
|
||||||
|
ret = bd7181x_rtc_alarm_irq_enable(dev, 0);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
rtc_time_to_hw(rtc_data, &alm->time);
|
||||||
|
|
||||||
|
/* update all the alarm registers in one shot */
|
||||||
|
ret = regmap_bulk_write(mfd->regmap, BD7181X_REG_ALM0_SEC, rtc_data, sizeof rtc_data);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "rtc_set_alarm error %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alm->enabled)
|
||||||
|
ret = bd7181x_rtc_alarm_irq_enable(dev, 1);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**@brief bd7181x rtc alarm interrupt
|
||||||
|
* @param irq system irq
|
||||||
|
* @param rtc rtc device of system
|
||||||
|
* @retval IRQ_HANDLED success
|
||||||
|
* @retval IRQ_NONE error
|
||||||
|
*/
|
||||||
|
static irqreturn_t bd7181x_rtc_interrupt(int irq, void *rtc)
|
||||||
|
{
|
||||||
|
struct device *dev = rtc;
|
||||||
|
unsigned long events = 0;
|
||||||
|
struct bd7181x *mfd = dev_get_drvdata(dev->parent);
|
||||||
|
struct bd7181x_rtc *bd_rtc = dev_get_drvdata(dev);
|
||||||
|
int ret;
|
||||||
|
u32 rtc_reg;
|
||||||
|
|
||||||
|
dev_info(mfd->dev, "bd7181x_rtc_interrupt() in.\n");
|
||||||
|
|
||||||
|
ret = regmap_read(mfd->regmap, BD7181X_REG_INT_STAT_12, &rtc_reg);
|
||||||
|
if (ret)
|
||||||
|
return IRQ_NONE;
|
||||||
|
|
||||||
|
dev_info(mfd->dev, "BD7181X_REG_INT_STAT_12=0x%x\n", rtc_reg);
|
||||||
|
|
||||||
|
if (rtc_reg & ALM0)
|
||||||
|
events = RTC_IRQF | RTC_AF;
|
||||||
|
|
||||||
|
ret = regmap_write(mfd->regmap, BD7181X_REG_INT_STAT_12, rtc_reg);
|
||||||
|
if (ret)
|
||||||
|
return IRQ_NONE;
|
||||||
|
|
||||||
|
dev_info(mfd->dev, "\n~~~IRQ ALARM.\n");
|
||||||
|
|
||||||
|
/* Notify RTC core on event */
|
||||||
|
rtc_update_irq(bd_rtc->rtc, 1, events);
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief function operations definition */
|
||||||
|
static struct rtc_class_ops bd7181x_rtc_ops = {
|
||||||
|
.read_time = bd7181x_rtc_read_time,
|
||||||
|
.set_time = bd7181x_rtc_set_time,
|
||||||
|
.read_alarm = bd7181x_rtc_read_alarm,
|
||||||
|
.set_alarm = bd7181x_rtc_set_alarm,
|
||||||
|
.alarm_irq_enable = bd7181x_rtc_alarm_irq_enable,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**@brief probe bd7181x rtc device
|
||||||
|
@param pdev bd7181x rtc platform device
|
||||||
|
@retval 0 success
|
||||||
|
@retval negative fail
|
||||||
|
*/
|
||||||
|
static int bd7181x_rtc_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct bd7181x *bd7181x = NULL;
|
||||||
|
struct bd7181x_rtc *bd_rtc = NULL;
|
||||||
|
int ret;
|
||||||
|
int irq;
|
||||||
|
u32 rtc_reg;
|
||||||
|
|
||||||
|
bd7181x = dev_get_drvdata(pdev->dev.parent);
|
||||||
|
|
||||||
|
bd_rtc = devm_kzalloc(&pdev->dev, sizeof(struct bd7181x_rtc),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!bd_rtc)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* Clear pending interrupts */
|
||||||
|
ret = regmap_read(bd7181x->regmap, BD7181X_REG_INT_STAT_12, &rtc_reg);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = regmap_write(bd7181x->regmap, BD7181X_REG_INT_STAT_12, rtc_reg);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
dev_dbg(&pdev->dev, "Enabling rtc-bd7181x.\n");
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* Enable RTC alarm interrupt */
|
||||||
|
ret = regmap_update_bits(bd7181x->regmap, BD7181X_REG_INT_EN_00, ALMALE, ALMALE);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
#endif
|
||||||
|
/* Enable ALM0_EN mask */
|
||||||
|
ret = regmap_write(bd7181x->regmap, BD7181X_REG_ALM0_MASK, ALM0);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
irq = platform_get_irq(pdev, 0);
|
||||||
|
if (irq <= 0) {
|
||||||
|
dev_warn(&pdev->dev, "Wake up is not possible as irq = %d\n", irq);
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
|
||||||
|
bd7181x_rtc_interrupt, IRQF_TRIGGER_LOW | IRQF_EARLY_RESUME,
|
||||||
|
dev_name(&pdev->dev), &pdev->dev);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(&pdev->dev, "IRQ is not free.\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
bd_rtc->irq = irq;
|
||||||
|
device_set_wakeup_capable(&pdev->dev, 1);
|
||||||
|
|
||||||
|
bd_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
|
||||||
|
&bd7181x_rtc_ops, THIS_MODULE);
|
||||||
|
if (IS_ERR(bd_rtc->rtc)) {
|
||||||
|
ret = PTR_ERR(bd_rtc->rtc);
|
||||||
|
dev_err(&pdev->dev, "RTC device register: err %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, bd_rtc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable bd7181x RTC interrupts.
|
||||||
|
* Sets status flag to free.
|
||||||
|
*/
|
||||||
|
/**@brief remove bd7181x rtc device
|
||||||
|
@param pdev bd7181x rtc platform device
|
||||||
|
@return 0
|
||||||
|
*/
|
||||||
|
static int bd7181x_rtc_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
bd7181x_rtc_alarm_irq_enable(&pdev->dev, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**@brief shutdown bd7181x rtc device
|
||||||
|
@param pdev bd7181x rtc platform device
|
||||||
|
@return void
|
||||||
|
*/
|
||||||
|
static void bd7181x_rtc_shutdown(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
/* mask timer interrupts, but leave alarm interrupts on to enable
|
||||||
|
power-on when alarm is triggered */
|
||||||
|
bd7181x_rtc_alarm_irq_enable(&pdev->dev, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
/**@brief suspend bd7181x rtc device
|
||||||
|
* @param dev rtc device of system
|
||||||
|
* @retval 0
|
||||||
|
*/
|
||||||
|
static int bd7181x_rtc_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct bd7181x_rtc *bd_rtc = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (device_may_wakeup(dev))
|
||||||
|
enable_irq_wake(bd_rtc->irq);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**@brief resume bd7181x rtc device
|
||||||
|
* @param dev rtc device of system
|
||||||
|
* @retval 0
|
||||||
|
*/
|
||||||
|
static int bd7181x_rtc_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct bd7181x_rtc *bd_rtc = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (device_may_wakeup(dev))
|
||||||
|
disable_irq_wake(bd_rtc->irq);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static SIMPLE_DEV_PM_OPS(bd7181x_rtc_pm_ops, bd7181x_rtc_suspend, bd7181x_rtc_resume);
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF
|
||||||
|
static const struct of_device_id bd7181x_rtc_of_match[] = {
|
||||||
|
{.compatible = "ti,bd7181x-rtc", },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, bd7181x_rtc_of_match);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static struct platform_driver bd7181xrtc_driver = {
|
||||||
|
.probe = bd7181x_rtc_probe,
|
||||||
|
.remove = bd7181x_rtc_remove,
|
||||||
|
.shutdown = bd7181x_rtc_shutdown,
|
||||||
|
.driver = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.name = "bd7181x-rtc",
|
||||||
|
.pm = &bd7181x_rtc_pm_ops,
|
||||||
|
.of_match_table = of_match_ptr(bd7181x_rtc_of_match),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**@brief module initialize function */
|
||||||
|
static int __init bd7181x_rtc_init(void)
|
||||||
|
{
|
||||||
|
return platform_driver_register(&bd7181xrtc_driver);
|
||||||
|
}
|
||||||
|
module_init(bd7181x_rtc_init);
|
||||||
|
|
||||||
|
/**@brief module deinitialize function */
|
||||||
|
static void __exit bd7181x_rtc_exit(void)
|
||||||
|
{
|
||||||
|
platform_driver_unregister(&bd7181xrtc_driver);
|
||||||
|
}
|
||||||
|
module_exit(bd7181x_rtc_exit);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Peter Yang <yanglsh@embest-tech.com>");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
|
MODULE_ALIAS("platform:bd7181x-rtc");
|
|
@ -0,0 +1,601 @@
|
||||||
|
/**
|
||||||
|
* @file bd7181x.h ROHM BD71815GW/BD71817GW header file
|
||||||
|
*
|
||||||
|
* Copyright 2014 Embest Technology Co. Ltd. Inc.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @author yanglsh@embest-tech.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LINUX_MFD_BD7181X_H
|
||||||
|
#define __LINUX_MFD_BD7181X_H
|
||||||
|
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
|
||||||
|
// LDO5VSEL_EQ_H
|
||||||
|
// define to 1 when LDO5VSEL connect to High
|
||||||
|
// define to 0 when LDO5VSEL connect to Low
|
||||||
|
#define LDO5VSEL_EQ_H 1
|
||||||
|
|
||||||
|
#ifndef LDO5VSEL_EQ_H
|
||||||
|
#error define LDO5VSEL_EQ_H to 1 when connect to High, to 0 when connect to Low
|
||||||
|
#else
|
||||||
|
#if LDO5VSEL_EQ_H == 1
|
||||||
|
#define BD7181X_REG_LDO5_VOLT BD7181X_REG_LDO5_VOLT_H
|
||||||
|
#elif LDO5VSEL_EQ_H == 0
|
||||||
|
#define BD7181X_REG_LDO5_VOLT BD7181X_REG_LDO5_VOLT_L
|
||||||
|
#else
|
||||||
|
#error Define LDO5VSEL_EQ_H only to 0 or 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum {
|
||||||
|
BD7181X_BUCK1 = 0,
|
||||||
|
BD7181X_BUCK2,
|
||||||
|
BD7181X_BUCK3,
|
||||||
|
BD7181X_BUCK4,
|
||||||
|
BD7181X_BUCK5,
|
||||||
|
// General Purpose
|
||||||
|
BD7181X_LDO1,
|
||||||
|
BD7181X_LDO2,
|
||||||
|
BD7181X_LDO3,
|
||||||
|
// LDOs for SD Card and SD Card Interface
|
||||||
|
BD7181X_LDO4,
|
||||||
|
BD7181X_LDO5,
|
||||||
|
// LDO for DDR Reference Voltage
|
||||||
|
BD7181X_LDODVREF,
|
||||||
|
// LDO for Secure Non-Volatile Storage
|
||||||
|
// BD7181X_LDOSNVS,
|
||||||
|
// LDO for Low-Power State Retention
|
||||||
|
BD7181X_LDOLPSR,
|
||||||
|
BD7181X_WLED,
|
||||||
|
BD7181X_REGULATOR_CNT,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BD7181X_SUPPLY_STATE_ENABLED 0x1
|
||||||
|
|
||||||
|
enum {
|
||||||
|
BD7181X_REG_DEVICE = 0,
|
||||||
|
BD7181X_REG_PWRCTRL,
|
||||||
|
BD7181X_REG_BUCK1_MODE,
|
||||||
|
BD7181X_REG_BUCK2_MODE,
|
||||||
|
BD7181X_REG_BUCK3_MODE,
|
||||||
|
BD7181X_REG_BUCK4_MODE,
|
||||||
|
BD7181X_REG_BUCK5_MODE,
|
||||||
|
BD7181X_REG_BUCK1_VOLT_H,
|
||||||
|
// 0x08
|
||||||
|
BD7181X_REG_BUCK1_VOLT_L,
|
||||||
|
BD7181X_REG_BUCK2_VOLT_H,
|
||||||
|
BD7181X_REG_BUCK2_VOLT_L,
|
||||||
|
BD7181X_REG_BUCK3_VOLT,
|
||||||
|
BD7181X_REG_BUCK4_VOLT,
|
||||||
|
BD7181X_REG_BUCK5_VOLT,
|
||||||
|
BD7181X_REG_LED_CTRL,
|
||||||
|
BD7181X_REG_LED_DIMM,
|
||||||
|
// 0x10
|
||||||
|
BD7181X_REG_LDO_MODE1,
|
||||||
|
BD7181X_REG_LDO_MODE2,
|
||||||
|
BD7181X_REG_LDO_MODE3,
|
||||||
|
BD7181X_REG_LDO_MODE4,
|
||||||
|
BD7181X_REG_LDO1_VOLT,
|
||||||
|
BD7181X_REG_LDO2_VOLT,
|
||||||
|
BD7181X_REG_LDO3_VOLT,
|
||||||
|
BD7181X_REG_LDO4_VOLT,
|
||||||
|
// 0x18
|
||||||
|
BD7181X_REG_LDO5_VOLT_H,
|
||||||
|
BD7181X_REG_LDO5_VOLT_L,
|
||||||
|
BD7181X_REG_BUCK_PD_DIS,
|
||||||
|
BD7181X_REG_LDO_PD_DIS,
|
||||||
|
BD7181X_REG_GPO,
|
||||||
|
BD7181X_REG_OUT32K,
|
||||||
|
BD7181X_REG_SEC,
|
||||||
|
BD7181X_REG_MIN,
|
||||||
|
// 0x20
|
||||||
|
BD7181X_REG_HOUR,
|
||||||
|
BD7181X_REG_WEEK,
|
||||||
|
BD7181X_REG_DAY,
|
||||||
|
BD7181X_REG_MONTH,
|
||||||
|
BD7181X_REG_YEAR,
|
||||||
|
BD7181X_REG_ALM0_SEC,
|
||||||
|
|
||||||
|
// 0x2C
|
||||||
|
BD7181X_REG_ALM1_SEC = 0x2C,
|
||||||
|
|
||||||
|
// 0x33
|
||||||
|
BD7181X_REG_ALM0_MASK = 0x33,
|
||||||
|
BD7181X_REG_ALM1_MASK,
|
||||||
|
BD7181X_REG_ALM2,
|
||||||
|
BD7181X_REG_TRIM,
|
||||||
|
BD7181X_REG_CONF,
|
||||||
|
// 0x38
|
||||||
|
BD7181X_REG_SYS_INIT,
|
||||||
|
BD7181X_REG_CHG_STATE,
|
||||||
|
BD7181X_REG_CHG_LAST_STATE,
|
||||||
|
BD7181X_REG_BAT_STAT,
|
||||||
|
BD7181X_REG_DCIN_STAT,
|
||||||
|
BD7181X_REG_VSYS_STAT,
|
||||||
|
BD7181X_REG_CHG_STAT,
|
||||||
|
BD7181X_REG_CHG_WDT_STAT,
|
||||||
|
// 0x40
|
||||||
|
BD7181X_REG_BAT_TEMP,
|
||||||
|
BD7181X_REG_IGNORE_0,
|
||||||
|
BD7181X_REG_INHIBIT_0,
|
||||||
|
BD7181X_REG_DCIN_CLPS,
|
||||||
|
BD7181X_REG_VSYS_REG,
|
||||||
|
BD7181X_REG_VSYS_MAX,
|
||||||
|
BD7181X_REG_VSYS_MIN,
|
||||||
|
BD7181X_REG_CHG_SET1,
|
||||||
|
// 0x48
|
||||||
|
BD7181X_REG_CHG_SET2,
|
||||||
|
BD7181X_REG_CHG_WDT_PRE,
|
||||||
|
BD7181X_REG_CHG_WDT_FST,
|
||||||
|
BD7181X_REG_CHG_IPRE,
|
||||||
|
BD7181X_REG_CHG_IFST,
|
||||||
|
BD7181X_REG_CHG_IFST_TERM,
|
||||||
|
BD7181X_REG_CHG_VPRE,
|
||||||
|
BD7181X_REG_CHG_VBAT_1,
|
||||||
|
// 0x50
|
||||||
|
BD7181X_REG_CHG_VBAT_2,
|
||||||
|
BD7181X_REG_CHG_VBAT_3,
|
||||||
|
BD7181X_REG_CHG_LED_1,
|
||||||
|
BD7181X_REG_VF_TH,
|
||||||
|
BD7181X_REG_BAT_SET_1,
|
||||||
|
BD7181X_REG_BAT_SET_2,
|
||||||
|
BD7181X_REG_BAT_SET_3,
|
||||||
|
BD7181X_REG_ALM_VBAT_TH_U,
|
||||||
|
// 0x58
|
||||||
|
BD7181X_REG_ALM_VBAT_TH_L,
|
||||||
|
BD7181X_REG_ALM_DCIN_TH,
|
||||||
|
BD7181X_REG_ALM_VSYS_TH,
|
||||||
|
BD7181X_REG_VM_IBAT_U,
|
||||||
|
BD7181X_REG_VM_IBAT_L,
|
||||||
|
BD7181X_REG_VM_VBAT_U,
|
||||||
|
BD7181X_REG_VM_VBAT_L,
|
||||||
|
BD7181X_REG_VM_BTMP,
|
||||||
|
// 0x60
|
||||||
|
BD7181X_REG_VM_VTH,
|
||||||
|
BD7181X_REG_VM_DCIN_U,
|
||||||
|
BD7181X_REG_VM_DCIN_L,
|
||||||
|
BD7181X_REG_VM_VSYS,
|
||||||
|
BD7181X_REG_VM_VF,
|
||||||
|
BD7181X_REG_VM_OCI_PRE_U,
|
||||||
|
BD7181X_REG_VM_OCI_PRE_L,
|
||||||
|
BD7181X_REG_VM_OCV_PRE_U,
|
||||||
|
// 0x68
|
||||||
|
BD7181X_REG_VM_OCV_PRE_L,
|
||||||
|
BD7181X_REG_VM_OCI_PST_U,
|
||||||
|
BD7181X_REG_VM_OCI_PST_L,
|
||||||
|
BD7181X_REG_VM_OCV_PST_U,
|
||||||
|
BD7181X_REG_VM_OCV_PST_L,
|
||||||
|
BD7181X_REG_VM_SA_VBAT_U,
|
||||||
|
BD7181X_REG_VM_SA_VBAT_L,
|
||||||
|
BD7181X_REG_VM_SA_IBAT_U,
|
||||||
|
// 0x70
|
||||||
|
BD7181X_REG_VM_SA_IBAT_L,
|
||||||
|
BD7181X_REG_CC_CTRL,
|
||||||
|
BD7181X_REG_CC_BATCAP1_TH_U,
|
||||||
|
BD7181X_REG_CC_BATCAP1_TH_L,
|
||||||
|
BD7181X_REG_CC_BATCAP2_TH_U,
|
||||||
|
BD7181X_REG_CC_BATCAP2_TH_L,
|
||||||
|
BD7181X_REG_CC_BATCAP3_TH_U,
|
||||||
|
BD7181X_REG_CC_BATCAP3_TH_L,
|
||||||
|
// 0x78
|
||||||
|
BD7181X_REG_CC_STAT,
|
||||||
|
BD7181X_REG_CC_CCNTD_3,
|
||||||
|
BD7181X_REG_CC_CCNTD_2,
|
||||||
|
BD7181X_REG_CC_CCNTD_1,
|
||||||
|
BD7181X_REG_CC_CCNTD_0,
|
||||||
|
BD7181X_REG_CC_CURCD_U,
|
||||||
|
BD7181X_REG_CC_CURCD_L,
|
||||||
|
BD7181X_REG_VM_OCUR_THR_1,
|
||||||
|
// 0x80
|
||||||
|
BD7181X_REG_VM_OCUR_DUR_1,
|
||||||
|
BD7181X_REG_VM_OCUR_THR_2,
|
||||||
|
BD7181X_REG_VM_OCUR_DUR_2,
|
||||||
|
BD7181X_REG_VM_OCUR_THR_3,
|
||||||
|
BD7181X_REG_VM_OCUR_DUR_3,
|
||||||
|
BD7181X_REG_VM_OCUR_MON,
|
||||||
|
BD7181X_REG_VM_BTMP_OV_THR,
|
||||||
|
BD7181X_REG_VM_BTMP_OV_DUR,
|
||||||
|
// 0x88
|
||||||
|
BD7181X_REG_VM_BTMP_LO_THR,
|
||||||
|
BD7181X_REG_VM_BTMP_LO_DUR,
|
||||||
|
BD7181X_REG_VM_BTMP_MON,
|
||||||
|
BD7181X_REG_INT_EN_01,
|
||||||
|
// 0x95
|
||||||
|
BD7181X_REG_INT_EN_11 = 0x95,
|
||||||
|
// 0x96
|
||||||
|
BD7181X_REG_INT_EN_12 = 0x96,
|
||||||
|
BD7181X_REG_INT_STAT,
|
||||||
|
|
||||||
|
// 0x98
|
||||||
|
BD7181X_REG_INT_STAT_01,
|
||||||
|
BD7181X_REG_INT_STAT_02,
|
||||||
|
BD7181X_REG_INT_STAT_03,
|
||||||
|
BD7181X_REG_INT_STAT_04,
|
||||||
|
BD7181X_REG_INT_STAT_05,
|
||||||
|
BD7181X_REG_INT_STAT_06,
|
||||||
|
BD7181X_REG_INT_STAT_07,
|
||||||
|
BD7181X_REG_INT_STAT_08,
|
||||||
|
|
||||||
|
// 0xA0
|
||||||
|
BD7181X_REG_INT_STAT_09,
|
||||||
|
BD7181X_REG_INT_STAT_10,
|
||||||
|
BD7181X_REG_INT_STAT_11,
|
||||||
|
BD7181X_REG_INT_STAT_12,
|
||||||
|
BD7181X_REG_INT_UPDATE,
|
||||||
|
|
||||||
|
// 0xC0
|
||||||
|
BD7181X_REG_VM_VSYS_U = 0xC0,
|
||||||
|
BD7181X_REG_VM_VSYS_L,
|
||||||
|
BD7181X_REG_VM_SA_VSYS_U,
|
||||||
|
BD7181X_REG_VM_SA_VSYS_L,
|
||||||
|
|
||||||
|
// 0xD0
|
||||||
|
BD7181X_REG_VM_SA_IBAT_MIN_U = 0xD0,
|
||||||
|
BD7181X_REG_VM_SA_IBAT_MIN_L,
|
||||||
|
BD7181X_REG_VM_SA_IBAT_MAX_U,
|
||||||
|
BD7181X_REG_VM_SA_IBAT_MAX_L,
|
||||||
|
BD7181X_REG_VM_SA_VBAT_MIN_U,
|
||||||
|
BD7181X_REG_VM_SA_VBAT_MIN_L,
|
||||||
|
BD7181X_REG_VM_SA_VBAT_MAX_U,
|
||||||
|
BD7181X_REG_VM_SA_VBAT_MAX_L,
|
||||||
|
BD7181X_REG_VM_SA_VSYS_MIN_U,
|
||||||
|
BD7181X_REG_VM_SA_VSYS_MIN_L,
|
||||||
|
BD7181X_REG_VM_SA_VSYS_MAX_U,
|
||||||
|
BD7181X_REG_VM_SA_VSYS_MAX_L,
|
||||||
|
BD7181X_REG_VM_SA_MINMAX_CLR,
|
||||||
|
|
||||||
|
// 0xE0
|
||||||
|
BD7181X_REG_REX_CCNTD_3 = 0xE0,
|
||||||
|
BD7181X_REG_REX_CCNTD_2,
|
||||||
|
BD7181X_REG_REX_CCNTD_1,
|
||||||
|
BD7181X_REG_REX_CCNTD_0,
|
||||||
|
BD7181X_REG_REX_SA_VBAT_U,
|
||||||
|
BD7181X_REG_REX_SA_VBAT_L,
|
||||||
|
BD7181X_REG_REX_CTRL_1,
|
||||||
|
BD7181X_REG_REX_CTRL_2,
|
||||||
|
BD7181X_REG_FULL_CCNTD_3,
|
||||||
|
BD7181X_REG_FULL_CCNTD_2,
|
||||||
|
BD7181X_REG_FULL_CCNTD_1,
|
||||||
|
BD7181X_REG_FULL_CCNTD_0,
|
||||||
|
BD7181X_REG_FULL_CTRL,
|
||||||
|
|
||||||
|
// 0xF0
|
||||||
|
BD7181X_REG_CCNTD_CHG_3 = 0xF0,
|
||||||
|
BD7181X_REG_CCNTD_CHG_2,
|
||||||
|
|
||||||
|
// 0xFE
|
||||||
|
BD7181X_REG_TEST_MODE = 0xFE,
|
||||||
|
BD7181X_MAX_REGISTER,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* BD7181X_REG_BUCK1_MODE bits */
|
||||||
|
#define BUCK1_RAMPRATE_MASK 0xC0
|
||||||
|
#define BUCK1_RAMPRATE_10P00MV 0x0
|
||||||
|
#define BUCK1_RAMPRATE_5P00MV 0x1
|
||||||
|
#define BUCK1_RAMPRATE_2P50MV 0x2
|
||||||
|
#define BUCK1_RAMPRATE_1P25MV 0x3
|
||||||
|
|
||||||
|
/* BD7181X_REG_BUCK1_VOLT_H bits */
|
||||||
|
#define BUCK1_DVSSEL 0x80
|
||||||
|
#define BUCK1_STBY_DVS 0x40
|
||||||
|
#define BUCK1_H_MASK 0x3F
|
||||||
|
#define BUCK1_H_DEFAULT 0x14
|
||||||
|
|
||||||
|
/* BD7181X_REG_BUCK1_VOLT_L bits */
|
||||||
|
#define BUCK1_L_MASK 0x3F
|
||||||
|
#define BUCK1_L_DEFAULT 0x14
|
||||||
|
|
||||||
|
/* BD7181X_REG_BUCK2_VOLT_H bits */
|
||||||
|
#define BUCK2_DVSSEL 0x80
|
||||||
|
#define BUCK2_STBY_DVS 0x40
|
||||||
|
#define BUCK2_H_MASK 0x3F
|
||||||
|
#define BUCK2_H_DEFAULT 0x14
|
||||||
|
|
||||||
|
/* BD7181X_REG_BUCK2_VOLT_L bits */
|
||||||
|
#define BUCK2_L_MASK 0x3F
|
||||||
|
#define BUCK2_L_DEFAULT 0x14
|
||||||
|
|
||||||
|
/* BD7181X_REG_LDO1_CTRL bits */
|
||||||
|
#define LDO1_EN 0x01
|
||||||
|
#define LDO2_EN 0x02
|
||||||
|
#define LDO3_EN 0x04
|
||||||
|
#define DVREF_EN 0x08
|
||||||
|
#define VOSNVS_SW_EN 0x10
|
||||||
|
#define VOLT_MASK 0x3F
|
||||||
|
|
||||||
|
/* BD7181X_REG_OUT32K bits */
|
||||||
|
#define OUT32K_EN 0x01
|
||||||
|
#define OUT32K_MODE 0x02
|
||||||
|
|
||||||
|
/* BD7181X_REG_BAT_STAT bits */
|
||||||
|
#define BAT_DET 0x20
|
||||||
|
#define BAT_DET_OFFSET 5
|
||||||
|
#define BAT_DET_DONE 0x10
|
||||||
|
#define VBAT_OV 0x08
|
||||||
|
#define DBAT_DET 0x01
|
||||||
|
|
||||||
|
/* BD7181X_REG_VBUS_STAT bits */
|
||||||
|
#define VBUS_DET 0x01
|
||||||
|
|
||||||
|
#define BUCK1_RAMPRATE_10MV_US 0x0
|
||||||
|
#define BUCK1_RAMPRATE_5MV_US 0x1
|
||||||
|
#define BUCK1_RAMPRATE_2P5MV_US 0x2
|
||||||
|
#define BUCK1_RAMPRATE_1P25MV_US 0x3a
|
||||||
|
|
||||||
|
/* BD7181X_REG_ALM0_MASK bits */
|
||||||
|
#define A0_ONESEC 0x80
|
||||||
|
|
||||||
|
/* BD7181X_REG_INT_EN_00 bits */
|
||||||
|
#define ALMALE 0x1
|
||||||
|
|
||||||
|
/* BD7181X_REG_INT_STAT_03 bits */
|
||||||
|
#define DCIN_MON_DET 0x02
|
||||||
|
#define DCIN_MON_RES 0x01
|
||||||
|
#define POWERON_LONG 0x04
|
||||||
|
#define POWERON_MID 0x08
|
||||||
|
#define POWERON_SHORT 0x10
|
||||||
|
#define POWERON_PRESS 0x20
|
||||||
|
|
||||||
|
|
||||||
|
/* BD71805_REG_INT_STAT_08 bits */
|
||||||
|
#define VBAT_MON_DET 0x02
|
||||||
|
#define VBAT_MON_RES 0x01
|
||||||
|
|
||||||
|
/* BD71805_REG_INT_STAT_11 bits */
|
||||||
|
#define INT_STAT_11_VF_DET 0x80
|
||||||
|
#define INT_STAT_11_VF_RES 0x40
|
||||||
|
#define INT_STAT_11_VF125_DET 0x20
|
||||||
|
#define INT_STAT_11_VF125_RES 0x10
|
||||||
|
#define INT_STAT_11_OVTMP_DET 0x08
|
||||||
|
#define INT_STAT_11_OVTMP_RES 0x04
|
||||||
|
#define INT_STAT_11_LOTMP_DET 0x02
|
||||||
|
#define INT_STAT_11_LOTMP_RES 0x01
|
||||||
|
|
||||||
|
#define VBAT_MON_DET 0x02
|
||||||
|
#define VBAT_MON_RES 0x01
|
||||||
|
|
||||||
|
/* BD7181X_REG_PWRCTRL bits */
|
||||||
|
#define RESTARTEN 0x01
|
||||||
|
|
||||||
|
/* BD7181X_REG_GPO bits */
|
||||||
|
#define READY_FORCE_LOW 0x04
|
||||||
|
|
||||||
|
/* BD7181X_REG_CHG_SET1 bits */
|
||||||
|
#define CHG_EN 0x01
|
||||||
|
|
||||||
|
/* BD7181X interrupt masks */
|
||||||
|
enum {
|
||||||
|
BD7181X_INT_EN_01_BUCKAST_MASK = 0x0F,
|
||||||
|
BD7181X_INT_EN_02_DCINAST_MASK = 0x3E,
|
||||||
|
BD7181X_INT_EN_03_DCINAST_MASK = 0x3F,
|
||||||
|
BD7181X_INT_EN_04_VSYSAST_MASK = 0xCF,
|
||||||
|
BD7181X_INT_EN_05_CHGAST_MASK = 0xFC,
|
||||||
|
BD7181X_INT_EN_06_BATAST_MASK = 0xF3,
|
||||||
|
BD7181X_INT_EN_07_BMONAST_MASK = 0xFE,
|
||||||
|
BD7181X_INT_EN_08_BMONAST_MASK = 0x03,
|
||||||
|
BD7181X_INT_EN_09_BMONAST_MASK = 0x07,
|
||||||
|
BD7181X_INT_EN_10_BMONAST_MASK = 0x3F,
|
||||||
|
BD7181X_INT_EN_11_TMPAST_MASK = 0xFF,
|
||||||
|
BD7181X_INT_EN_12_ALMAST_MASK = 0x07,
|
||||||
|
};
|
||||||
|
/* BD7181X interrupt irqs */
|
||||||
|
enum {
|
||||||
|
BD7181X_IRQ_BUCK_01 = 0x0,
|
||||||
|
BD7181X_IRQ_DCIN_02,
|
||||||
|
BD7181X_IRQ_DCIN_03,
|
||||||
|
BD7181X_IRQ_VSYS_04,
|
||||||
|
BD7181X_IRQ_CHARGE_05,
|
||||||
|
BD7181X_IRQ_BAT_06,
|
||||||
|
BD7181X_IRQ_BAT_MON_07,
|
||||||
|
BD7181X_IRQ_BAT_MON_08,
|
||||||
|
BD7181X_IRQ_BAT_MON_09,
|
||||||
|
BD7181X_IRQ_BAT_MON_10,
|
||||||
|
BD7181X_IRQ_TEMPERATURE_11,
|
||||||
|
BD7181X_IRQ_ALARM_12,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* BD7181X_REG_INT_EN_12 bits */
|
||||||
|
#define ALM0 0x1
|
||||||
|
|
||||||
|
/* BD7181X_REG_HOUR bits */
|
||||||
|
#define HOUR_24HOUR 0x80
|
||||||
|
|
||||||
|
/* BD7181X_REG_CC_CTRL bits */
|
||||||
|
#define CCNTRST 0x80
|
||||||
|
#define CCNTENB 0x40
|
||||||
|
#define CCCALIB 0x20
|
||||||
|
|
||||||
|
/* BD7181X_REG_CHG_SET1 bits */
|
||||||
|
#define WDT_AUTO 0x40
|
||||||
|
|
||||||
|
/* BD7181X_REG_CC_CURCD */
|
||||||
|
#define CURDIR_Discharging 0x8000
|
||||||
|
|
||||||
|
/* BD7181X_REG_VM_SA_IBAT */
|
||||||
|
#define IBAT_SA_DIR_Discharging 0x8000
|
||||||
|
|
||||||
|
/* BD7181X_REG_VM_SA_MINMAX_CLR bits */
|
||||||
|
#define VSYS_SA_MIN_CLR 0x10
|
||||||
|
#define VBAT_SA_MIN_CLR 0x01
|
||||||
|
|
||||||
|
/* BD7181X_REG_REX_CTRL_1 bits */
|
||||||
|
#define REX_CLR 0x10
|
||||||
|
|
||||||
|
/* BD7181X_REG_REX_CTRL_1 bits */
|
||||||
|
#define REX_PMU_STATE_MASK 0x04
|
||||||
|
|
||||||
|
/* BD7181X_REG_FULL_CTRL bits */
|
||||||
|
#define FULL_CLR 0x10
|
||||||
|
|
||||||
|
/* BD7181X_REG_LED_CTRL bits */
|
||||||
|
#define CHGDONE_LED_EN 0x10
|
||||||
|
|
||||||
|
/** @brief charge state enumuration */
|
||||||
|
enum CHG_STATE {
|
||||||
|
CHG_STATE_SUSPEND = 0x0, /**< suspend state */
|
||||||
|
CHG_STATE_TRICKLE_CHARGE, /**< trickle charge state */
|
||||||
|
CHG_STATE_PRE_CHARGE, /**< precharge state */
|
||||||
|
CHG_STATE_FAST_CHARGE, /**< fast charge state */
|
||||||
|
CHG_STATE_TOP_OFF, /**< top off state */
|
||||||
|
CHG_STATE_DONE, /**< charge complete */
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief rtc or alarm registers structure */
|
||||||
|
struct bd7181x_rtc_alarm {
|
||||||
|
u8 sec;
|
||||||
|
u8 min;
|
||||||
|
u8 hour;
|
||||||
|
u8 week;
|
||||||
|
u8 day;
|
||||||
|
u8 month;
|
||||||
|
u8 year;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bd7181x;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Board platform data may be used to initialize regulators.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct bd7181x_board {
|
||||||
|
struct regulator_init_data *init_data[BD7181X_REGULATOR_CNT];
|
||||||
|
/**< regulator initialize data */
|
||||||
|
int gpio_intr; /**< gpio connected to bd7181x INTB */
|
||||||
|
int irq_base; /**< bd7181x sub irqs base # */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief bd7181x sub-driver chip access routines
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct bd7181x {
|
||||||
|
struct device *dev;
|
||||||
|
struct i2c_client *i2c_client;
|
||||||
|
struct regmap *regmap;
|
||||||
|
struct mutex io_mutex;
|
||||||
|
unsigned int id;
|
||||||
|
|
||||||
|
/* IRQ Handling */
|
||||||
|
int chip_irq; /**< bd7181x irq to host cpu */
|
||||||
|
struct regmap_irq_chip_data *irq_data;
|
||||||
|
|
||||||
|
/* Client devices */
|
||||||
|
struct bd7181x_pmic *pmic; /**< client device regulator */
|
||||||
|
struct bd7181x_power *power; /**< client device battery */
|
||||||
|
|
||||||
|
struct bd7181x_board *of_plat_data;
|
||||||
|
/**< Device node parsed board data */
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline int bd7181x_chip_id(struct bd7181x *bd7181x)
|
||||||
|
{
|
||||||
|
return bd7181x->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief bd7181x_reg_read
|
||||||
|
* read single register's value of bd7181x
|
||||||
|
* @param bd7181x device to read
|
||||||
|
* @param reg register address
|
||||||
|
* @return register value if success
|
||||||
|
* error number if fail
|
||||||
|
*/
|
||||||
|
static inline int bd7181x_reg_read(struct bd7181x *bd7181x, u8 reg)
|
||||||
|
{
|
||||||
|
int r, val;
|
||||||
|
|
||||||
|
r = regmap_read(bd7181x->regmap, reg, &val);
|
||||||
|
if (r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief bd7181x_reg_write
|
||||||
|
* write single register of bd7181x
|
||||||
|
* @param bd7181x device to write
|
||||||
|
* @param reg register address
|
||||||
|
* @param val value to write
|
||||||
|
* @retval 0 if success
|
||||||
|
* @retval negative error number if fail
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline int bd7181x_reg_write(struct bd7181x *bd7181x, u8 reg,
|
||||||
|
unsigned int val)
|
||||||
|
{
|
||||||
|
return regmap_write(bd7181x->regmap, reg, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief bd7181x_set_bits
|
||||||
|
* set bits in one register of bd7181x
|
||||||
|
* @param bd7181x device to read
|
||||||
|
* @param reg register address
|
||||||
|
* @param mask mask bits
|
||||||
|
* @retval 0 if success
|
||||||
|
* @retval negative error number if fail
|
||||||
|
*/
|
||||||
|
static inline int bd7181x_set_bits(struct bd7181x *bd7181x, u8 reg,
|
||||||
|
u8 mask)
|
||||||
|
{
|
||||||
|
return regmap_update_bits(bd7181x->regmap, reg, mask, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief bd7181x_clear_bits
|
||||||
|
* clear bits in one register of bd7181x
|
||||||
|
* @param bd7181x device to read
|
||||||
|
* @param reg register address
|
||||||
|
* @param mask mask bits
|
||||||
|
* @retval 0 if success
|
||||||
|
* @retval negative error number if fail
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline int bd7181x_clear_bits(struct bd7181x *bd7181x, u8 reg,
|
||||||
|
u8 mask)
|
||||||
|
{
|
||||||
|
return regmap_update_bits(bd7181x->regmap, reg, mask, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief bd7181x_update_bits
|
||||||
|
* update bits in one register of bd7181x
|
||||||
|
* @param bd7181x device to read
|
||||||
|
* @param reg register address
|
||||||
|
* @param mask mask bits
|
||||||
|
* @param val value to update
|
||||||
|
* @retval 0 if success
|
||||||
|
* @retval negative error number if fail
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline int bd7181x_update_bits(struct bd7181x *bd7181x, u8 reg,
|
||||||
|
u8 mask, u8 val)
|
||||||
|
{
|
||||||
|
return regmap_update_bits(bd7181x->regmap, reg, mask, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief bd7181x platform data type
|
||||||
|
*/
|
||||||
|
struct bd7181x_gpo_plat_data {
|
||||||
|
u32 mode; ///< gpo output mode
|
||||||
|
int gpio_base; ///< base gpio number in system
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BD7181X_DBG0 0x0001
|
||||||
|
#define BD7181X_DBG1 0x0002
|
||||||
|
#define BD7181X_DBG2 0x0004
|
||||||
|
#define BD7181X_DBG3 0x0008
|
||||||
|
|
||||||
|
extern unsigned int bd7181x_debug_mask;
|
||||||
|
#define bd7181x_debug(debug, fmt, arg...) do { if(debug & bd7181x_debug_mask) printk("BD7181x:" fmt, ##arg);} while(0)
|
||||||
|
|
||||||
|
#endif /* __LINUX_MFD_BD7181X_H */
|
Loading…
Reference in New Issue