blob: 56cce66175e7988dd8c7ad2f106bc582b1d77b61 [file] [log] [blame]
/*
* driver/mfd/ricoh583.c
*
* Core driver implementation to access RICOH583 power management chip.
*
* Copyright (C) 2011 NVIDIA Corporation
*
* Copyright (C) 2011 RICOH COMPANY,LTD
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
/*#define DEBUG 1*/
/*#define VERBOSE_DEBUG 1*/
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>
#include <linux/mfd/ricoh583.h>
#define RICOH_ONOFFSEL_REG 0x10
#define RICOH_SWCTL_REG 0x5E
/* Interrupt enable register */
#define RICOH583_INT_EN_SYS1 0x19
#define RICOH583_INT_EN_SYS2 0x1D
#define RICOH583_INT_EN_DCDC 0x41
#define RICOH583_INT_EN_RTC 0xED
#define RICOH583_INT_EN_ADC1 0x90
#define RICOH583_INT_EN_ADC2 0x91
#define RICOH583_INT_EN_ADC3 0x92
#define RICOH583_INT_EN_GPIO 0xA8
/* interrupt status registers (monitor regs in Ricoh)*/
#define RICOH583_INTC_INTPOL 0xAD
#define RICOH583_INTC_INTEN 0xAE
#define RICOH583_INTC_INTMON 0xAF
#define RICOH583_INT_MON_GRP 0xAF
#define RICOH583_INT_MON_SYS1 0x1B
#define RICOH583_INT_MON_SYS2 0x1F
#define RICOH583_INT_MON_DCDC 0x43
#define RICOH583_INT_MON_RTC 0xEE
/* interrupt clearing registers */
#define RICOH583_INT_IR_SYS1 0x1A
#define RICOH583_INT_IR_SYS2 0x1E
#define RICOH583_INT_IR_DCDC 0x42
#define RICOH583_INT_IR_RTC 0xEE
#define RICOH583_INT_IR_ADCL 0x94
#define RICOH583_INT_IR_ADCH 0x95
#define RICOH583_INT_IR_ADCEND 0x96
#define RICOH583_INT_IR_GPIOR 0xA9
#define RICOH583_INT_IR_GPIOF 0xAA
/* GPIO register base address */
#define RICOH583_GPIO_IOSEL 0xA0
#define RICOH583_GPIO_PDEN 0xA1
#define RICOH583_GPIO_IOOUT 0xA2
#define RICOH583_GPIO_PGSEL 0xA3
#define RICOH583_GPIO_GPINV 0xA4
#define RICOH583_GPIO_GPDEB 0xA5
#define RICOH583_GPIO_GPEDGE1 0xA6
#define RICOH583_GPIO_GPEDGE2 0xA7
#define RICOH583_GPIO_EN_GPIR 0xA8
#define RICOH583_GPIO_MON_IOIN 0xAB
#define RICOH583_GPIO_GPOFUNC 0xAC
#define RICOH583_INTC_INTEN 0xAE
enum int_type {
SYS_INT = 0x1,
DCDC_INT = 0x2,
RTC_INT = 0x4,
ADC_INT = 0x8,
GPIO_INT = 0x10,
};
struct ricoh583_irq_data {
u8 int_type;
u8 master_bit;
u8 int_en_bit;
u8 mask_reg_index;
int grp_index;
};
struct deepsleep_control_data {
u8 reg_add;
u8 ds_pos_bit;
};
#define RICOH583_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 ricoh583_irq_data ricoh583_irqs[] = {
[RICOH583_IRQ_ONKEY] = RICOH583_IRQ(SYS_INT, 0, 0, 0, 0),
[RICOH583_IRQ_ACOK] = RICOH583_IRQ(SYS_INT, 0, 1, 1, 0),
[RICOH583_IRQ_LIDOPEN] = RICOH583_IRQ(SYS_INT, 0, 2, 2, 0),
[RICOH583_IRQ_PREOT] = RICOH583_IRQ(SYS_INT, 0, 3, 3, 0),
[RICOH583_IRQ_CLKSTP] = RICOH583_IRQ(SYS_INT, 0, 4, 4, 0),
[RICOH583_IRQ_ONKEY_OFF] = RICOH583_IRQ(SYS_INT, 0, 5, 5, 0),
[RICOH583_IRQ_WD] = RICOH583_IRQ(SYS_INT, 0, 7, 7, 0),
[RICOH583_IRQ_EN_PWRREQ1] = RICOH583_IRQ(SYS_INT, 0, 8, 0, 1),
[RICOH583_IRQ_EN_PWRREQ2] = RICOH583_IRQ(SYS_INT, 0, 9, 1, 1),
[RICOH583_IRQ_PRE_VINDET] = RICOH583_IRQ(SYS_INT, 0, 10, 2, 1),
[RICOH583_IRQ_DC0LIM] = RICOH583_IRQ(DCDC_INT, 1, 0, 0, 2),
[RICOH583_IRQ_DC1LIM] = RICOH583_IRQ(DCDC_INT, 1, 1, 1, 2),
[RICOH583_IRQ_DC2LIM] = RICOH583_IRQ(DCDC_INT, 1, 2, 2, 2),
[RICOH583_IRQ_DC3LIM] = RICOH583_IRQ(DCDC_INT, 1, 3, 3, 2),
[RICOH583_IRQ_CTC] = RICOH583_IRQ(RTC_INT, 2, 0, 0, 3),
[RICOH583_IRQ_YALE] = RICOH583_IRQ(RTC_INT, 2, 5, 5, 3),
[RICOH583_IRQ_DALE] = RICOH583_IRQ(RTC_INT, 2, 6, 6, 3),
[RICOH583_IRQ_WALE] = RICOH583_IRQ(RTC_INT, 2, 7, 7, 3),
[RICOH583_IRQ_AIN1L] = RICOH583_IRQ(ADC_INT, 3, 0, 0, 4),
[RICOH583_IRQ_AIN2L] = RICOH583_IRQ(ADC_INT, 3, 1, 1, 4),
[RICOH583_IRQ_AIN3L] = RICOH583_IRQ(ADC_INT, 3, 2, 2, 4),
[RICOH583_IRQ_VBATL] = RICOH583_IRQ(ADC_INT, 3, 3, 3, 4),
[RICOH583_IRQ_VIN3L] = RICOH583_IRQ(ADC_INT, 3, 4, 4, 4),
[RICOH583_IRQ_VIN8L] = RICOH583_IRQ(ADC_INT, 3, 5, 5, 4),
[RICOH583_IRQ_AIN1H] = RICOH583_IRQ(ADC_INT, 3, 6, 0, 5),
[RICOH583_IRQ_AIN2H] = RICOH583_IRQ(ADC_INT, 3, 7, 1, 5),
[RICOH583_IRQ_AIN3H] = RICOH583_IRQ(ADC_INT, 3, 8, 2, 5),
[RICOH583_IRQ_VBATH] = RICOH583_IRQ(ADC_INT, 3, 9, 3, 5),
[RICOH583_IRQ_VIN3H] = RICOH583_IRQ(ADC_INT, 3, 10, 4, 5),
[RICOH583_IRQ_VIN8H] = RICOH583_IRQ(ADC_INT, 3, 11, 5, 5),
[RICOH583_IRQ_ADCEND] = RICOH583_IRQ(ADC_INT, 3, 12, 0, 6),
[RICOH583_IRQ_GPIO0] = RICOH583_IRQ(GPIO_INT, 4, 0, 0, 7),
[RICOH583_IRQ_GPIO1] = RICOH583_IRQ(GPIO_INT, 4, 1, 1, 7),
[RICOH583_IRQ_GPIO2] = RICOH583_IRQ(GPIO_INT, 4, 2, 2, 7),
[RICOH583_IRQ_GPIO3] = RICOH583_IRQ(GPIO_INT, 4, 3, 3, 7),
[RICOH583_IRQ_GPIO4] = RICOH583_IRQ(GPIO_INT, 4, 4, 4, 7),
[RICOH583_IRQ_GPIO5] = RICOH583_IRQ(GPIO_INT, 4, 5, 5, 7),
[RICOH583_IRQ_GPIO6] = RICOH583_IRQ(GPIO_INT, 4, 6, 6, 7),
[RICOH583_IRQ_GPIO7] = RICOH583_IRQ(GPIO_INT, 4, 7, 7, 7),
[RICOH583_NR_IRQS] = RICOH583_IRQ(GPIO_INT, 4, 8, 8, 7),
};
#define DEEPSLEEP_INIT(_id, _reg, _pos) \
[RICOH583_DS_##_id] = {.reg_add = _reg, .ds_pos_bit = _pos}
static struct deepsleep_control_data deepsleep_data[] = {
DEEPSLEEP_INIT(DC1, 0x21, 4),
DEEPSLEEP_INIT(DC2, 0x22, 0),
DEEPSLEEP_INIT(DC3, 0x22, 4),
DEEPSLEEP_INIT(LDO0, 0x23, 0),
DEEPSLEEP_INIT(LDO1, 0x23, 4),
DEEPSLEEP_INIT(LDO2, 0x24, 0),
DEEPSLEEP_INIT(LDO3, 0x24, 4),
DEEPSLEEP_INIT(LDO4, 0x25, 0),
DEEPSLEEP_INIT(LDO5, 0x25, 4),
DEEPSLEEP_INIT(LDO6, 0x26, 0),
DEEPSLEEP_INIT(LDO7, 0x26, 4),
DEEPSLEEP_INIT(LDO8, 0x27, 0),
DEEPSLEEP_INIT(LDO9, 0x27, 4),
DEEPSLEEP_INIT(PSO0, 0x28, 0),
DEEPSLEEP_INIT(PSO1, 0x28, 4),
DEEPSLEEP_INIT(PSO2, 0x29, 0),
DEEPSLEEP_INIT(PSO3, 0x29, 4),
DEEPSLEEP_INIT(PSO4, 0x2A, 0),
DEEPSLEEP_INIT(PSO5, 0x2A, 4),
DEEPSLEEP_INIT(PSO6, 0x2B, 0),
DEEPSLEEP_INIT(PSO7, 0x2B, 4),
};
#define MAX_INTERRUPT_MASKS 8
#define MAX_MAIN_INTERRUPT 5
#define EXT_PWR_REQ \
(RICOH583_EXT_PWRREQ1_CONTROL | RICOH583_EXT_PWRREQ2_CONTROL)
struct ricoh583 {
struct device *dev;
struct i2c_client *client;
struct mutex io_lock;
int gpio_base;
struct gpio_chip gpio;
int irq_base;
struct irq_chip irq_chip;
struct mutex irq_lock;
unsigned long group_irq_en[MAX_MAIN_INTERRUPT];
/* For main interrupt bits in INTC */
u8 intc_inten_cache;
u8 intc_inten_reg;
/* For group interrupt bits and address */
u8 irq_en_cache[MAX_INTERRUPT_MASKS];
u8 irq_en_reg[MAX_INTERRUPT_MASKS];
u8 irq_en_add[MAX_INTERRUPT_MASKS];
/* Interrupt monitor and clear register */
u8 irq_mon_add[MAX_INTERRUPT_MASKS + 1];
u8 irq_clr_add[MAX_INTERRUPT_MASKS + 1];
u8 main_int_type[MAX_INTERRUPT_MASKS + 1];
/* For gpio edge */
u8 gpedge_cache[2];
u8 gpedge_reg[2];
u8 gpedge_add[2];
};
static inline int __ricoh583_read(struct i2c_client *client,
u8 reg, uint8_t *val)
{
int ret;
ret = i2c_smbus_read_byte_data(client, reg);
if (ret < 0) {
dev_err(&client->dev, "failed reading at 0x%02x\n", reg);
return ret;
}
*val = (uint8_t)ret;
dev_dbg(&client->dev, "ricoh583: reg read reg=%x, val=%x\n",
reg, *val);
return 0;
}
static inline int __ricoh583_bulk_reads(struct i2c_client *client, u8 reg,
int len, uint8_t *val)
{
int ret;
int i;
ret = i2c_smbus_read_i2c_block_data(client, reg, len, val);
if (ret < 0) {
dev_err(&client->dev, "failed reading from 0x%02x\n", reg);
return ret;
}
for (i = 0; i < len; ++i) {
dev_dbg(&client->dev, "ricoh583: reg read reg=%x, val=%x\n",
reg + i, *(val + i));
}
return 0;
}
static inline int __ricoh583_write(struct i2c_client *client,
u8 reg, uint8_t val)
{
int ret;
dev_dbg(&client->dev, "ricoh583: reg write reg=%x, val=%x\n",
reg, val);
ret = i2c_smbus_write_byte_data(client, reg, val);
if (ret < 0) {
dev_err(&client->dev, "failed writing 0x%02x to 0x%02x\n",
val, reg);
return ret;
}
return 0;
}
static inline int __ricoh583_bulk_writes(struct i2c_client *client, u8 reg,
int len, uint8_t *val)
{
int ret;
int i;
for (i = 0; i < len; ++i) {
dev_dbg(&client->dev, "ricoh583: reg write reg=%x, val=%x\n",
reg + i, *(val + i));
}
ret = i2c_smbus_write_i2c_block_data(client, reg, len, val);
if (ret < 0) {
dev_err(&client->dev, "failed writings to 0x%02x\n", reg);
return ret;
}
return 0;
}
int ricoh583_write(struct device *dev, u8 reg, uint8_t val)
{
struct ricoh583 *ricoh583 = dev_get_drvdata(dev);
int ret = 0;
mutex_lock(&ricoh583->io_lock);
ret = __ricoh583_write(to_i2c_client(dev), reg, val);
mutex_unlock(&ricoh583->io_lock);
return ret;
}
EXPORT_SYMBOL_GPL(ricoh583_write);
int ricoh583_bulk_writes(struct device *dev, u8 reg, u8 len, uint8_t *val)
{
struct ricoh583 *ricoh583 = dev_get_drvdata(dev);
int ret = 0;
mutex_lock(&ricoh583->io_lock);
ret = __ricoh583_bulk_writes(to_i2c_client(dev), reg, len, val);
mutex_unlock(&ricoh583->io_lock);
return ret;
}
EXPORT_SYMBOL_GPL(ricoh583_bulk_writes);
int ricoh583_read(struct device *dev, u8 reg, uint8_t *val)
{
return __ricoh583_read(to_i2c_client(dev), reg, val);
}
EXPORT_SYMBOL_GPL(ricoh583_read);
int ricoh583_bulk_reads(struct device *dev, u8 reg, u8 len, uint8_t *val)
{
return __ricoh583_bulk_reads(to_i2c_client(dev), reg, len, val);
}
EXPORT_SYMBOL_GPL(ricoh583_bulk_reads);
int ricoh583_set_bits(struct device *dev, u8 reg, uint8_t bit_mask)
{
struct ricoh583 *ricoh583 = dev_get_drvdata(dev);
uint8_t reg_val;
int ret = 0;
mutex_lock(&ricoh583->io_lock);
ret = __ricoh583_read(to_i2c_client(dev), reg, &reg_val);
if (ret)
goto out;
if ((reg_val & bit_mask) != bit_mask) {
reg_val |= bit_mask;
ret = __ricoh583_write(to_i2c_client(dev), reg, reg_val);
}
out:
mutex_unlock(&ricoh583->io_lock);
return ret;
}
EXPORT_SYMBOL_GPL(ricoh583_set_bits);
int ricoh583_clr_bits(struct device *dev, u8 reg, uint8_t bit_mask)
{
struct ricoh583 *ricoh583 = dev_get_drvdata(dev);
uint8_t reg_val;
int ret = 0;
mutex_lock(&ricoh583->io_lock);
ret = __ricoh583_read(to_i2c_client(dev), reg, &reg_val);
if (ret)
goto out;
if (reg_val & bit_mask) {
reg_val &= ~bit_mask;
ret = __ricoh583_write(to_i2c_client(dev), reg, reg_val);
}
out:
mutex_unlock(&ricoh583->io_lock);
return ret;
}
EXPORT_SYMBOL_GPL(ricoh583_clr_bits);
int ricoh583_update(struct device *dev, u8 reg, uint8_t val, uint8_t mask)
{
struct ricoh583 *ricoh583 = dev_get_drvdata(dev);
uint8_t reg_val;
int ret = 0;
mutex_lock(&ricoh583->io_lock);
ret = __ricoh583_read(ricoh583->client, reg, &reg_val);
if (ret)
goto out;
if ((reg_val & mask) != val) {
reg_val = (reg_val & ~mask) | (val & mask);
ret = __ricoh583_write(ricoh583->client, reg, reg_val);
}
out:
mutex_unlock(&ricoh583->io_lock);
return ret;
}
EXPORT_SYMBOL_GPL(ricoh583_update);
static int __ricoh583_set_ext_pwrreq1_control(struct device *dev,
enum ricoh583_deepsleep_control_id id,
enum ricoh583_ext_pwrreq_control ext_pwr, int slots)
{
int ret;
uint8_t sleepseq_val;
u8 en_bit;
u8 slot_bit;
if (!(ext_pwr & RICOH583_EXT_PWRREQ1_CONTROL))
return 0;
if (id == RICOH583_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 = ricoh583_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 |= (1 << en_bit);
sleepseq_val |= ((slots & 0x7) << slot_bit);
ret = ricoh583_set_bits(dev, RICOH_ONOFFSEL_REG, (1 << 1));
if (ret < 0) {
dev_err(dev, "Error in updating the 0x%02x register\n",
RICOH_ONOFFSEL_REG);
return ret;
}
ret = ricoh583_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 == RICOH583_DS_LDO4) {
ret = ricoh583_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 __ricoh583_set_ext_pwrreq2_control(struct device *dev,
enum ricoh583_deepsleep_control_id id,
enum ricoh583_ext_pwrreq_control ext_pwr)
{
int ret;
if (!(ext_pwr & RICOH583_EXT_PWRREQ2_CONTROL))
return 0;
if (id != RICOH583_DS_DC0) {
dev_err(dev, "PWRREQ2 is invalid control for rail %d\n", id);
return -EINVAL;
}
ret = ricoh583_set_bits(dev, RICOH_ONOFFSEL_REG, (1 << 2));
if (ret < 0)
dev_err(dev, "Error in updating the ONOFFSEL 0x10 register\n");
return ret;
}
int ricoh583_ext_power_req_config(struct device *dev,
enum ricoh583_deepsleep_control_id id,
enum ricoh583_ext_pwrreq_control ext_pwr_req,
int deepsleep_slot_nr)
{
if ((ext_pwr_req & EXT_PWR_REQ) == EXT_PWR_REQ)
return -EINVAL;
if (ext_pwr_req & RICOH583_EXT_PWRREQ1_CONTROL)
return __ricoh583_set_ext_pwrreq1_control(dev, id,
ext_pwr_req, deepsleep_slot_nr);
if (ext_pwr_req & RICOH583_EXT_PWRREQ2_CONTROL)
return __ricoh583_set_ext_pwrreq2_control(dev,
id, ext_pwr_req);
return 0;
}
EXPORT_SYMBOL_GPL(ricoh583_ext_power_req_config);
static int ricoh583_ext_power_init(struct ricoh583 *ricoh583,
struct ricoh583_platform_data *pdata)
{
int ret;
int i;
uint8_t on_off_val = 0;
/* Clear ONOFFSEL register */
mutex_lock(&ricoh583->io_lock);
if (pdata->enable_shutdown_pin)
on_off_val |= 0x1;
ret = __ricoh583_write(ricoh583->client, RICOH_ONOFFSEL_REG,
on_off_val);
if (ret < 0)
dev_err(ricoh583->dev, "Error in writing reg %d error: "
"%d\n", RICOH_ONOFFSEL_REG, ret);
ret = __ricoh583_write(ricoh583->client, RICOH_SWCTL_REG, 0x0);
if (ret < 0)
dev_err(ricoh583->dev, "Error in writing reg %d error: "
"%d\n", RICOH_SWCTL_REG, ret);
/* Clear sleepseq register */
for (i = 0x21; i < 0x2B; ++i) {
ret = __ricoh583_write(ricoh583->client, i, 0x0);
if (ret < 0)
dev_err(ricoh583->dev, "Error in writing reg 0x%02x "
"error: %d\n", i, ret);
}
mutex_unlock(&ricoh583->io_lock);
return 0;
}
static struct i2c_client *ricoh583_i2c_client;
int ricoh583_power_off(void)
{
if (!ricoh583_i2c_client)
return -EINVAL;
return 0;
}
static int ricoh583_gpio_get(struct gpio_chip *gc, unsigned offset)
{
struct ricoh583 *ricoh583 = container_of(gc, struct ricoh583, gpio);
uint8_t val;
int ret;
ret = __ricoh583_read(ricoh583->client, RICOH583_GPIO_MON_IOIN, &val);
if (ret < 0)
return ret;
return ((val & (0x1 << offset)) != 0);
}
static void ricoh583_gpio_set(struct gpio_chip *chip, unsigned offset,
int value)
{
struct ricoh583 *ricoh583 = container_of(chip, struct ricoh583, gpio);
if (value)
ricoh583_set_bits(ricoh583->dev, RICOH583_GPIO_IOOUT,
1 << offset);
else
ricoh583_clr_bits(ricoh583->dev, RICOH583_GPIO_IOOUT,
1 << offset);
}
static int ricoh583_gpio_input(struct gpio_chip *chip, unsigned offset)
{
struct ricoh583 *ricoh583 = container_of(chip, struct ricoh583, gpio);
return ricoh583_clr_bits(ricoh583->dev, RICOH583_GPIO_IOSEL,
1 << offset);
}
static int ricoh583_gpio_output(struct gpio_chip *chip, unsigned offset,
int value)
{
struct ricoh583 *ricoh583 = container_of(chip, struct ricoh583, gpio);
ricoh583_gpio_set(chip, offset, value);
return ricoh583_set_bits(ricoh583->dev, RICOH583_GPIO_IOSEL,
1 << offset);
}
static int ricoh583_gpio_to_irq(struct gpio_chip *chip, unsigned off)
{
struct ricoh583 *ricoh583 = container_of(chip, struct ricoh583, gpio);
if ((off >= 0) && (off < 8))
return ricoh583->irq_base + RICOH583_IRQ_GPIO0 + off;
return -EIO;
}
static int ricoh583_gpio_request(struct gpio_chip *chip, unsigned offset)
{
struct ricoh583 *ricoh583 = container_of(chip, struct ricoh583, gpio);
int ret;
ret = ricoh583_clr_bits(ricoh583->dev, RICOH583_GPIO_PGSEL,
1 << offset);
if (ret < 0)
dev_err(ricoh583->dev, "%s(): The error in writing register "
"0x%02x\n", __func__, RICOH583_GPIO_PGSEL);
return ret;
}
static void ricoh583_gpio_free(struct gpio_chip *chip, unsigned offset)
{
struct ricoh583 *ricoh583 = container_of(chip, struct ricoh583, gpio);
int ret;
ret = ricoh583_set_bits(ricoh583->dev, RICOH583_GPIO_PGSEL,
1 << offset);
if (ret < 0)
dev_err(ricoh583->dev, "%s(): The error in writing register "
"0x%02x\n", __func__, RICOH583_GPIO_PGSEL);
}
static void ricoh583_gpio_init(struct ricoh583 *ricoh583,
struct ricoh583_platform_data *pdata)
{
int ret;
int i;
struct ricoh583_gpio_init_data *ginit;
if (pdata->gpio_base <= 0)
return;
ret = ricoh583_write(ricoh583->dev, RICOH583_GPIO_PGSEL, 0xEF);
if (ret < 0) {
dev_err(ricoh583->dev, "%s(): The error in writing register "
"0x%02x\n", __func__, RICOH583_GPIO_PGSEL);
return;
}
for (i = 0; i < pdata->num_gpioinit_data; ++i) {
ginit = &pdata->gpio_init_data[i];
if (!ginit->init_apply)
continue;
if (ginit->pulldn_en)
ret = ricoh583_set_bits(ricoh583->dev,
RICOH583_GPIO_PDEN, 1 << i);
else
ret = ricoh583_clr_bits(ricoh583->dev,
RICOH583_GPIO_PDEN, 1 << i);
if (ret < 0)
dev_err(ricoh583->dev, "Gpio %d init "
"pden configuration failed: %d\n", i, ret);
if (ginit->output_mode_en) {
if (ginit->output_val)
ret = ricoh583_set_bits(ricoh583->dev,
RICOH583_GPIO_IOOUT, 1 << i);
else
ret = ricoh583_clr_bits(ricoh583->dev,
RICOH583_GPIO_IOOUT, 1 << i);
if (!ret)
ret = ricoh583_set_bits(ricoh583->dev,
RICOH583_GPIO_IOSEL, 1 << i);
} else
ret = ricoh583_clr_bits(ricoh583->dev,
RICOH583_GPIO_IOSEL, 1 << i);
if (ret < 0)
dev_err(ricoh583->dev, "Gpio %d init "
"dir configuration failed: %d\n", i, ret);
ret = ricoh583_clr_bits(ricoh583->dev, RICOH583_GPIO_PGSEL,
1 << i);
if (ret < 0)
dev_err(ricoh583->dev, "%s(): The error in writing "
"register 0x%02x\n", __func__,
RICOH583_GPIO_PGSEL);
}
ricoh583->gpio.owner = THIS_MODULE;
ricoh583->gpio.label = ricoh583->client->name;
ricoh583->gpio.dev = ricoh583->dev;
ricoh583->gpio.base = pdata->gpio_base;
ricoh583->gpio.ngpio = RICOH583_NR_GPIO;
ricoh583->gpio.can_sleep = 1;
ricoh583->gpio.request = ricoh583_gpio_request;
ricoh583->gpio.free = ricoh583_gpio_free;
ricoh583->gpio.direction_input = ricoh583_gpio_input;
ricoh583->gpio.direction_output = ricoh583_gpio_output;
ricoh583->gpio.set = ricoh583_gpio_set;
ricoh583->gpio.get = ricoh583_gpio_get;
ricoh583->gpio.to_irq = ricoh583_gpio_to_irq;
ret = gpiochip_add(&ricoh583->gpio);
if (ret)
dev_warn(ricoh583->dev, "GPIO registration failed: %d\n", ret);
}
static void ricoh583_irq_lock(struct irq_data *irq_data)
{
struct ricoh583 *ricoh583 = irq_data_get_irq_chip_data(irq_data);
mutex_lock(&ricoh583->irq_lock);
}
static void ricoh583_irq_unmask(struct irq_data *irq_data)
{
struct ricoh583 *ricoh583 = irq_data_get_irq_chip_data(irq_data);
unsigned int __irq = irq_data->irq - ricoh583->irq_base;
const struct ricoh583_irq_data *data = &ricoh583_irqs[__irq];
ricoh583->group_irq_en[data->grp_index] |= (1 << data->grp_index);
if (ricoh583->group_irq_en[data->grp_index])
ricoh583->intc_inten_reg |= 1 << data->master_bit;
ricoh583->irq_en_reg[data->mask_reg_index] |= 1 << data->int_en_bit;
}
static void ricoh583_irq_mask(struct irq_data *irq_data)
{
struct ricoh583 *ricoh583 = irq_data_get_irq_chip_data(irq_data);
unsigned int __irq = irq_data->irq - ricoh583->irq_base;
const struct ricoh583_irq_data *data = &ricoh583_irqs[__irq];
ricoh583->group_irq_en[data->grp_index] &= ~(1 << data->grp_index);
if (!ricoh583->group_irq_en[data->grp_index])
ricoh583->intc_inten_reg &= ~(1 << data->master_bit);
ricoh583->irq_en_reg[data->mask_reg_index] &= ~(1 << data->int_en_bit);
}
static void ricoh583_irq_sync_unlock(struct irq_data *irq_data)
{
struct ricoh583 *ricoh583 = irq_data_get_irq_chip_data(irq_data);
int i;
for (i = 0; i < ARRAY_SIZE(ricoh583->gpedge_reg); i++) {
if (ricoh583->gpedge_reg[i] != ricoh583->gpedge_cache[i]) {
if (!WARN_ON(__ricoh583_write(ricoh583->client,
ricoh583->gpedge_add[i],
ricoh583->gpedge_reg[i])))
ricoh583->gpedge_cache[i] =
ricoh583->gpedge_reg[i];
}
}
for (i = 0; i < ARRAY_SIZE(ricoh583->irq_en_reg); i++) {
if (ricoh583->irq_en_reg[i] != ricoh583->irq_en_cache[i]) {
if (!WARN_ON(__ricoh583_write(ricoh583->client,
ricoh583->irq_en_add[i],
ricoh583->irq_en_reg[i])))
ricoh583->irq_en_cache[i] =
ricoh583->irq_en_reg[i];
}
}
if (ricoh583->intc_inten_reg != ricoh583->intc_inten_cache) {
if (!WARN_ON(__ricoh583_write(ricoh583->client,
RICOH583_INTC_INTEN, ricoh583->intc_inten_reg)))
ricoh583->intc_inten_cache = ricoh583->intc_inten_reg;
}
mutex_unlock(&ricoh583->irq_lock);
}
static int ricoh583_irq_set_type(struct irq_data *irq_data, unsigned int type)
{
struct ricoh583 *ricoh583 = irq_data_get_irq_chip_data(irq_data);
unsigned int __irq = irq_data->irq - ricoh583->irq_base;
const struct ricoh583_irq_data *data = &ricoh583_irqs[__irq];
int val = 0;
int gpedge_index;
int gpedge_bit_pos;
if (data->int_type & GPIO_INT) {
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;
ricoh583->gpedge_reg[gpedge_index] &= ~(3 << gpedge_bit_pos);
ricoh583->gpedge_reg[gpedge_index] |= (val << gpedge_bit_pos);
ricoh583_irq_unmask(irq_data);
}
return 0;
}
static irqreturn_t ricoh583_irq(int irq, void *data)
{
struct ricoh583 *ricoh583 = data;
u8 int_sts[9];
u8 master_int;
int i;
int ret;
u8 rtc_int_sts = 0;
/* Clear the status */
for (i = 0; i < 9; i++)
int_sts[i] = 0;
ret = __ricoh583_read(ricoh583->client, RICOH583_INTC_INTMON,
&master_int);
if (ret < 0) {
dev_err(ricoh583->dev, "Error in reading reg 0x%02x "
"error: %d\n", RICOH583_INTC_INTMON, ret);
return IRQ_HANDLED;
}
for (i = 0; i < 9; ++i) {
if (!(master_int & ricoh583->main_int_type[i]))
continue;
ret = __ricoh583_read(ricoh583->client,
ricoh583->irq_mon_add[i], &int_sts[i]);
if (ret < 0) {
dev_err(ricoh583->dev, "Error in reading reg 0x%02x "
"error: %d\n", ricoh583->irq_mon_add[i], ret);
int_sts[i] = 0;
continue;
}
if (ricoh583->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 = __ricoh583_write(ricoh583->client,
ricoh583->irq_clr_add[i], ~int_sts[i]);
if (ret < 0) {
dev_err(ricoh583->dev, "Error in reading reg 0x%02x "
"error: %d\n", ricoh583->irq_clr_add[i], ret);
}
if (ricoh583->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 < RICOH583_NR_IRQS; ++i) {
const struct ricoh583_irq_data *data = &ricoh583_irqs[i];
if ((int_sts[data->mask_reg_index] & (1 << data->int_en_bit)) &&
(ricoh583->group_irq_en[data->master_bit] &
(1 << data->grp_index)))
handle_nested_irq(ricoh583->irq_base + i);
}
return IRQ_HANDLED;
}
static int ricoh583_irq_init(struct ricoh583 *ricoh583, int irq,
int irq_base)
{
int i, ret;
if (!irq_base) {
dev_warn(ricoh583->dev, "No interrupt support on IRQ base\n");
return -EINVAL;
}
mutex_init(&ricoh583->irq_lock);
/* Initialize all locals to 0 */
for (i = 0; i < MAX_INTERRUPT_MASKS; i++) {
ricoh583->irq_en_cache[i] = 0;
ricoh583->irq_en_reg[i] = 0;
}
ricoh583->intc_inten_cache = 0;
ricoh583->intc_inten_reg = 0;
for (i = 0; i < 2; i++) {
ricoh583->gpedge_cache[i] = 0;
ricoh583->gpedge_reg[i] = 0;
}
/* Interrupt enable register */
ricoh583->gpedge_add[0] = RICOH583_GPIO_GPEDGE2;
ricoh583->gpedge_add[1] = RICOH583_GPIO_GPEDGE1;
ricoh583->irq_en_add[0] = RICOH583_INT_EN_SYS1;
ricoh583->irq_en_add[1] = RICOH583_INT_EN_SYS2;
ricoh583->irq_en_add[2] = RICOH583_INT_EN_DCDC;
ricoh583->irq_en_add[3] = RICOH583_INT_EN_RTC;
ricoh583->irq_en_add[4] = RICOH583_INT_EN_ADC1;
ricoh583->irq_en_add[5] = RICOH583_INT_EN_ADC2;
ricoh583->irq_en_add[6] = RICOH583_INT_EN_ADC3;
ricoh583->irq_en_add[7] = RICOH583_INT_EN_GPIO;
/* Interrupt status monitor register */
ricoh583->irq_mon_add[0] = RICOH583_INT_MON_SYS1;
ricoh583->irq_mon_add[1] = RICOH583_INT_MON_SYS2;
ricoh583->irq_mon_add[2] = RICOH583_INT_MON_DCDC;
ricoh583->irq_mon_add[3] = RICOH583_INT_MON_RTC;
ricoh583->irq_mon_add[4] = RICOH583_INT_IR_ADCL;
ricoh583->irq_mon_add[5] = RICOH583_INT_IR_ADCH;
ricoh583->irq_mon_add[6] = RICOH583_INT_IR_ADCEND;
ricoh583->irq_mon_add[7] = RICOH583_INT_IR_GPIOF;
ricoh583->irq_mon_add[8] = RICOH583_INT_IR_GPIOR;
/* Interrupt status clear register */
ricoh583->irq_clr_add[0] = RICOH583_INT_IR_SYS1;
ricoh583->irq_clr_add[1] = RICOH583_INT_IR_SYS2;
ricoh583->irq_clr_add[2] = RICOH583_INT_IR_DCDC;
ricoh583->irq_clr_add[3] = RICOH583_INT_IR_RTC;
ricoh583->irq_clr_add[4] = RICOH583_INT_IR_ADCL;
ricoh583->irq_clr_add[5] = RICOH583_INT_IR_ADCH;
ricoh583->irq_clr_add[6] = RICOH583_INT_IR_ADCEND;
ricoh583->irq_clr_add[7] = RICOH583_INT_IR_GPIOF;
ricoh583->irq_clr_add[8] = RICOH583_INT_IR_GPIOR;
ricoh583->main_int_type[0] = SYS_INT;
ricoh583->main_int_type[1] = SYS_INT;
ricoh583->main_int_type[2] = DCDC_INT;
ricoh583->main_int_type[3] = RTC_INT;
ricoh583->main_int_type[4] = ADC_INT;
ricoh583->main_int_type[5] = ADC_INT;
ricoh583->main_int_type[6] = ADC_INT;
ricoh583->main_int_type[7] = GPIO_INT;
ricoh583->main_int_type[8] = GPIO_INT;
/* Initailize all int register to 0 */
for (i = 0; i < MAX_INTERRUPT_MASKS; i++) {
ret = __ricoh583_write(ricoh583->client,
ricoh583->irq_en_add[i],
ricoh583->irq_en_reg[i]);
if (ret < 0)
dev_err(ricoh583->dev, "Error in writing reg 0x%02x "
"error: %d\n", ricoh583->irq_en_add[i], ret);
}
for (i = 0; i < 2; i++) {
ret = __ricoh583_write(ricoh583->client,
ricoh583->gpedge_add[i],
ricoh583->gpedge_reg[i]);
if (ret < 0)
dev_err(ricoh583->dev, "Error in writing reg 0x%02x "
"error: %d\n", ricoh583->gpedge_add[i], ret);
}
ret = __ricoh583_write(ricoh583->client, RICOH583_INTC_INTEN, 0x0);
if (ret < 0)
dev_err(ricoh583->dev, "Error in writing reg 0x%02x "
"error: %d\n", RICOH583_INTC_INTEN, ret);
/* Clear all interrupts in case they woke up active. */
for (i = 0; i < 9; i++) {
ret = __ricoh583_write(ricoh583->client,
ricoh583->irq_clr_add[i], 0);
if (ret < 0)
dev_err(ricoh583->dev, "Error in writing reg 0x%02x "
"error: %d\n", ricoh583->irq_clr_add[i], ret);
}
ricoh583->irq_base = irq_base;
ricoh583->irq_chip.name = "ricoh583";
ricoh583->irq_chip.irq_mask = ricoh583_irq_mask;
ricoh583->irq_chip.irq_unmask = ricoh583_irq_unmask;
ricoh583->irq_chip.irq_bus_lock = ricoh583_irq_lock;
ricoh583->irq_chip.irq_bus_sync_unlock = ricoh583_irq_sync_unlock;
ricoh583->irq_chip.irq_set_type = ricoh583_irq_set_type;
for (i = 0; i < RICOH583_NR_IRQS; i++) {
int __irq = i + ricoh583->irq_base;
irq_set_chip_data(__irq, ricoh583);
irq_set_chip_and_handler(__irq, &ricoh583->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, ricoh583_irq, IRQF_ONESHOT,
"ricoh583", ricoh583);
if (ret < 0)
dev_err(ricoh583->dev, "Error in registering interrupt "
"error: %d\n", ret);
if (!ret) {
device_init_wakeup(ricoh583->dev, 1);
enable_irq_wake(irq);
}
return ret;
}
static int ricoh583_remove_subdev(struct device *dev, void *unused)
{
platform_device_unregister(to_platform_device(dev));
return 0;
}
static int ricoh583_remove_subdevs(struct ricoh583 *ricoh583)
{
return device_for_each_child(ricoh583->dev, NULL,
ricoh583_remove_subdev);
}
static int ricoh583_add_subdevs(struct ricoh583 *ricoh583,
struct ricoh583_platform_data *pdata)
{
struct ricoh583_subdev_info *subdev;
struct platform_device *pdev;
int i, ret = 0;
for (i = 0; i < pdata->num_subdevs; i++) {
subdev = &pdata->subdevs[i];
pdev = platform_device_alloc(subdev->name, subdev->id);
pdev->dev.parent = ricoh583->dev;
pdev->dev.platform_data = subdev->platform_data;
ret = platform_device_add(pdev);
if (ret)
goto failed;
}
return 0;
failed:
ricoh583_remove_subdevs(ricoh583);
return ret;
}
#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
#include <linux/seq_file.h>
static void print_regs(const char *header, struct seq_file *s,
struct i2c_client *client, int start_offset,
int end_offset)
{
uint8_t reg_val;
int i;
int ret;
seq_printf(s, "%s\n", header);
for (i = start_offset; i <= end_offset; ++i) {
ret = __ricoh583_read(client, i, &reg_val);
if (ret >= 0)
seq_printf(s, "Reg 0x%02x Value 0x%02x\n", i, reg_val);
}
seq_printf(s, "------------------\n");
}
static int dbg_tps_show(struct seq_file *s, void *unused)
{
struct ricoh583 *tps = s->private;
struct i2c_client *client = tps->client;
seq_printf(s, "RICOH583 Registers\n");
seq_printf(s, "------------------\n");
print_regs("System Regs", s, client, 0x0, 0xF);
print_regs("Power Control Regs", s, client, 0x10, 0x2B);
print_regs("DCDC1 Regs", s, client, 0x30, 0x43);
print_regs("DCDC1 Regs", s, client, 0x60, 0x63);
print_regs("LDO Regs", s, client, 0x50, 0x5F);
print_regs("LDO Regs", s, client, 0x64, 0x6D);
print_regs("ADC Regs", s, client, 0x70, 0x72);
print_regs("ADC Regs", s, client, 0x74, 0x8B);
print_regs("ADC Regs", s, client, 0x90, 0x96);
print_regs("GPIO Regs", s, client, 0xA0, 0xAC);
print_regs("INTC Regs", s, client, 0xAD, 0xAF);
print_regs("RTC Regs", s, client, 0xE0, 0xEE);
print_regs("RTC Regs", s, client, 0xF0, 0xF4);
return 0;
}
static int dbg_tps_open(struct inode *inode, struct file *file)
{
return single_open(file, dbg_tps_show, inode->i_private);
}
static const struct file_operations debug_fops = {
.open = dbg_tps_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static void __init ricoh583_debuginit(struct ricoh583 *tps)
{
(void)debugfs_create_file("ricoh583", S_IRUGO, NULL,
tps, &debug_fops);
}
#else
static void __init ricoh583_debuginit(struct ricoh583 *tpsi)
{
return;
}
#endif
static int ricoh583_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct ricoh583 *ricoh583;
struct ricoh583_platform_data *pdata = i2c->dev.platform_data;
int ret;
ricoh583 = kzalloc(sizeof(struct ricoh583), GFP_KERNEL);
if (ricoh583 == NULL)
return -ENOMEM;
ricoh583->client = i2c;
ricoh583->dev = &i2c->dev;
i2c_set_clientdata(i2c, ricoh583);
mutex_init(&ricoh583->io_lock);
ret = ricoh583_ext_power_init(ricoh583, pdata);
if (ret < 0)
goto err_irq_init;
if (i2c->irq) {
ret = ricoh583_irq_init(ricoh583, i2c->irq, pdata->irq_base);
if (ret) {
dev_err(&i2c->dev, "IRQ init failed: %d\n", ret);
goto err_irq_init;
}
}
ret = ricoh583_add_subdevs(ricoh583, pdata);
if (ret) {
dev_err(&i2c->dev, "add devices failed: %d\n", ret);
goto err_add_devs;
}
ricoh583_gpio_init(ricoh583, pdata);
ricoh583_debuginit(ricoh583);
ricoh583_i2c_client = i2c;
return 0;
err_add_devs:
if (i2c->irq)
free_irq(i2c->irq, ricoh583);
err_irq_init:
kfree(ricoh583);
return ret;
}
static int ricoh583_i2c_remove(struct i2c_client *i2c)
{
struct ricoh583 *ricoh583 = i2c_get_clientdata(i2c);
if (i2c->irq)
free_irq(i2c->irq, ricoh583);
ricoh583_remove_subdevs(ricoh583);
kfree(ricoh583);
return 0;
}
#ifdef CONFIG_PM
static int ricoh583_i2c_suspend(struct device *dev)
{
struct i2c_client *i2c = to_i2c_client(dev);
if (i2c->irq)
disable_irq(i2c->irq);
return 0;
}
static int ricoh583_i2c_resume(struct device *dev)
{
struct i2c_client *i2c = to_i2c_client(dev);
if (i2c->irq)
enable_irq(i2c->irq);
return 0;
}
static const struct dev_pm_ops ricoh583_pm_ops = {
.suspend = ricoh583_i2c_suspend,
.resume = ricoh583_i2c_resume,
};
#endif
static const struct i2c_device_id ricoh583_i2c_id[] = {
{"ricoh583", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, ricoh583_i2c_id);
static struct i2c_driver ricoh583_i2c_driver = {
.driver = {
.name = "ricoh583",
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &ricoh583_pm_ops,
#endif
},
.probe = ricoh583_i2c_probe,
.remove = ricoh583_i2c_remove,
.id_table = ricoh583_i2c_id,
};
static int __init ricoh583_i2c_init(void)
{
int ret = -ENODEV;
ret = i2c_add_driver(&ricoh583_i2c_driver);
if (ret != 0)
pr_err("Failed to register I2C driver: %d\n", ret);
return ret;
}
subsys_initcall(ricoh583_i2c_init);
static void __exit ricoh583_i2c_exit(void)
{
i2c_del_driver(&ricoh583_i2c_driver);
}
module_exit(ricoh583_i2c_exit);
MODULE_DESCRIPTION("RICOH583 multi-function core driver");
MODULE_LICENSE("GPL");