mfd: Add support for RICOH PMIC RC5T583
Ricoh power management IC RC5T583 contains is multi functional device having multiple sub devices inside this. This device has multiple dcdc/ldo regulators, gpios, interrupt controllers, on-key, RTCs, ADCs. This device have 4 DCDCs, 8 LDOs, 8 GPIOs, 6 ADCs, 3 RTCs etc. Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
parent
bc628fd19d
commit
1b1247dd75
5 changed files with 1104 additions and 0 deletions
|
@ -846,6 +846,20 @@ config MFD_INTEL_MSIC
|
|||
Passage) chip. This chip embeds audio, battery, GPIO, etc.
|
||||
devices used in Intel Medfield platforms.
|
||||
|
||||
config MFD_RC5T583
|
||||
bool "Ricoh RC5T583 Power Management system device"
|
||||
depends on I2C && GENERIC_HARDIRQS
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Select this option to get support for the RICOH583 Power
|
||||
Management system device.
|
||||
This driver provides common support for accessing the device
|
||||
through i2c interface. The device supports multiple sub-devices
|
||||
like GPIO, interrupts, RTC, LDO and DCDC regulators, onkey.
|
||||
Additional drivers must be enabled in order to use the
|
||||
different functionality of the device.
|
||||
|
||||
endmenu
|
||||
endif
|
||||
|
||||
|
|
|
@ -112,4 +112,5 @@ obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o
|
|||
obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
|
||||
obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
|
||||
obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o
|
||||
obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
|
||||
obj-$(CONFIG_MFD_S5M_CORE) += s5m-core.o s5m-irq.o
|
||||
|
|
408
drivers/mfd/rc5t583-irq.c
Normal file
408
drivers/mfd/rc5t583-irq.c
Normal file
|
@ -0,0 +1,408 @@
|
|||
/*
|
||||
* Interrupt driver for RICOH583 power management chip.
|
||||
*
|
||||
* Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved.
|
||||
* Author: Laxman dewangan <ldewangan@nvidia.com>
|
||||
*
|
||||
* based on code
|
||||
* Copyright (C) 2011 RICOH COMPANY,LTD
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mfd/rc5t583.h>
|
||||
|
||||
enum int_type {
|
||||
SYS_INT = 0x1,
|
||||
DCDC_INT = 0x2,
|
||||
RTC_INT = 0x4,
|
||||
ADC_INT = 0x8,
|
||||
GPIO_INT = 0x10,
|
||||
};
|
||||
|
||||
static int gpedge_add[] = {
|
||||
RC5T583_GPIO_GPEDGE2,
|
||||
RC5T583_GPIO_GPEDGE2
|
||||
};
|
||||
|
||||
static int irq_en_add[] = {
|
||||
RC5T583_INT_EN_SYS1,
|
||||
RC5T583_INT_EN_SYS2,
|
||||
RC5T583_INT_EN_DCDC,
|
||||
RC5T583_INT_EN_RTC,
|
||||
RC5T583_INT_EN_ADC1,
|
||||
RC5T583_INT_EN_ADC2,
|
||||
RC5T583_INT_EN_ADC3,
|
||||
RC5T583_GPIO_EN_INT
|
||||
};
|
||||
|
||||
static int irq_mon_add[] = {
|
||||
RC5T583_INT_MON_SYS1,
|
||||
RC5T583_INT_MON_SYS2,
|
||||
RC5T583_INT_MON_DCDC,
|
||||
RC5T583_INT_MON_RTC,
|
||||
RC5T583_INT_IR_ADCL,
|
||||
RC5T583_INT_IR_ADCH,
|
||||
RC5T583_INT_IR_ADCEND,
|
||||
RC5T583_INT_IR_GPIOF,
|
||||
RC5T583_INT_IR_GPIOR
|
||||
};
|
||||
|
||||
static int irq_clr_add[] = {
|
||||
RC5T583_INT_IR_SYS1,
|
||||
RC5T583_INT_IR_SYS2,
|
||||
RC5T583_INT_IR_DCDC,
|
||||
RC5T583_INT_IR_RTC,
|
||||
RC5T583_INT_IR_ADCL,
|
||||
RC5T583_INT_IR_ADCH,
|
||||
RC5T583_INT_IR_ADCEND,
|
||||
RC5T583_INT_IR_GPIOF,
|
||||
RC5T583_INT_IR_GPIOR
|
||||
};
|
||||
|
||||
static int main_int_type[] = {
|
||||
SYS_INT,
|
||||
SYS_INT,
|
||||
DCDC_INT,
|
||||
RTC_INT,
|
||||
ADC_INT,
|
||||
ADC_INT,
|
||||
ADC_INT,
|
||||
GPIO_INT,
|
||||
GPIO_INT,
|
||||
};
|
||||
|
||||
struct rc5t583_irq_data {
|
||||
u8 int_type;
|
||||
u8 master_bit;
|
||||
u8 int_en_bit;
|
||||
u8 mask_reg_index;
|
||||
int grp_index;
|
||||
};
|
||||
|
||||
#define RC5T583_IRQ(_int_type, _master_bit, _grp_index, \
|
||||
_int_bit, _mask_ind) \
|
||||
{ \
|
||||
.int_type = _int_type, \
|
||||
.master_bit = _master_bit, \
|
||||
.grp_index = _grp_index, \
|
||||
.int_en_bit = _int_bit, \
|
||||
.mask_reg_index = _mask_ind, \
|
||||
}
|
||||
|
||||
static const struct rc5t583_irq_data rc5t583_irqs[RC5T583_MAX_IRQS] = {
|
||||
[RC5T583_IRQ_ONKEY] = RC5T583_IRQ(SYS_INT, 0, 0, 0, 0),
|
||||
[RC5T583_IRQ_ACOK] = RC5T583_IRQ(SYS_INT, 0, 1, 1, 0),
|
||||
[RC5T583_IRQ_LIDOPEN] = RC5T583_IRQ(SYS_INT, 0, 2, 2, 0),
|
||||
[RC5T583_IRQ_PREOT] = RC5T583_IRQ(SYS_INT, 0, 3, 3, 0),
|
||||
[RC5T583_IRQ_CLKSTP] = RC5T583_IRQ(SYS_INT, 0, 4, 4, 0),
|
||||
[RC5T583_IRQ_ONKEY_OFF] = RC5T583_IRQ(SYS_INT, 0, 5, 5, 0),
|
||||
[RC5T583_IRQ_WD] = RC5T583_IRQ(SYS_INT, 0, 7, 7, 0),
|
||||
[RC5T583_IRQ_EN_PWRREQ1] = RC5T583_IRQ(SYS_INT, 0, 8, 0, 1),
|
||||
[RC5T583_IRQ_EN_PWRREQ2] = RC5T583_IRQ(SYS_INT, 0, 9, 1, 1),
|
||||
[RC5T583_IRQ_PRE_VINDET] = RC5T583_IRQ(SYS_INT, 0, 10, 2, 1),
|
||||
|
||||
[RC5T583_IRQ_DC0LIM] = RC5T583_IRQ(DCDC_INT, 1, 0, 0, 2),
|
||||
[RC5T583_IRQ_DC1LIM] = RC5T583_IRQ(DCDC_INT, 1, 1, 1, 2),
|
||||
[RC5T583_IRQ_DC2LIM] = RC5T583_IRQ(DCDC_INT, 1, 2, 2, 2),
|
||||
[RC5T583_IRQ_DC3LIM] = RC5T583_IRQ(DCDC_INT, 1, 3, 3, 2),
|
||||
|
||||
[RC5T583_IRQ_CTC] = RC5T583_IRQ(RTC_INT, 2, 0, 0, 3),
|
||||
[RC5T583_IRQ_YALE] = RC5T583_IRQ(RTC_INT, 2, 5, 5, 3),
|
||||
[RC5T583_IRQ_DALE] = RC5T583_IRQ(RTC_INT, 2, 6, 6, 3),
|
||||
[RC5T583_IRQ_WALE] = RC5T583_IRQ(RTC_INT, 2, 7, 7, 3),
|
||||
|
||||
[RC5T583_IRQ_AIN1L] = RC5T583_IRQ(ADC_INT, 3, 0, 0, 4),
|
||||
[RC5T583_IRQ_AIN2L] = RC5T583_IRQ(ADC_INT, 3, 1, 1, 4),
|
||||
[RC5T583_IRQ_AIN3L] = RC5T583_IRQ(ADC_INT, 3, 2, 2, 4),
|
||||
[RC5T583_IRQ_VBATL] = RC5T583_IRQ(ADC_INT, 3, 3, 3, 4),
|
||||
[RC5T583_IRQ_VIN3L] = RC5T583_IRQ(ADC_INT, 3, 4, 4, 4),
|
||||
[RC5T583_IRQ_VIN8L] = RC5T583_IRQ(ADC_INT, 3, 5, 5, 4),
|
||||
[RC5T583_IRQ_AIN1H] = RC5T583_IRQ(ADC_INT, 3, 6, 0, 5),
|
||||
[RC5T583_IRQ_AIN2H] = RC5T583_IRQ(ADC_INT, 3, 7, 1, 5),
|
||||
[RC5T583_IRQ_AIN3H] = RC5T583_IRQ(ADC_INT, 3, 8, 2, 5),
|
||||
[RC5T583_IRQ_VBATH] = RC5T583_IRQ(ADC_INT, 3, 9, 3, 5),
|
||||
[RC5T583_IRQ_VIN3H] = RC5T583_IRQ(ADC_INT, 3, 10, 4, 5),
|
||||
[RC5T583_IRQ_VIN8H] = RC5T583_IRQ(ADC_INT, 3, 11, 5, 5),
|
||||
[RC5T583_IRQ_ADCEND] = RC5T583_IRQ(ADC_INT, 3, 12, 0, 6),
|
||||
|
||||
[RC5T583_IRQ_GPIO0] = RC5T583_IRQ(GPIO_INT, 4, 0, 0, 7),
|
||||
[RC5T583_IRQ_GPIO1] = RC5T583_IRQ(GPIO_INT, 4, 1, 1, 7),
|
||||
[RC5T583_IRQ_GPIO2] = RC5T583_IRQ(GPIO_INT, 4, 2, 2, 7),
|
||||
[RC5T583_IRQ_GPIO3] = RC5T583_IRQ(GPIO_INT, 4, 3, 3, 7),
|
||||
[RC5T583_IRQ_GPIO4] = RC5T583_IRQ(GPIO_INT, 4, 4, 4, 7),
|
||||
[RC5T583_IRQ_GPIO5] = RC5T583_IRQ(GPIO_INT, 4, 5, 5, 7),
|
||||
[RC5T583_IRQ_GPIO6] = RC5T583_IRQ(GPIO_INT, 4, 6, 6, 7),
|
||||
[RC5T583_IRQ_GPIO7] = RC5T583_IRQ(GPIO_INT, 4, 7, 7, 7),
|
||||
};
|
||||
|
||||
static void rc5t583_irq_lock(struct irq_data *irq_data)
|
||||
{
|
||||
struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
|
||||
mutex_lock(&rc5t583->irq_lock);
|
||||
}
|
||||
|
||||
static void rc5t583_irq_unmask(struct irq_data *irq_data)
|
||||
{
|
||||
struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
|
||||
unsigned int __irq = irq_data->irq - rc5t583->irq_base;
|
||||
const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
|
||||
|
||||
rc5t583->group_irq_en[data->grp_index] |= 1 << data->grp_index;
|
||||
rc5t583->intc_inten_reg |= 1 << data->master_bit;
|
||||
rc5t583->irq_en_reg[data->mask_reg_index] |= 1 << data->int_en_bit;
|
||||
}
|
||||
|
||||
static void rc5t583_irq_mask(struct irq_data *irq_data)
|
||||
{
|
||||
struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
|
||||
unsigned int __irq = irq_data->irq - rc5t583->irq_base;
|
||||
const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
|
||||
|
||||
rc5t583->group_irq_en[data->grp_index] &= ~(1 << data->grp_index);
|
||||
if (!rc5t583->group_irq_en[data->grp_index])
|
||||
rc5t583->intc_inten_reg &= ~(1 << data->master_bit);
|
||||
|
||||
rc5t583->irq_en_reg[data->mask_reg_index] &= ~(1 << data->int_en_bit);
|
||||
}
|
||||
|
||||
static int rc5t583_irq_set_type(struct irq_data *irq_data, unsigned int type)
|
||||
{
|
||||
struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
|
||||
unsigned int __irq = irq_data->irq - rc5t583->irq_base;
|
||||
const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
|
||||
int val = 0;
|
||||
int gpedge_index;
|
||||
int gpedge_bit_pos;
|
||||
|
||||
/* Supporting only trigger level inetrrupt */
|
||||
if ((data->int_type & GPIO_INT) && (type & IRQ_TYPE_EDGE_BOTH)) {
|
||||
gpedge_index = data->int_en_bit / 4;
|
||||
gpedge_bit_pos = data->int_en_bit % 4;
|
||||
|
||||
if (type & IRQ_TYPE_EDGE_FALLING)
|
||||
val |= 0x2;
|
||||
|
||||
if (type & IRQ_TYPE_EDGE_RISING)
|
||||
val |= 0x1;
|
||||
|
||||
rc5t583->gpedge_reg[gpedge_index] &= ~(3 << gpedge_bit_pos);
|
||||
rc5t583->gpedge_reg[gpedge_index] |= (val << gpedge_bit_pos);
|
||||
rc5t583_irq_unmask(irq_data);
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void rc5t583_irq_sync_unlock(struct irq_data *irq_data)
|
||||
{
|
||||
struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(rc5t583->gpedge_reg); i++) {
|
||||
ret = rc5t583_write(rc5t583->dev, gpedge_add[i],
|
||||
rc5t583->gpedge_reg[i]);
|
||||
if (ret < 0)
|
||||
dev_warn(rc5t583->dev,
|
||||
"Error in writing reg 0x%02x error: %d\n",
|
||||
gpedge_add[i], ret);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(rc5t583->irq_en_reg); i++) {
|
||||
ret = rc5t583_write(rc5t583->dev, irq_en_add[i],
|
||||
rc5t583->irq_en_reg[i]);
|
||||
if (ret < 0)
|
||||
dev_warn(rc5t583->dev,
|
||||
"Error in writing reg 0x%02x error: %d\n",
|
||||
irq_en_add[i], ret);
|
||||
}
|
||||
|
||||
ret = rc5t583_write(rc5t583->dev, RC5T583_INTC_INTEN,
|
||||
rc5t583->intc_inten_reg);
|
||||
if (ret < 0)
|
||||
dev_warn(rc5t583->dev,
|
||||
"Error in writing reg 0x%02x error: %d\n",
|
||||
RC5T583_INTC_INTEN, ret);
|
||||
|
||||
mutex_unlock(&rc5t583->irq_lock);
|
||||
}
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int rc5t583_irq_set_wake(struct irq_data *irq_data, unsigned int on)
|
||||
{
|
||||
struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
|
||||
return irq_set_irq_wake(rc5t583->chip_irq, on);
|
||||
}
|
||||
#else
|
||||
#define rc5t583_irq_set_wake NULL
|
||||
#endif
|
||||
|
||||
static irqreturn_t rc5t583_irq(int irq, void *data)
|
||||
{
|
||||
struct rc5t583 *rc5t583 = data;
|
||||
uint8_t int_sts[RC5T583_MAX_INTERRUPT_MASK_REGS];
|
||||
uint8_t master_int;
|
||||
int i;
|
||||
int ret;
|
||||
unsigned int rtc_int_sts = 0;
|
||||
|
||||
/* Clear the status */
|
||||
for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; i++)
|
||||
int_sts[i] = 0;
|
||||
|
||||
ret = rc5t583_read(rc5t583->dev, RC5T583_INTC_INTMON, &master_int);
|
||||
if (ret < 0) {
|
||||
dev_err(rc5t583->dev,
|
||||
"Error in reading reg 0x%02x error: %d\n",
|
||||
RC5T583_INTC_INTMON, ret);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; ++i) {
|
||||
if (!(master_int & main_int_type[i]))
|
||||
continue;
|
||||
|
||||
ret = rc5t583_read(rc5t583->dev, irq_mon_add[i], &int_sts[i]);
|
||||
if (ret < 0) {
|
||||
dev_warn(rc5t583->dev,
|
||||
"Error in reading reg 0x%02x error: %d\n",
|
||||
irq_mon_add[i], ret);
|
||||
int_sts[i] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (main_int_type[i] & RTC_INT) {
|
||||
rtc_int_sts = 0;
|
||||
if (int_sts[i] & 0x1)
|
||||
rtc_int_sts |= BIT(6);
|
||||
if (int_sts[i] & 0x2)
|
||||
rtc_int_sts |= BIT(7);
|
||||
if (int_sts[i] & 0x4)
|
||||
rtc_int_sts |= BIT(0);
|
||||
if (int_sts[i] & 0x8)
|
||||
rtc_int_sts |= BIT(5);
|
||||
}
|
||||
|
||||
ret = rc5t583_write(rc5t583->dev, irq_clr_add[i],
|
||||
~int_sts[i]);
|
||||
if (ret < 0)
|
||||
dev_warn(rc5t583->dev,
|
||||
"Error in reading reg 0x%02x error: %d\n",
|
||||
irq_clr_add[i], ret);
|
||||
|
||||
if (main_int_type[i] & RTC_INT)
|
||||
int_sts[i] = rtc_int_sts;
|
||||
}
|
||||
|
||||
/* Merge gpio interrupts for rising and falling case*/
|
||||
int_sts[7] |= int_sts[8];
|
||||
|
||||
/* Call interrupt handler if enabled */
|
||||
for (i = 0; i < RC5T583_MAX_IRQS; ++i) {
|
||||
const struct rc5t583_irq_data *data = &rc5t583_irqs[i];
|
||||
if ((int_sts[data->mask_reg_index] & (1 << data->int_en_bit)) &&
|
||||
(rc5t583->group_irq_en[data->master_bit] &
|
||||
(1 << data->grp_index)))
|
||||
handle_nested_irq(rc5t583->irq_base + i);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct irq_chip rc5t583_irq_chip = {
|
||||
.name = "rc5t583-irq",
|
||||
.irq_mask = rc5t583_irq_mask,
|
||||
.irq_unmask = rc5t583_irq_unmask,
|
||||
.irq_bus_lock = rc5t583_irq_lock,
|
||||
.irq_bus_sync_unlock = rc5t583_irq_sync_unlock,
|
||||
.irq_set_type = rc5t583_irq_set_type,
|
||||
.irq_set_wake = rc5t583_irq_set_wake,
|
||||
};
|
||||
|
||||
int rc5t583_irq_init(struct rc5t583 *rc5t583, int irq, int irq_base)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
if (!irq_base) {
|
||||
dev_warn(rc5t583->dev, "No interrupt support on IRQ base\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_init(&rc5t583->irq_lock);
|
||||
|
||||
/* Initailize all int register to 0 */
|
||||
for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; i++) {
|
||||
ret = rc5t583_write(rc5t583->dev, irq_en_add[i],
|
||||
rc5t583->irq_en_reg[i]);
|
||||
if (ret < 0)
|
||||
dev_warn(rc5t583->dev,
|
||||
"Error in writing reg 0x%02x error: %d\n",
|
||||
irq_en_add[i], ret);
|
||||
}
|
||||
|
||||
for (i = 0; i < RC5T583_MAX_GPEDGE_REG; i++) {
|
||||
ret = rc5t583_write(rc5t583->dev, gpedge_add[i],
|
||||
rc5t583->gpedge_reg[i]);
|
||||
if (ret < 0)
|
||||
dev_warn(rc5t583->dev,
|
||||
"Error in writing reg 0x%02x error: %d\n",
|
||||
gpedge_add[i], ret);
|
||||
}
|
||||
|
||||
ret = rc5t583_write(rc5t583->dev, RC5T583_INTC_INTEN, 0x0);
|
||||
if (ret < 0)
|
||||
dev_warn(rc5t583->dev,
|
||||
"Error in writing reg 0x%02x error: %d\n",
|
||||
RC5T583_INTC_INTEN, ret);
|
||||
|
||||
/* Clear all interrupts in case they woke up active. */
|
||||
for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; i++) {
|
||||
ret = rc5t583_write(rc5t583->dev, irq_clr_add[i], 0);
|
||||
if (ret < 0)
|
||||
dev_warn(rc5t583->dev,
|
||||
"Error in writing reg 0x%02x error: %d\n",
|
||||
irq_clr_add[i], ret);
|
||||
}
|
||||
|
||||
rc5t583->irq_base = irq_base;
|
||||
rc5t583->chip_irq = irq;
|
||||
|
||||
for (i = 0; i < RC5T583_MAX_IRQS; i++) {
|
||||
int __irq = i + rc5t583->irq_base;
|
||||
irq_set_chip_data(__irq, rc5t583);
|
||||
irq_set_chip_and_handler(__irq, &rc5t583_irq_chip,
|
||||
handle_simple_irq);
|
||||
irq_set_nested_thread(__irq, 1);
|
||||
#ifdef CONFIG_ARM
|
||||
set_irq_flags(__irq, IRQF_VALID);
|
||||
#endif
|
||||
}
|
||||
|
||||
ret = request_threaded_irq(irq, NULL, rc5t583_irq, IRQF_ONESHOT,
|
||||
"rc5t583", rc5t583);
|
||||
if (ret < 0)
|
||||
dev_err(rc5t583->dev,
|
||||
"Error in registering interrupt error: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rc5t583_irq_exit(struct rc5t583 *rc5t583)
|
||||
{
|
||||
if (rc5t583->chip_irq)
|
||||
free_irq(rc5t583->chip_irq, rc5t583);
|
||||
return 0;
|
||||
}
|
386
drivers/mfd/rc5t583.c
Normal file
386
drivers/mfd/rc5t583.c
Normal file
|
@ -0,0 +1,386 @@
|
|||
/*
|
||||
* Core driver access RC5T583 power management chip.
|
||||
*
|
||||
* Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved.
|
||||
* Author: Laxman dewangan <ldewangan@nvidia.com>
|
||||
*
|
||||
* Based on code
|
||||
* Copyright (C) 2011 RICOH COMPANY,LTD
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/rc5t583.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define RICOH_ONOFFSEL_REG 0x10
|
||||
#define RICOH_SWCTL_REG 0x5E
|
||||
|
||||
struct deepsleep_control_data {
|
||||
u8 reg_add;
|
||||
u8 ds_pos_bit;
|
||||
};
|
||||
|
||||
#define DEEPSLEEP_INIT(_id, _reg, _pos) \
|
||||
{ \
|
||||
.reg_add = RC5T583_##_reg, \
|
||||
.ds_pos_bit = _pos, \
|
||||
}
|
||||
|
||||
static struct deepsleep_control_data deepsleep_data[] = {
|
||||
DEEPSLEEP_INIT(DC0, SLPSEQ1, 0),
|
||||
DEEPSLEEP_INIT(DC1, SLPSEQ1, 4),
|
||||
DEEPSLEEP_INIT(DC2, SLPSEQ2, 0),
|
||||
DEEPSLEEP_INIT(DC3, SLPSEQ2, 4),
|
||||
DEEPSLEEP_INIT(LDO0, SLPSEQ3, 0),
|
||||
DEEPSLEEP_INIT(LDO1, SLPSEQ3, 4),
|
||||
DEEPSLEEP_INIT(LDO2, SLPSEQ4, 0),
|
||||
DEEPSLEEP_INIT(LDO3, SLPSEQ4, 4),
|
||||
DEEPSLEEP_INIT(LDO4, SLPSEQ5, 0),
|
||||
DEEPSLEEP_INIT(LDO5, SLPSEQ5, 4),
|
||||
DEEPSLEEP_INIT(LDO6, SLPSEQ6, 0),
|
||||
DEEPSLEEP_INIT(LDO7, SLPSEQ6, 4),
|
||||
DEEPSLEEP_INIT(LDO8, SLPSEQ7, 0),
|
||||
DEEPSLEEP_INIT(LDO9, SLPSEQ7, 4),
|
||||
DEEPSLEEP_INIT(PSO0, SLPSEQ8, 0),
|
||||
DEEPSLEEP_INIT(PSO1, SLPSEQ8, 4),
|
||||
DEEPSLEEP_INIT(PSO2, SLPSEQ9, 0),
|
||||
DEEPSLEEP_INIT(PSO3, SLPSEQ9, 4),
|
||||
DEEPSLEEP_INIT(PSO4, SLPSEQ10, 0),
|
||||
DEEPSLEEP_INIT(PSO5, SLPSEQ10, 4),
|
||||
DEEPSLEEP_INIT(PSO6, SLPSEQ11, 0),
|
||||
DEEPSLEEP_INIT(PSO7, SLPSEQ11, 4),
|
||||
};
|
||||
|
||||
#define EXT_PWR_REQ \
|
||||
(RC5T583_EXT_PWRREQ1_CONTROL | RC5T583_EXT_PWRREQ2_CONTROL)
|
||||
|
||||
static struct mfd_cell rc5t583_subdevs[] = {
|
||||
{.name = "rc5t583-regulator",},
|
||||
{.name = "rc5t583-rtc", },
|
||||
{.name = "rc5t583-key", }
|
||||
};
|
||||
|
||||
int rc5t583_write(struct device *dev, uint8_t reg, uint8_t val)
|
||||
{
|
||||
struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
|
||||
return regmap_write(rc5t583->regmap, reg, val);
|
||||
}
|
||||
|
||||
int rc5t583_read(struct device *dev, uint8_t reg, uint8_t *val)
|
||||
{
|
||||
struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
|
||||
unsigned int ival;
|
||||
int ret;
|
||||
ret = regmap_read(rc5t583->regmap, reg, &ival);
|
||||
if (!ret)
|
||||
*val = (uint8_t)ival;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rc5t583_set_bits(struct device *dev, unsigned int reg,
|
||||
unsigned int bit_mask)
|
||||
{
|
||||
struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
|
||||
return regmap_update_bits(rc5t583->regmap, reg, bit_mask, bit_mask);
|
||||
}
|
||||
|
||||
int rc5t583_clear_bits(struct device *dev, unsigned int reg,
|
||||
unsigned int bit_mask)
|
||||
{
|
||||
struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
|
||||
return regmap_update_bits(rc5t583->regmap, reg, bit_mask, 0);
|
||||
}
|
||||
|
||||
int rc5t583_update(struct device *dev, unsigned int reg,
|
||||
unsigned int val, unsigned int mask)
|
||||
{
|
||||
struct rc5t583 *rc5t583 = dev_get_drvdata(dev);
|
||||
return regmap_update_bits(rc5t583->regmap, reg, mask, val);
|
||||
}
|
||||
|
||||
static int __rc5t583_set_ext_pwrreq1_control(struct device *dev,
|
||||
int id, int ext_pwr, int slots)
|
||||
{
|
||||
int ret;
|
||||
uint8_t sleepseq_val;
|
||||
unsigned int en_bit;
|
||||
unsigned int slot_bit;
|
||||
|
||||
if (id == RC5T583_DS_DC0) {
|
||||
dev_err(dev, "PWRREQ1 is invalid control for rail %d\n", id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
en_bit = deepsleep_data[id].ds_pos_bit;
|
||||
slot_bit = en_bit + 1;
|
||||
ret = rc5t583_read(dev, deepsleep_data[id].reg_add, &sleepseq_val);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Error in reading reg 0x%x\n",
|
||||
deepsleep_data[id].reg_add);
|
||||
return ret;
|
||||
}
|
||||
|
||||
sleepseq_val &= ~(0xF << en_bit);
|
||||
sleepseq_val |= BIT(en_bit);
|
||||
sleepseq_val |= ((slots & 0x7) << slot_bit);
|
||||
ret = rc5t583_set_bits(dev, RICOH_ONOFFSEL_REG, BIT(1));
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Error in updating the 0x%02x register\n",
|
||||
RICOH_ONOFFSEL_REG);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = rc5t583_write(dev, deepsleep_data[id].reg_add, sleepseq_val);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Error in writing reg 0x%x\n",
|
||||
deepsleep_data[id].reg_add);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (id == RC5T583_DS_LDO4) {
|
||||
ret = rc5t583_write(dev, RICOH_SWCTL_REG, 0x1);
|
||||
if (ret < 0)
|
||||
dev_err(dev, "Error in writing reg 0x%x\n",
|
||||
RICOH_SWCTL_REG);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __rc5t583_set_ext_pwrreq2_control(struct device *dev,
|
||||
int id, int ext_pwr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (id != RC5T583_DS_DC0) {
|
||||
dev_err(dev, "PWRREQ2 is invalid control for rail %d\n", id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = rc5t583_set_bits(dev, RICOH_ONOFFSEL_REG, BIT(2));
|
||||
if (ret < 0)
|
||||
dev_err(dev, "Error in updating the ONOFFSEL 0x10 register\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rc5t583_ext_power_req_config(struct device *dev, int ds_id,
|
||||
int ext_pwr_req, int deepsleep_slot_nr)
|
||||
{
|
||||
if ((ext_pwr_req & EXT_PWR_REQ) == EXT_PWR_REQ)
|
||||
return -EINVAL;
|
||||
|
||||
if (ext_pwr_req & RC5T583_EXT_PWRREQ1_CONTROL)
|
||||
return __rc5t583_set_ext_pwrreq1_control(dev, ds_id,
|
||||
ext_pwr_req, deepsleep_slot_nr);
|
||||
|
||||
if (ext_pwr_req & RC5T583_EXT_PWRREQ2_CONTROL)
|
||||
return __rc5t583_set_ext_pwrreq2_control(dev,
|
||||
ds_id, ext_pwr_req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rc5t583_clear_ext_power_req(struct rc5t583 *rc5t583,
|
||||
struct rc5t583_platform_data *pdata)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
uint8_t on_off_val = 0;
|
||||
|
||||
/* Clear ONOFFSEL register */
|
||||
if (pdata->enable_shutdown)
|
||||
on_off_val = 0x1;
|
||||
|
||||
ret = rc5t583_write(rc5t583->dev, RICOH_ONOFFSEL_REG, on_off_val);
|
||||
if (ret < 0)
|
||||
dev_warn(rc5t583->dev, "Error in writing reg %d error: %d\n",
|
||||
RICOH_ONOFFSEL_REG, ret);
|
||||
|
||||
ret = rc5t583_write(rc5t583->dev, RICOH_SWCTL_REG, 0x0);
|
||||
if (ret < 0)
|
||||
dev_warn(rc5t583->dev, "Error in writing reg %d error: %d\n",
|
||||
RICOH_SWCTL_REG, ret);
|
||||
|
||||
/* Clear sleep sequence register */
|
||||
for (i = RC5T583_SLPSEQ1; i <= RC5T583_SLPSEQ11; ++i) {
|
||||
ret = rc5t583_write(rc5t583->dev, i, 0x0);
|
||||
if (ret < 0)
|
||||
dev_warn(rc5t583->dev,
|
||||
"Error in writing reg 0x%02x error: %d\n",
|
||||
i, ret);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
/* Enable caching in interrupt registers */
|
||||
switch (reg) {
|
||||
case RC5T583_INT_EN_SYS1:
|
||||
case RC5T583_INT_EN_SYS2:
|
||||
case RC5T583_INT_EN_DCDC:
|
||||
case RC5T583_INT_EN_RTC:
|
||||
case RC5T583_INT_EN_ADC1:
|
||||
case RC5T583_INT_EN_ADC2:
|
||||
case RC5T583_INT_EN_ADC3:
|
||||
case RC5T583_GPIO_GPEDGE1:
|
||||
case RC5T583_GPIO_GPEDGE2:
|
||||
case RC5T583_GPIO_EN_INT:
|
||||
return false;
|
||||
|
||||
case RC5T583_GPIO_MON_IOIN:
|
||||
/* This is gpio input register */
|
||||
return true;
|
||||
|
||||
default:
|
||||
/* Enable caching in gpio registers */
|
||||
if ((reg >= RC5T583_GPIO_IOSEL) &&
|
||||
(reg <= RC5T583_GPIO_GPOFUNC))
|
||||
return false;
|
||||
|
||||
/* Enable caching in sleep seq registers */
|
||||
if ((reg >= RC5T583_SLPSEQ1) && (reg <= RC5T583_SLPSEQ11))
|
||||
return false;
|
||||
|
||||
/* Enable caching of regulator registers */
|
||||
if ((reg >= RC5T583_REG_DC0CTL) && (reg <= RC5T583_REG_SR3CTL))
|
||||
return false;
|
||||
if ((reg >= RC5T583_REG_LDOEN1) &&
|
||||
(reg <= RC5T583_REG_LDO9DAC_DS))
|
||||
return false;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static const struct regmap_config rc5t583_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.volatile_reg = volatile_reg,
|
||||
.max_register = RC5T583_MAX_REGS,
|
||||
.num_reg_defaults_raw = RC5T583_MAX_REGS,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static int __devinit rc5t583_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct rc5t583 *rc5t583;
|
||||
struct rc5t583_platform_data *pdata = i2c->dev.platform_data;
|
||||
int ret;
|
||||
bool irq_init_success = false;
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&i2c->dev, "Err: Platform data not found\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc5t583 = devm_kzalloc(&i2c->dev, sizeof(struct rc5t583), GFP_KERNEL);
|
||||
if (!rc5t583) {
|
||||
dev_err(&i2c->dev, "Memory allocation failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rc5t583->dev = &i2c->dev;
|
||||
i2c_set_clientdata(i2c, rc5t583);
|
||||
|
||||
rc5t583->regmap = regmap_init_i2c(i2c, &rc5t583_regmap_config);
|
||||
if (IS_ERR(rc5t583->regmap)) {
|
||||
ret = PTR_ERR(rc5t583->regmap);
|
||||
dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = rc5t583_clear_ext_power_req(rc5t583, pdata);
|
||||
if (ret < 0)
|
||||
goto err_irq_init;
|
||||
|
||||
if (i2c->irq) {
|
||||
ret = rc5t583_irq_init(rc5t583, i2c->irq, pdata->irq_base);
|
||||
/* Still continue with waring if irq init fails */
|
||||
if (ret)
|
||||
dev_warn(&i2c->dev, "IRQ init failed: %d\n", ret);
|
||||
else
|
||||
irq_init_success = true;
|
||||
}
|
||||
|
||||
ret = mfd_add_devices(rc5t583->dev, -1, rc5t583_subdevs,
|
||||
ARRAY_SIZE(rc5t583_subdevs), NULL, 0);
|
||||
if (ret) {
|
||||
dev_err(&i2c->dev, "add mfd devices failed: %d\n", ret);
|
||||
goto err_add_devs;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_add_devs:
|
||||
if (irq_init_success)
|
||||
rc5t583_irq_exit(rc5t583);
|
||||
err_irq_init:
|
||||
regmap_exit(rc5t583->regmap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit rc5t583_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
struct rc5t583 *rc5t583 = i2c_get_clientdata(i2c);
|
||||
|
||||
mfd_remove_devices(rc5t583->dev);
|
||||
rc5t583_irq_exit(rc5t583);
|
||||
regmap_exit(rc5t583->regmap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id rc5t583_i2c_id[] = {
|
||||
{.name = "rc5t583", .driver_data = 0},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, rc5t583_i2c_id);
|
||||
|
||||
static struct i2c_driver rc5t583_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "rc5t583",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = rc5t583_i2c_probe,
|
||||
.remove = __devexit_p(rc5t583_i2c_remove),
|
||||
.id_table = rc5t583_i2c_id,
|
||||
};
|
||||
|
||||
static int __init rc5t583_i2c_init(void)
|
||||
{
|
||||
return i2c_add_driver(&rc5t583_i2c_driver);
|
||||
}
|
||||
subsys_initcall(rc5t583_i2c_init);
|
||||
|
||||
static void __exit rc5t583_i2c_exit(void)
|
||||
{
|
||||
i2c_del_driver(&rc5t583_i2c_driver);
|
||||
}
|
||||
|
||||
module_exit(rc5t583_i2c_exit);
|
||||
|
||||
MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
|
||||
MODULE_DESCRIPTION("RICOH RC5T583 power management system device driver");
|
||||
MODULE_LICENSE("GPL v2");
|
295
include/linux/mfd/rc5t583.h
Normal file
295
include/linux/mfd/rc5t583.h
Normal file
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
* Core driver interface to access RICOH_RC5T583 power management chip.
|
||||
*
|
||||
* Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved.
|
||||
* Author: Laxman dewangan <ldewangan@nvidia.com>
|
||||
*
|
||||
* Based on code
|
||||
* Copyright (C) 2011 RICOH COMPANY,LTD
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MFD_RC5T583_H
|
||||
#define __LINUX_MFD_RC5T583_H
|
||||
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define RC5T583_MAX_REGS 0xF8
|
||||
|
||||
/* Maximum number of main interrupts */
|
||||
#define MAX_MAIN_INTERRUPT 5
|
||||
#define RC5T583_MAX_GPEDGE_REG 2
|
||||
#define RC5T583_MAX_INTERRUPT_MASK_REGS 9
|
||||
|
||||
/* Interrupt enable register */
|
||||
#define RC5T583_INT_EN_SYS1 0x19
|
||||
#define RC5T583_INT_EN_SYS2 0x1D
|
||||
#define RC5T583_INT_EN_DCDC 0x41
|
||||
#define RC5T583_INT_EN_RTC 0xED
|
||||
#define RC5T583_INT_EN_ADC1 0x90
|
||||
#define RC5T583_INT_EN_ADC2 0x91
|
||||
#define RC5T583_INT_EN_ADC3 0x92
|
||||
|
||||
/* Interrupt status registers (monitor regs in Ricoh)*/
|
||||
#define RC5T583_INTC_INTPOL 0xAD
|
||||
#define RC5T583_INTC_INTEN 0xAE
|
||||
#define RC5T583_INTC_INTMON 0xAF
|
||||
|
||||
#define RC5T583_INT_MON_GRP 0xAF
|
||||
#define RC5T583_INT_MON_SYS1 0x1B
|
||||
#define RC5T583_INT_MON_SYS2 0x1F
|
||||
#define RC5T583_INT_MON_DCDC 0x43
|
||||
#define RC5T583_INT_MON_RTC 0xEE
|
||||
|
||||
/* Interrupt clearing registers */
|
||||
#define RC5T583_INT_IR_SYS1 0x1A
|
||||
#define RC5T583_INT_IR_SYS2 0x1E
|
||||
#define RC5T583_INT_IR_DCDC 0x42
|
||||
#define RC5T583_INT_IR_RTC 0xEE
|
||||
#define RC5T583_INT_IR_ADCL 0x94
|
||||
#define RC5T583_INT_IR_ADCH 0x95
|
||||
#define RC5T583_INT_IR_ADCEND 0x96
|
||||
#define RC5T583_INT_IR_GPIOR 0xA9
|
||||
#define RC5T583_INT_IR_GPIOF 0xAA
|
||||
|
||||
/* Sleep sequence registers */
|
||||
#define RC5T583_SLPSEQ1 0x21
|
||||
#define RC5T583_SLPSEQ2 0x22
|
||||
#define RC5T583_SLPSEQ3 0x23
|
||||
#define RC5T583_SLPSEQ4 0x24
|
||||
#define RC5T583_SLPSEQ5 0x25
|
||||
#define RC5T583_SLPSEQ6 0x26
|
||||
#define RC5T583_SLPSEQ7 0x27
|
||||
#define RC5T583_SLPSEQ8 0x28
|
||||
#define RC5T583_SLPSEQ9 0x29
|
||||
#define RC5T583_SLPSEQ10 0x2A
|
||||
#define RC5T583_SLPSEQ11 0x2B
|
||||
|
||||
/* Regulator registers */
|
||||
#define RC5T583_REG_DC0CTL 0x30
|
||||
#define RC5T583_REG_DC0DAC 0x31
|
||||
#define RC5T583_REG_DC0LATCTL 0x32
|
||||
#define RC5T583_REG_SR0CTL 0x33
|
||||
|
||||
#define RC5T583_REG_DC1CTL 0x34
|
||||
#define RC5T583_REG_DC1DAC 0x35
|
||||
#define RC5T583_REG_DC1LATCTL 0x36
|
||||
#define RC5T583_REG_SR1CTL 0x37
|
||||
|
||||
#define RC5T583_REG_DC2CTL 0x38
|
||||
#define RC5T583_REG_DC2DAC 0x39
|
||||
#define RC5T583_REG_DC2LATCTL 0x3A
|
||||
#define RC5T583_REG_SR2CTL 0x3B
|
||||
|
||||
#define RC5T583_REG_DC3CTL 0x3C
|
||||
#define RC5T583_REG_DC3DAC 0x3D
|
||||
#define RC5T583_REG_DC3LATCTL 0x3E
|
||||
#define RC5T583_REG_SR3CTL 0x3F
|
||||
|
||||
|
||||
#define RC5T583_REG_LDOEN1 0x50
|
||||
#define RC5T583_REG_LDOEN2 0x51
|
||||
#define RC5T583_REG_LDODIS1 0x52
|
||||
#define RC5T583_REG_LDODIS2 0x53
|
||||
|
||||
#define RC5T583_REG_LDO0DAC 0x54
|
||||
#define RC5T583_REG_LDO1DAC 0x55
|
||||
#define RC5T583_REG_LDO2DAC 0x56
|
||||
#define RC5T583_REG_LDO3DAC 0x57
|
||||
#define RC5T583_REG_LDO4DAC 0x58
|
||||
#define RC5T583_REG_LDO5DAC 0x59
|
||||
#define RC5T583_REG_LDO6DAC 0x5A
|
||||
#define RC5T583_REG_LDO7DAC 0x5B
|
||||
#define RC5T583_REG_LDO8DAC 0x5C
|
||||
#define RC5T583_REG_LDO9DAC 0x5D
|
||||
|
||||
#define RC5T583_REG_DC0DAC_DS 0x60
|
||||
#define RC5T583_REG_DC1DAC_DS 0x61
|
||||
#define RC5T583_REG_DC2DAC_DS 0x62
|
||||
#define RC5T583_REG_DC3DAC_DS 0x63
|
||||
|
||||
#define RC5T583_REG_LDO0DAC_DS 0x64
|
||||
#define RC5T583_REG_LDO1DAC_DS 0x65
|
||||
#define RC5T583_REG_LDO2DAC_DS 0x66
|
||||
#define RC5T583_REG_LDO3DAC_DS 0x67
|
||||
#define RC5T583_REG_LDO4DAC_DS 0x68
|
||||
#define RC5T583_REG_LDO5DAC_DS 0x69
|
||||
#define RC5T583_REG_LDO6DAC_DS 0x6A
|
||||
#define RC5T583_REG_LDO7DAC_DS 0x6B
|
||||
#define RC5T583_REG_LDO8DAC_DS 0x6C
|
||||
#define RC5T583_REG_LDO9DAC_DS 0x6D
|
||||
|
||||
/* GPIO register base address */
|
||||
#define RC5T583_GPIO_IOSEL 0xA0
|
||||
#define RC5T583_GPIO_PDEN 0xA1
|
||||
#define RC5T583_GPIO_IOOUT 0xA2
|
||||
#define RC5T583_GPIO_PGSEL 0xA3
|
||||
#define RC5T583_GPIO_GPINV 0xA4
|
||||
#define RC5T583_GPIO_GPDEB 0xA5
|
||||
#define RC5T583_GPIO_GPEDGE1 0xA6
|
||||
#define RC5T583_GPIO_GPEDGE2 0xA7
|
||||
#define RC5T583_GPIO_EN_INT 0xA8
|
||||
#define RC5T583_GPIO_MON_IOIN 0xAB
|
||||
#define RC5T583_GPIO_GPOFUNC 0xAC
|
||||
|
||||
/* RICOH_RC5T583 IRQ definitions */
|
||||
enum {
|
||||
RC5T583_IRQ_ONKEY,
|
||||
RC5T583_IRQ_ACOK,
|
||||
RC5T583_IRQ_LIDOPEN,
|
||||
RC5T583_IRQ_PREOT,
|
||||
RC5T583_IRQ_CLKSTP,
|
||||
RC5T583_IRQ_ONKEY_OFF,
|
||||
RC5T583_IRQ_WD,
|
||||
RC5T583_IRQ_EN_PWRREQ1,
|
||||
RC5T583_IRQ_EN_PWRREQ2,
|
||||
RC5T583_IRQ_PRE_VINDET,
|
||||
|
||||
RC5T583_IRQ_DC0LIM,
|
||||
RC5T583_IRQ_DC1LIM,
|
||||
RC5T583_IRQ_DC2LIM,
|
||||
RC5T583_IRQ_DC3LIM,
|
||||
|
||||
RC5T583_IRQ_CTC,
|
||||
RC5T583_IRQ_YALE,
|
||||
RC5T583_IRQ_DALE,
|
||||
RC5T583_IRQ_WALE,
|
||||
|
||||
RC5T583_IRQ_AIN1L,
|
||||
RC5T583_IRQ_AIN2L,
|
||||
RC5T583_IRQ_AIN3L,
|
||||
RC5T583_IRQ_VBATL,
|
||||
RC5T583_IRQ_VIN3L,
|
||||
RC5T583_IRQ_VIN8L,
|
||||
RC5T583_IRQ_AIN1H,
|
||||
RC5T583_IRQ_AIN2H,
|
||||
RC5T583_IRQ_AIN3H,
|
||||
RC5T583_IRQ_VBATH,
|
||||
RC5T583_IRQ_VIN3H,
|
||||
RC5T583_IRQ_VIN8H,
|
||||
RC5T583_IRQ_ADCEND,
|
||||
|
||||
RC5T583_IRQ_GPIO0,
|
||||
RC5T583_IRQ_GPIO1,
|
||||
RC5T583_IRQ_GPIO2,
|
||||
RC5T583_IRQ_GPIO3,
|
||||
RC5T583_IRQ_GPIO4,
|
||||
RC5T583_IRQ_GPIO5,
|
||||
RC5T583_IRQ_GPIO6,
|
||||
RC5T583_IRQ_GPIO7,
|
||||
|
||||
/* Should be last entry */
|
||||
RC5T583_MAX_IRQS,
|
||||
};
|
||||
|
||||
/* Ricoh583 gpio definitions */
|
||||
enum {
|
||||
RC5T583_GPIO0,
|
||||
RC5T583_GPIO1,
|
||||
RC5T583_GPIO2,
|
||||
RC5T583_GPIO3,
|
||||
RC5T583_GPIO4,
|
||||
RC5T583_GPIO5,
|
||||
RC5T583_GPIO6,
|
||||
RC5T583_GPIO7,
|
||||
|
||||
/* Should be last entry */
|
||||
RC5T583_MAX_GPIO,
|
||||
};
|
||||
|
||||
enum {
|
||||
RC5T583_DS_NONE,
|
||||
RC5T583_DS_DC0,
|
||||
RC5T583_DS_DC1,
|
||||
RC5T583_DS_DC2,
|
||||
RC5T583_DS_DC3,
|
||||
RC5T583_DS_LDO0,
|
||||
RC5T583_DS_LDO1,
|
||||
RC5T583_DS_LDO2,
|
||||
RC5T583_DS_LDO3,
|
||||
RC5T583_DS_LDO4,
|
||||
RC5T583_DS_LDO5,
|
||||
RC5T583_DS_LDO6,
|
||||
RC5T583_DS_LDO7,
|
||||
RC5T583_DS_LDO8,
|
||||
RC5T583_DS_LDO9,
|
||||
RC5T583_DS_PSO0,
|
||||
RC5T583_DS_PSO1,
|
||||
RC5T583_DS_PSO2,
|
||||
RC5T583_DS_PSO3,
|
||||
RC5T583_DS_PSO4,
|
||||
RC5T583_DS_PSO5,
|
||||
RC5T583_DS_PSO6,
|
||||
RC5T583_DS_PSO7,
|
||||
|
||||
/* Should be last entry */
|
||||
RC5T583_DS_MAX,
|
||||
};
|
||||
|
||||
/*
|
||||
* Ricoh pmic RC5T583 supports sleep through two external controls.
|
||||
* The output of gpios and regulator can be enable/disable through
|
||||
* this external signals.
|
||||
*/
|
||||
enum {
|
||||
RC5T583_EXT_PWRREQ1_CONTROL = 0x1,
|
||||
RC5T583_EXT_PWRREQ2_CONTROL = 0x2,
|
||||
};
|
||||
|
||||
struct rc5t583 {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
int chip_irq;
|
||||
int irq_base;
|
||||
struct mutex irq_lock;
|
||||
unsigned long group_irq_en[MAX_MAIN_INTERRUPT];
|
||||
|
||||
/* For main interrupt bits in INTC */
|
||||
uint8_t intc_inten_reg;
|
||||
|
||||
/* For group interrupt bits and address */
|
||||
uint8_t irq_en_reg[RC5T583_MAX_INTERRUPT_MASK_REGS];
|
||||
|
||||
/* For gpio edge */
|
||||
uint8_t gpedge_reg[RC5T583_MAX_GPEDGE_REG];
|
||||
};
|
||||
|
||||
/*
|
||||
* rc5t583_platform_data: Platform data for ricoh rc5t583 pmu.
|
||||
* The board specific data is provided through this structure.
|
||||
* @irq_base: Irq base number on which this device registers their interrupts.
|
||||
* @enable_shutdown: Enable shutdown through the input pin "shutdown".
|
||||
*/
|
||||
|
||||
struct rc5t583_platform_data {
|
||||
int irq_base;
|
||||
bool enable_shutdown;
|
||||
};
|
||||
|
||||
int rc5t583_write(struct device *dev, u8 reg, uint8_t val);
|
||||
int rc5t583_read(struct device *dev, uint8_t reg, uint8_t *val);
|
||||
int rc5t583_set_bits(struct device *dev, unsigned int reg,
|
||||
unsigned int bit_mask);
|
||||
int rc5t583_clear_bits(struct device *dev, unsigned int reg,
|
||||
unsigned int bit_mask);
|
||||
int rc5t583_update(struct device *dev, unsigned int reg,
|
||||
unsigned int val, unsigned int mask);
|
||||
int rc5t583_ext_power_req_config(struct device *dev, int deepsleep_id,
|
||||
int ext_pwr_req, int deepsleep_slot_nr);
|
||||
int rc5t583_irq_init(struct rc5t583 *rc5t583, int irq, int irq_base);
|
||||
int rc5t583_irq_exit(struct rc5t583 *rc5t583);
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue