/*
* driver/mfd/ricoh619.c
*
* Core driver implementation to access RICOH R5T619 power management chip.
*
* Copyright (C) 2012-2013 RICOH COMPANY,LTD
*
* Based on code
* Copyright (C) 2011 NVIDIA Corporation
*
* 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, see .
*
*/
/*#define DEBUG 1*/
/*#define VERBOSE_DEBUG 1*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct sleep_control_data {
u8 reg_add;
};
#define SLEEP_INIT(_id, _reg) \
[RICOH619_DS_##_id] = {.reg_add = _reg}
static struct sleep_control_data sleep_data[] = {
SLEEP_INIT(DC1, 0x16),
SLEEP_INIT(DC2, 0x17),
SLEEP_INIT(DC3, 0x18),
SLEEP_INIT(DC4, 0x19),
SLEEP_INIT(DC5, 0x1A),
SLEEP_INIT(LDO1, 0x1B),
SLEEP_INIT(LDO2, 0x1C),
SLEEP_INIT(LDO3, 0x1D),
SLEEP_INIT(LDO4, 0x1E),
SLEEP_INIT(LDO5, 0x1F),
SLEEP_INIT(LDO6, 0x20),
SLEEP_INIT(LDO7, 0x21),
SLEEP_INIT(LDO8, 0x22),
SLEEP_INIT(LDO9, 0x23),
SLEEP_INIT(LDO10, 0x24),
SLEEP_INIT(PSO0, 0x25),
SLEEP_INIT(PSO1, 0x26),
SLEEP_INIT(PSO2, 0x27),
SLEEP_INIT(PSO3, 0x28),
SLEEP_INIT(PSO4, 0x29),
SLEEP_INIT(LDORTC1, 0x2A),
};
static inline int __ricoh61x_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, "ricoh61x: reg read reg=%x, val=%x\n",
reg, *val);
return 0;
}
static inline int __ricoh61x_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, "ricoh61x: reg read reg=%x, val=%x\n",
reg + i, *(val + i));
}
return 0;
}
static inline int __ricoh61x_write(struct i2c_client *client,
u8 reg, uint8_t val)
{
int ret;
dev_dbg(&client->dev, "ricoh61x: 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 __ricoh61x_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, "ricoh61x: 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;
}
static inline int set_bank_ricoh61x(struct device *dev, int bank)
{
struct ricoh61x *ricoh61x = dev_get_drvdata(dev);
int ret;
if (bank != (bank & 1))
return -EINVAL;
if (bank == ricoh61x->bank_num)
return 0;
ret = __ricoh61x_write(to_i2c_client(dev), RICOH61x_REG_BANKSEL, bank);
if (!ret)
ricoh61x->bank_num = bank;
return ret;
}
int ricoh61x_write(struct device *dev, u8 reg, uint8_t val)
{
struct ricoh61x *ricoh61x = dev_get_drvdata(dev);
int ret = 0;
mutex_lock(&ricoh61x->io_lock);
ret = set_bank_ricoh61x(dev, 0);
if (!ret)
ret = __ricoh61x_write(to_i2c_client(dev), reg, val);
mutex_unlock(&ricoh61x->io_lock);
return ret;
}
EXPORT_SYMBOL_GPL(ricoh61x_write);
int ricoh61x_write_bank1(struct device *dev, u8 reg, uint8_t val)
{
struct ricoh61x *ricoh61x = dev_get_drvdata(dev);
int ret = 0;
mutex_lock(&ricoh61x->io_lock);
ret = set_bank_ricoh61x(dev, 1);
if (!ret)
ret = __ricoh61x_write(to_i2c_client(dev), reg, val);
mutex_unlock(&ricoh61x->io_lock);
return ret;
}
EXPORT_SYMBOL_GPL(ricoh61x_write_bank1);
int ricoh61x_bulk_writes(struct device *dev, u8 reg, u8 len, uint8_t *val)
{
struct ricoh61x *ricoh61x = dev_get_drvdata(dev);
int ret = 0;
mutex_lock(&ricoh61x->io_lock);
ret = set_bank_ricoh61x(dev, 0);
if (!ret)
ret = __ricoh61x_bulk_writes(to_i2c_client(dev), reg, len, val);
mutex_unlock(&ricoh61x->io_lock);
return ret;
}
EXPORT_SYMBOL_GPL(ricoh61x_bulk_writes);
int ricoh61x_bulk_writes_bank1(struct device *dev, u8 reg, u8 len, uint8_t *val)
{
struct ricoh61x *ricoh61x = dev_get_drvdata(dev);
int ret = 0;
mutex_lock(&ricoh61x->io_lock);
ret = set_bank_ricoh61x(dev, 1);
if (!ret)
ret = __ricoh61x_bulk_writes(to_i2c_client(dev), reg, len, val);
mutex_unlock(&ricoh61x->io_lock);
return ret;
}
EXPORT_SYMBOL_GPL(ricoh61x_bulk_writes_bank1);
int ricoh61x_read(struct device *dev, u8 reg, uint8_t *val)
{
struct ricoh61x *ricoh61x = dev_get_drvdata(dev);
int ret = 0;
mutex_lock(&ricoh61x->io_lock);
ret = set_bank_ricoh61x(dev, 0);
if (!ret)
ret = __ricoh61x_read(to_i2c_client(dev), reg, val);
mutex_unlock(&ricoh61x->io_lock);
return ret;
}
EXPORT_SYMBOL_GPL(ricoh61x_read);
int ricoh61x_read_bank1(struct device *dev, u8 reg, uint8_t *val)
{
struct ricoh61x *ricoh61x = dev_get_drvdata(dev);
int ret = 0;
mutex_lock(&ricoh61x->io_lock);
ret = set_bank_ricoh61x(dev, 1);
if (!ret)
ret = __ricoh61x_read(to_i2c_client(dev), reg, val);
mutex_unlock(&ricoh61x->io_lock);
return ret;
}
EXPORT_SYMBOL_GPL(ricoh61x_read_bank1);
int ricoh61x_bulk_reads(struct device *dev, u8 reg, u8 len, uint8_t *val)
{
struct ricoh61x *ricoh61x = dev_get_drvdata(dev);
int ret = 0;
mutex_lock(&ricoh61x->io_lock);
ret = set_bank_ricoh61x(dev, 0);
if (!ret)
ret = __ricoh61x_bulk_reads(to_i2c_client(dev), reg, len, val);
mutex_unlock(&ricoh61x->io_lock);
return ret;
}
EXPORT_SYMBOL_GPL(ricoh61x_bulk_reads);
int ricoh61x_bulk_reads_bank1(struct device *dev, u8 reg, u8 len, uint8_t *val)
{
struct ricoh61x *ricoh61x = dev_get_drvdata(dev);
int ret = 0;
mutex_lock(&ricoh61x->io_lock);
ret = set_bank_ricoh61x(dev, 1);
if (!ret)
ret = __ricoh61x_bulk_reads(to_i2c_client(dev), reg, len, val);
mutex_unlock(&ricoh61x->io_lock);
return ret;
}
EXPORT_SYMBOL_GPL(ricoh61x_bulk_reads_bank1);
int ricoh61x_set_bits(struct device *dev, u8 reg, uint8_t bit_mask)
{
struct ricoh61x *ricoh61x = dev_get_drvdata(dev);
uint8_t reg_val;
int ret = 0;
mutex_lock(&ricoh61x->io_lock);
ret = set_bank_ricoh61x(dev, 0);
if (!ret) {
ret = __ricoh61x_read(to_i2c_client(dev), reg, ®_val);
if (ret)
goto out;
if ((reg_val & bit_mask) != bit_mask) {
reg_val |= bit_mask;
ret = __ricoh61x_write(to_i2c_client(dev), reg,
reg_val);
}
}
out:
mutex_unlock(&ricoh61x->io_lock);
return ret;
}
EXPORT_SYMBOL_GPL(ricoh61x_set_bits);
int ricoh61x_clr_bits(struct device *dev, u8 reg, uint8_t bit_mask)
{
struct ricoh61x *ricoh61x = dev_get_drvdata(dev);
uint8_t reg_val;
int ret = 0;
mutex_lock(&ricoh61x->io_lock);
ret = set_bank_ricoh61x(dev, 0);
if (!ret) {
ret = __ricoh61x_read(to_i2c_client(dev), reg, ®_val);
if (ret)
goto out;
if (reg_val & bit_mask) {
reg_val &= ~bit_mask;
ret = __ricoh61x_write(to_i2c_client(dev), reg,
reg_val);
}
}
out:
mutex_unlock(&ricoh61x->io_lock);
return ret;
}
EXPORT_SYMBOL_GPL(ricoh61x_clr_bits);
int ricoh61x_update(struct device *dev, u8 reg, uint8_t val, uint8_t mask)
{
struct ricoh61x *ricoh61x = dev_get_drvdata(dev);
uint8_t reg_val;
int ret = 0;
mutex_lock(&ricoh61x->io_lock);
ret = set_bank_ricoh61x(dev, 0);
if (!ret) {
ret = __ricoh61x_read(ricoh61x->client, reg, ®_val);
if (ret)
goto out;
if ((reg_val & mask) != val) {
reg_val = (reg_val & ~mask) | (val & mask);
ret = __ricoh61x_write(ricoh61x->client, reg, reg_val);
}
}
out:
mutex_unlock(&ricoh61x->io_lock);
return ret;
}
EXPORT_SYMBOL_GPL(ricoh61x_update);
int ricoh61x_update_bank1(struct device *dev, u8 reg, uint8_t val, uint8_t mask)
{
struct ricoh61x *ricoh61x = dev_get_drvdata(dev);
uint8_t reg_val;
int ret = 0;
mutex_lock(&ricoh61x->io_lock);
ret = set_bank_ricoh61x(dev, 1);
if (!ret) {
ret = __ricoh61x_read(ricoh61x->client, reg, ®_val);
if (ret)
goto out;
if ((reg_val & mask) != val) {
reg_val = (reg_val & ~mask) | (val & mask);
ret = __ricoh61x_write(ricoh61x->client, reg, reg_val);
}
}
out:
mutex_unlock(&ricoh61x->io_lock);
return ret;
}
static struct i2c_client *ricoh61x_i2c_client;
int ricoh619_cc_sum_clear(void)
{
int ret;
uint8_t cc_clr[4] = {0, 0, 0, 0}; /* temporary box */
if (!ricoh61x_i2c_client)
return -EINVAL;
/* CC_pause enter */
ret = __ricoh61x_write(ricoh61x_i2c_client, RICOH61x_CC_CTRL, 0x01);
if (ret < 0)
dev_err(&ricoh61x_i2c_client->dev,
"Error in writing CC_CTRL_REG\n");
/* Write CC_SUM */
ret = __ricoh61x_bulk_writes(ricoh61x_i2c_client, RICOH61x_CC_SUMREG3, 4, cc_clr);
if (ret < 0)
dev_err(&ricoh61x_i2c_client->dev,
"Error in writing CC_SUM_REG\n");
/* CC_pause exit */
ret = __ricoh61x_write(ricoh61x_i2c_client, RICOH61x_CC_CTRL, 0);
if (ret < 0)
dev_err(&ricoh61x_i2c_client->dev,
"Error in writing CC_CTRL_REG\n");
return 0;
}
int ricoh619_power_off(void)
{
int ret;
uint8_t reg_val;
reg_val = g_soc;
reg_val &= 0x7f;
if (!ricoh61x_i2c_client)
return -EINVAL;
ricoh619_cc_sum_clear();
ret = __ricoh61x_write(ricoh61x_i2c_client, RICOH61x_PSWR, reg_val);
if (ret < 0)
dev_err(&ricoh61x_i2c_client->dev,
"Error in writing PSWR_REG\n");
if (g_fg_on_mode == 0) {
/* Clear RICOH61x_FG_CTRL 0x01 bit */
ret = __ricoh61x_read(ricoh61x_i2c_client,
RICOH61x_FG_CTRL, ®_val);
if (reg_val & 0x01) {
reg_val &= ~0x01;
ret = __ricoh61x_write(ricoh61x_i2c_client,
RICOH61x_FG_CTRL, reg_val);
}
if (ret < 0)
dev_err(&ricoh61x_i2c_client->dev,
"Error in writing FG_CTRL\n");
}
/* set rapid timer 300 min */
ret = __ricoh61x_read(ricoh61x_i2c_client,
TIMSET_REG, ®_val);
reg_val |= 0x03;
ret = __ricoh61x_write(ricoh61x_i2c_client,
TIMSET_REG, reg_val);
if (ret < 0)
dev_err(&ricoh61x_i2c_client->dev,
"Error in writing the TIMSET_Reg\n");
/* Disable all Interrupt */
__ricoh61x_write(ricoh61x_i2c_client, RICOH61x_INTC_INTEN, 0);
/* Not repeat power ON after power off(Power Off/N_OE) */
__ricoh61x_write(ricoh61x_i2c_client, RICOH61x_PWR_REP_CNT, 0x0);
/* Power OFF */
__ricoh61x_write(ricoh61x_i2c_client, RICOH61x_PWR_SLP_CNT, 0x1);
return 0;
}
#include
#include
int ricoh619_charger_detect(void)
{
uint8_t reg_val=0;
int result = NO_CHARGER_PLUGGED;
struct ricoh61x *ricoh61x = i2c_get_clientdata(ricoh61x_i2c_client);
int ret;
int iInINT = in_interrupt();
//printk("%s(),suspend=%d,atomic=%d,interrupt=%d\n",__FUNCTION__,ricoh61x->iIsSuspending,in_atomic()?1:0,in_interrupt()?1:0);
if(iInINT) {
ret = __ricoh61x_read (ricoh61x_i2c_client, CHGSTATE_REG, ®_val);
}
else {
ret = ricoh61x_read (ricoh61x->dev, CHGSTATE_REG, ®_val);
}
if (0xC0 & reg_val) {
int retryMax = 50;
int retryCnt = 0;
result = UNKOWN_CHARGER;
do {
if(retryCnt++>=retryMax) {
printk(KERN_ERR"%s() : retry read BAT_REL_SEL_REG cnt >=%d \n",
__FUNCTION__,retryMax);
break;
}
if(iInINT) {
ret = __ricoh61x_read (ricoh61x_i2c_client, BAT_REL_SEL_REG, ®_val);
}
else {
ret = ricoh61x_read (ricoh61x->dev, BAT_REL_SEL_REG, ®_val);
}
if(0!=ret) {
printk(KERN_ERR"%s() :read BAT_REL_SEL_REG failed!!,%s\n",
__FUNCTION__,ricoh61x->iIsSuspending?"suspending":"normal");
}
else {
if(0x04 != (reg_val&0x0C)) {
// not in Detecting charger state ...
if (0x20 == (reg_val&0x30)) {// DCP detected.
result = DCP_CHARGER;
//printk("DCP charger\n");
}
else if (0x10 == (reg_val&0x30)) {// CDP detected.
result = CDP_CHARGER;
//printk("CDP charger\n");
}
else if (0x00 == (reg_val&0x30)) {// SDP detected.
result = SDP_CHARGER;
//printk("SDP charger\n");
}
else {
//printk("Other charger\n");
}
break;
}
}
if(ricoh61x->iIsSuspending || iInINT ) {
mdelay (50);
}
else {
msleep (50);
}
} while (1);
}
return result;
}
int ricoh619_restart(void)
{
if (!ricoh61x_i2c_client)
return -EINVAL;
/* Repeat power ON after power off(Power Off/N_OE) */
__ricoh61x_write(ricoh61x_i2c_client, RICOH61x_PWR_REP_CNT, 0x5);//500ms off time .
/* Power OFF */
__ricoh61x_write(ricoh61x_i2c_client, RICOH61x_PWR_SLP_CNT, 0x1);
return 0;
}
static int ricoh61x_gpio_get(struct gpio_chip *gc, unsigned offset)
{
struct ricoh61x *ricoh61x = container_of(gc, struct ricoh61x,
gpio_chip);
uint8_t val;
int ret;
ret = ricoh61x_read(ricoh61x->dev, RICOH61x_GPIO_MON_IOIN, &val);
if (ret < 0)
return ret;
return ((val & (0x1 << offset)) != 0);
}
static void ricoh61x_gpio_set(struct gpio_chip *gc, unsigned offset,
int value)
{
struct ricoh61x *ricoh61x = container_of(gc, struct ricoh61x,
gpio_chip);
if (value)
ricoh61x_set_bits(ricoh61x->dev, RICOH61x_GPIO_IOOUT,
1 << offset);
else
ricoh61x_clr_bits(ricoh61x->dev, RICOH61x_GPIO_IOOUT,
1 << offset);
}
static int ricoh61x_gpio_input(struct gpio_chip *gc, unsigned offset)
{
struct ricoh61x *ricoh61x = container_of(gc, struct ricoh61x,
gpio_chip);
return ricoh61x_clr_bits(ricoh61x->dev, RICOH61x_GPIO_IOSEL,
1 << offset);
}
static int ricoh61x_gpio_output(struct gpio_chip *gc, unsigned offset,
int value)
{
struct ricoh61x *ricoh61x = container_of(gc, struct ricoh61x,
gpio_chip);
ricoh61x_gpio_set(gc, offset, value);
return ricoh61x_set_bits(ricoh61x->dev, RICOH61x_GPIO_IOSEL,
1 << offset);
}
static int ricoh61x_gpio_to_irq(struct gpio_chip *gc, unsigned off)
{
struct ricoh61x *ricoh61x = container_of(gc, struct ricoh61x,
gpio_chip);
if ((off >= 0) && (off < 8))
return ricoh61x->irq_base + RICOH61x_IRQ_GPIO0 + off;
return -EIO;
}
static void __devinit ricoh61x_gpio_init(struct ricoh61x *ricoh61x,
struct ricoh619_platform_data *pdata)
{
int ret;
int i;
struct ricoh619_gpio_init_data *ginit;
if (pdata->gpio_base <= 0)
return;
for (i = 0; i < pdata->num_gpioinit_data; ++i) {
ginit = &pdata->gpio_init_data[i];
if (!ginit->init_apply)
continue;
if (ginit->output_mode_en) {
/* GPIO output mode */
if (ginit->output_val)
/* output H */
ret = ricoh61x_set_bits(ricoh61x->dev,
RICOH61x_GPIO_IOOUT, 1 << i);
else
/* output L */
ret = ricoh61x_clr_bits(ricoh61x->dev,
RICOH61x_GPIO_IOOUT, 1 << i);
if (!ret)
ret = ricoh61x_set_bits(ricoh61x->dev,
RICOH61x_GPIO_IOSEL, 1 << i);
} else
/* GPIO input mode */
ret = ricoh61x_clr_bits(ricoh61x->dev,
RICOH61x_GPIO_IOSEL, 1 << i);
/* if LED function enabled in OTP */
if (ginit->led_mode) {
/* LED Mode 1 */
if (i == 0) /* GP0 */
ret = ricoh61x_set_bits(ricoh61x->dev,
RICOH61x_GPIO_LED_FUNC,
0x04 | (ginit->led_func & 0x03));
if (i == 1) /* GP1 */
ret = ricoh61x_set_bits(ricoh61x->dev,
RICOH61x_GPIO_LED_FUNC,
0x40 | (ginit->led_func & 0x03) << 4);
}
if (ret < 0)
dev_err(ricoh61x->dev, "Gpio %d init "
"dir configuration failed: %d\n", i, ret);
}
ricoh61x->gpio_chip.owner = THIS_MODULE;
ricoh61x->gpio_chip.label = ricoh61x->client->name;
ricoh61x->gpio_chip.dev = ricoh61x->dev;
ricoh61x->gpio_chip.base = pdata->gpio_base;
ricoh61x->gpio_chip.ngpio = RICOH61x_NR_GPIO;
ricoh61x->gpio_chip.can_sleep = 1;
ricoh61x->gpio_chip.direction_input = ricoh61x_gpio_input;
ricoh61x->gpio_chip.direction_output = ricoh61x_gpio_output;
ricoh61x->gpio_chip.set = ricoh61x_gpio_set;
ricoh61x->gpio_chip.get = ricoh61x_gpio_get;
ricoh61x->gpio_chip.to_irq = ricoh61x_gpio_to_irq;
ret = gpiochip_add(&ricoh61x->gpio_chip);
if (ret)
dev_warn(ricoh61x->dev, "GPIO registration failed: %d\n", ret);
#if 0 //[
// initial ricoh watchdog
ret = ricoh61x_write(ricoh61x->dev, RICOH61x_PWR_WD, 0x06);
ret = ricoh61x_set_bits(ricoh61x->dev, RICOH61x_INT_EN_SYS, 0x40);
#endif //]
// set vindac
ret = ricoh61x_write(ricoh61x->dev, 0x03, 0x00);//set VINDAC 3.0V .
}
static int ricoh61x_remove_subdev(struct device *dev, void *unused)
{
platform_device_unregister(to_platform_device(dev));
return 0;
}
static int ricoh61x_remove_subdevs(struct ricoh61x *ricoh61x)
{
return device_for_each_child(ricoh61x->dev, NULL,
ricoh61x_remove_subdev);
}
static int __devinit ricoh61x_add_subdevs(struct ricoh61x *ricoh61x,
struct ricoh619_platform_data *pdata)
{
struct ricoh619_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 = ricoh61x->dev;
pdev->dev.platform_data = subdev->platform_data;
ret = platform_device_add(pdev);
if (ret)
goto failed;
}
return 0;
failed:
ricoh61x_remove_subdevs(ricoh61x);
return ret;
}
#ifdef CONFIG_DEBUG_FS
#include
#include
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 = __ricoh61x_read(client, i, ®_val);
if (ret >= 0)
seq_printf(s, "Reg 0x%02x Value 0x%02x\n", i, reg_val);
}
seq_printf(s, "------------------\n");
}
static int dbg_ricoh_show(struct seq_file *s, void *unused)
{
struct ricoh61x *ricoh = s->private;
struct i2c_client *client = ricoh->client;
seq_printf(s, "RICOH61x Registers\n");
seq_printf(s, "------------------\n");
print_regs("System Regs", s, client, 0x0, 0x05);
print_regs("Power Control Regs", s, client, 0x07, 0x2B);
print_regs("DCDC Regs", s, client, 0x2C, 0x43);
print_regs("LDO Regs", s, client, 0x44, 0x61);
print_regs("ADC Regs", s, client, 0x64, 0x8F);
print_regs("GPIO Regs", s, client, 0x90, 0x98);
print_regs("INTC Regs", s, client, 0x9C, 0x9E);
print_regs("RTC Regs", s, client, 0xA0, 0xAF);
print_regs("OPT Regs", s, client, 0xB0, 0xB1);
print_regs("CHG Regs", s, client, 0xB2, 0xDF);
print_regs("FUEL Regs", s, client, 0xE0, 0xFC);
return 0;
}
static int dbg_ricoh_open(struct inode *inode, struct file *file)
{
return single_open(file, dbg_ricoh_show, inode->i_private);
}
static const struct file_operations debug_fops = {
.open = dbg_ricoh_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static void __init ricoh61x_debuginit(struct ricoh61x *ricoh)
{
(void)debugfs_create_file("ricoh61x", S_IRUGO, NULL,
ricoh, &debug_fops);
}
#else
static void print_regs(const char *header, struct i2c_client *client,
int start_offset, int end_offset)
{
uint8_t reg_val;
int i;
int ret;
printk(KERN_INFO "%s\n", header);
for (i = start_offset; i <= end_offset; ++i) {
ret = __ricoh61x_read(client, i, ®_val);
if (ret >= 0)
printk(KERN_INFO "Reg 0x%02x Value 0x%02x\n",
i, reg_val);
}
printk(KERN_INFO "------------------\n");
}
static void __init ricoh61x_debuginit(struct ricoh61x *ricoh)
{
struct i2c_client *client = ricoh->client;
printk(KERN_INFO "RICOH61x Registers\n");
printk(KERN_INFO "------------------\n");
print_regs("System Regs", client, 0x0, 0x05);
print_regs("Power Control Regs", client, 0x07, 0x2B);
print_regs("DCDC Regs", client, 0x2C, 0x43);
print_regs("LDO Regs", client, 0x44, 0x5C);
print_regs("ADC Regs", client, 0x64, 0x8F);
print_regs("GPIO Regs", client, 0x90, 0x9B);
print_regs("INTC Regs", client, 0x9C, 0x9E);
print_regs("OPT Regs", client, 0xB0, 0xB1);
print_regs("CHG Regs", client, 0xB2, 0xDF);
print_regs("FUEL Regs", client, 0xE0, 0xFC);
return 0;
}
#endif
static void __devinit ricoh61x_noe_init(struct ricoh61x *ricoh)
{
struct i2c_client *client = ricoh->client;
/* N_OE timer setting to 128mS */
__ricoh61x_write(client, RICOH61x_PWR_NOE_TIMSET, 0x0);
/* power on/off timer setting to on 1s, off 8S */
__ricoh61x_write(client, RICOH61x_PWR_ON_TIMSET, 0x5B);
#if 0 // do not set repeat power on bit to enable force power off by long press power key function.
/* Repeat power ON after reset (Power Off/N_OE) */
__ricoh61x_write(client, RICOH61x_PWR_REP_CNT, 0x1);
#endif
}
static int ricoh61x_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct ricoh61x *ricoh61x;
struct ricoh619_platform_data *pdata = client->dev.platform_data;
int ret;
printk(KERN_INFO "PMU: %s:\n", __func__);
ricoh61x = kzalloc(sizeof(struct ricoh61x), GFP_KERNEL);
if (ricoh61x == NULL)
return -ENOMEM;
ricoh61x->client = client;
ricoh61x->dev = &client->dev;
i2c_set_clientdata(client, ricoh61x);
mutex_init(&ricoh61x->io_lock);
ricoh61x->bank_num = 0;
if (pdata->init_port) {
/* For init PMIC_IRQ port */
ret = pdata->init_port(client->irq);
}
if (client->irq) {
ret = ricoh61x_irq_init(ricoh61x, client->irq, pdata->irq_base);
if (ret) {
dev_err(&client->dev, "IRQ init failed: %d\n", ret);
goto err_irq_init;
}
}
ret = ricoh61x_add_subdevs(ricoh61x, pdata);
if (ret) {
dev_err(&client->dev, "add devices failed: %d\n", ret);
goto err_add_devs;
}
ricoh61x_noe_init(ricoh61x);
ricoh61x_gpio_init(ricoh61x, pdata);
ricoh61x_debuginit(ricoh61x);
ricoh61x_i2c_client = client;
return 0;
err_add_devs:
if (client->irq)
ricoh61x_irq_exit(ricoh61x);
err_irq_init:
kfree(ricoh61x);
return ret;
}
static int __devexit ricoh61x_i2c_remove(struct i2c_client *client)
{
struct ricoh61x *ricoh61x = i2c_get_clientdata(client);
if (client->irq)
ricoh61x_irq_exit(ricoh61x);
ricoh61x_remove_subdevs(ricoh61x);
kfree(ricoh61x);
return 0;
}
#ifdef CONFIG_PM
static int ricoh61x_i2c_suspend(struct i2c_client *client, pm_message_t state)
{
struct ricoh61x *ricoh61x = i2c_get_clientdata(client);
ricoh61x->iIsSuspending = 1;
#if 0
printk(KERN_INFO "PMU: %s:\n", __func__);
if (client->irq)
disable_irq(client->irq);
#endif
return 0;
}
int pwrkey_wakeup;
static int ricoh61x_i2c_resume(struct i2c_client *client)
{
struct ricoh61x *ricoh61x = i2c_get_clientdata(client);
uint8_t reg_val;
int ret;
// printk(KERN_INFO "PMU: %s:\n", __func__);
/* Disable all Interrupt */
__ricoh61x_write(client, RICOH61x_INTC_INTEN, 0x0);
ret = __ricoh61x_read(client, RICOH61x_INT_IR_SYS, ®_val);
if (reg_val & 0x01) { /* If PWR_KEY wakeup */
printk(KERN_INFO "PMU: %s: PWR_KEY Wakeup\n", __func__);
pwrkey_wakeup = 1;
/* Clear PWR_KEY IRQ */
__ricoh61x_write(client, RICOH61x_INT_IR_SYS, 0x0);
}
// enable_irq(client->irq);
/* Enable all Interrupt */
__ricoh61x_write(client, RICOH61x_INTC_INTEN, 0xff);
ricoh61x->iIsSuspending = 0;
return 0;
}
#endif
static const struct i2c_device_id ricoh61x_i2c_id[] = {
{"ricoh619", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, ricoh61x_i2c_id);
static struct i2c_driver ricoh61x_i2c_driver = {
.driver = {
.name = "ricoh619",
.owner = THIS_MODULE,
},
.probe = ricoh61x_i2c_probe,
.remove = __devexit_p(ricoh61x_i2c_remove),
#ifdef CONFIG_PM
.suspend = ricoh61x_i2c_suspend,
.resume = ricoh61x_i2c_resume,
#endif
.id_table = ricoh61x_i2c_id,
};
static int __init ricoh61x_i2c_init(void)
{
int ret = -ENODEV;
printk(KERN_INFO "PMU: %s:\n", __func__);
ret = i2c_add_driver(&ricoh61x_i2c_driver);
if (ret != 0)
pr_err("Failed to register I2C driver: %d\n", ret);
return ret;
}
subsys_initcall(ricoh61x_i2c_init);
static void __exit ricoh61x_i2c_exit(void)
{
i2c_del_driver(&ricoh61x_i2c_driver);
}
module_exit(ricoh61x_i2c_exit);
MODULE_DESCRIPTION("RICOH R5T619 PMU multi-function core driver");
MODULE_LICENSE("GPL");