--- /dev/null
+#include <linux/regulator/machine.h>
+#include <linux/mfd/ricoh619.h>
+#include <linux/regulator/ricoh619-regulator.h>
+#include <linux/power/ricoh619_battery.h>
+#include <linux/rtc/rtc-ricoh619.h>
+#include <mach/sram.h>
+#include <linux/platform_device.h>
+
+#include <mach/gpio.h>
+#include <mach/iomux.h>
+#include <mach/board.h>
+
+#ifdef CONFIG_MFD_RICOH619
+
+static struct ricoh619 *Ricoh619;
+static int ricoh619_pre_init(struct ricoh619 *ricoh619){
+
+ Ricoh619 = ricoh619;
+ printk("%s,line=%d\n", __func__,__LINE__);
+ uint8_t cont;
+ int ret;
+
+ ret = ricoh619_clr_bits(ricoh619->dev,RICOH619_PWR_REP_CNT,(1 << 0)); //set restart when power off
+
+ /**********set dcdc mode when in sleep mode **************/
+
+ /*****************************************************/
+
+ return 0;
+ }
+static int ricoh619_post_init(struct ricoh619 *ricoh619)
+{
+ struct regulator *dcdc;
+ struct regulator *ldo;
+ int i = 0,ret=0;
+ printk("%s,line=%d\n", __func__,__LINE__);
+
+ #ifndef CONFIG_RK_CONFIG
+ g_pmic_type = PMIC_TYPE_RICOH619;
+ #endif
+ printk("%s:g_pmic_type=%d\n",__func__,g_pmic_type);
+
+ for(i = 0; i < ARRAY_SIZE(ricoh619_dcdc_info); i++)
+ {
+
+ if(ricoh619_dcdc_info[i].min_uv == 0 && ricoh619_dcdc_info[i].max_uv == 0)
+ continue;
+ dcdc =regulator_get(NULL, ricoh619_dcdc_info[i].name);
+ regulator_set_voltage(dcdc, ricoh619_dcdc_info[i].min_uv, ricoh619_dcdc_info[i].max_uv);
+ regulator_set_suspend_voltage(dcdc, ricoh619_dcdc_info[i].suspend_vol);
+ regulator_set_mode(dcdc, REGULATOR_MODE_NORMAL);
+ regulator_enable(dcdc);
+ printk("%s %s =%duV end\n", __func__,ricoh619_dcdc_info[i].name, regulator_get_voltage(dcdc));
+ regulator_put(dcdc);
+ udelay(100);
+ }
+
+ for(i = 0; i < ARRAY_SIZE(ricoh619_ldo_info); i++)
+ {
+ if(ricoh619_ldo_info[i].min_uv == 0 && ricoh619_ldo_info[i].max_uv == 0)
+ continue;
+ ldo =regulator_get(NULL, ricoh619_ldo_info[i].name);
+ regulator_set_voltage(ldo, ricoh619_ldo_info[i].min_uv, ricoh619_ldo_info[i].max_uv);
+ regulator_enable(ldo);
+ printk("%s %s =%duV end\n", __func__,ricoh619_ldo_info[i].name, regulator_get_voltage(ldo));
+ regulator_put(ldo);
+ }
+
+ #ifdef CONFIG_RK_CONFIG
+ if(sram_gpio_init(get_port_config(pmic_slp).gpio, &pmic_sleep) < 0){
+ printk(KERN_ERR "sram_gpio_init failed\n");
+ return -EINVAL;
+ }
+ if(port_output_init(pmic_slp, 0, "pmic_slp") < 0){
+ printk(KERN_ERR "port_output_init failed\n");
+ return -EINVAL;
+ }
+ #else
+ if(sram_gpio_init(PMU_POWER_SLEEP, &pmic_sleep) < 0){
+ printk(KERN_ERR "sram_gpio_init failed\n");
+ return -EINVAL;
+ }
+ gpio_request(PMU_POWER_SLEEP, "NULL");
+ gpio_direction_output(PMU_POWER_SLEEP, GPIO_LOW);
+
+ #endif
+
+ ret = ricoh619_clr_bits(ricoh619->dev,0xb1,(7<< 0)); //set vbatdec voltage 3.0v
+ ret = ricoh619_set_bits(ricoh619->dev,0xb1,(3<< 0)); //set vbatdec voltage 3.0v
+
+ printk("%s,line=%d END\n", __func__,__LINE__);
+
+ return 0;
+}
+static struct regulator_consumer_supply ricoh619_dcdc1_supply[] = {
+ {
+ .supply = "ricoh_dc1",
+ },
+ {
+ .supply = "vdd_cpu",
+ },
+
+};
+static struct regulator_consumer_supply ricoh619_dcdc2_supply[] = {
+ {
+ .supply = "ricoh_dc2",
+ },
+ {
+ .supply = "vdd_core",
+ },
+
+};
+static struct regulator_consumer_supply ricoh619_dcdc3_supply[] = {
+ {
+ .supply = "ricoh_dc3",
+ },
+};
+
+static struct regulator_consumer_supply ricoh619_dcdc4_supply[] = {
+ {
+ .supply = "ricoh_dc4",
+ },
+};
+
+static struct regulator_consumer_supply ricoh619_dcdc5_supply[] = {
+ {
+ .supply = "ricoh_dc5",
+ },
+};
+
+static struct regulator_consumer_supply ricoh619_ldo1_supply[] = {
+ {
+ .supply = "ricoh_ldo1",
+ },
+};
+static struct regulator_consumer_supply ricoh619_ldo2_supply[] = {
+ {
+ .supply = "ricoh_ldo2",
+ },
+};
+
+static struct regulator_consumer_supply ricoh619_ldo3_supply[] = {
+ {
+ .supply = "ricoh_ldo3",
+ },
+};
+static struct regulator_consumer_supply ricoh619_ldo4_supply[] = {
+ {
+ .supply = "ricoh_ldo4",
+ },
+};
+static struct regulator_consumer_supply ricoh619_ldo5_supply[] = {
+ {
+ .supply = "ricoh_ldo5",
+ },
+};
+static struct regulator_consumer_supply ricoh619_ldo6_supply[] = {
+ {
+ .supply = "ricoh_ldo6",
+ },
+};
+static struct regulator_consumer_supply ricoh619_ldo7_supply[] = {
+ {
+ .supply = "ricoh_ldo7",
+ },
+};
+static struct regulator_consumer_supply ricoh619_ldo8_supply[] = {
+ {
+ .supply = "ricoh_ldo8",
+ },
+};
+static struct regulator_consumer_supply ricoh619_ldo9_supply[] = {
+ {
+ .supply = "ricoh_ldo9",
+ },
+};
+static struct regulator_consumer_supply ricoh619_ldo10_supply[] = {
+ {
+ .supply = "ricoh_ldo10",
+ },
+};
+static struct regulator_consumer_supply ricoh619_ldortc1_supply[] = {
+ {
+ .supply = "ricoh_ldortc1",
+ },
+};
+
+static struct regulator_init_data ricoh619_dcdc1 = {
+ .constraints = {
+ .name = "RICOH_DC1",
+ .min_uV = 600000,
+ .max_uV = 3500000,
+ .apply_uV = 1,
+ .always_on = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST,
+
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ricoh619_dcdc1_supply),
+ .consumer_supplies = ricoh619_dcdc1_supply,
+};
+
+/* */
+static struct regulator_init_data ricoh619_dcdc2 = {
+ .constraints = {
+ .name = "RICOH_DC2",
+ .min_uV = 600000,
+ .max_uV = 3500000,
+ .apply_uV = 1,
+
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST,
+
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ricoh619_dcdc2_supply),
+ .consumer_supplies = ricoh619_dcdc2_supply,
+};
+
+/* */
+static struct regulator_init_data ricoh619_dcdc3 = {
+ .constraints = {
+ .name = "RICOH_DC3",
+ .min_uV = 600000,
+ .max_uV = 3500000,
+ .apply_uV = 1,
+
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST,
+
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ricoh619_dcdc3_supply),
+ .consumer_supplies = ricoh619_dcdc3_supply,
+};
+
+static struct regulator_init_data ricoh619_dcdc4 = {
+ .constraints = {
+ .name = "RICOH_DC4",
+ .min_uV = 600000,
+ .max_uV = 3500000,
+ .apply_uV = 1,
+
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST,
+
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ricoh619_dcdc4_supply),
+ .consumer_supplies = ricoh619_dcdc4_supply,
+};
+static struct regulator_init_data ricoh619_dcdc5 = {
+ .constraints = {
+ .name = "RICOH_DC5",
+ .min_uV = 600000,
+ .max_uV = 3500000,
+ .apply_uV = 1,
+
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST,
+
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ricoh619_dcdc5_supply),
+ .consumer_supplies = ricoh619_dcdc5_supply,
+};
+
+static struct regulator_init_data ricoh619_ldo1 = {
+ .constraints = {
+ .name = "RICOH_LDO1",
+ .min_uV = 900000,
+ .max_uV = 3500000,
+ .apply_uV = 1,
+
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ricoh619_ldo1_supply),
+ .consumer_supplies = ricoh619_ldo1_supply,
+};
+
+/* */
+static struct regulator_init_data ricoh619_ldo2 = {
+ .constraints = {
+ .name = "RICOH_LDO2",
+ .min_uV = 900000,
+ .max_uV = 3500000,
+ .apply_uV = 1,
+
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ricoh619_ldo2_supply),
+ .consumer_supplies = ricoh619_ldo2_supply,
+};
+
+/* */
+static struct regulator_init_data ricoh619_ldo3 = {
+ .constraints = {
+ .name = "RICOH_LDO3",
+ .min_uV = 900000,
+ .max_uV = 3500000,
+ .apply_uV = 1,
+
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ricoh619_ldo3_supply),
+ .consumer_supplies = ricoh619_ldo3_supply,
+};
+
+/* */
+static struct regulator_init_data ricoh619_ldo4 = {
+ .constraints = {
+ .name = "RICOH_LDO4",
+ .min_uV = 900000,
+ .max_uV = 3500000,
+ .apply_uV = 1,
+
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ricoh619_ldo4_supply),
+ .consumer_supplies = ricoh619_ldo4_supply,
+};
+
+/* */
+static struct regulator_init_data ricoh619_ldo5 = {
+ .constraints = {
+ .name = "RICOH_LDO5",
+ .min_uV = 900000,
+ .max_uV = 3500000,
+ .apply_uV = 1,
+
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ricoh619_ldo5_supply),
+ .consumer_supplies = ricoh619_ldo5_supply,
+};
+
+static struct regulator_init_data ricoh619_ldo6 = {
+ .constraints = {
+ .name = "RICOH_LDO6",
+ .min_uV = 900000,
+ .max_uV = 3500000,
+ .apply_uV = 1,
+
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ricoh619_ldo6_supply),
+ .consumer_supplies = ricoh619_ldo6_supply,
+};
+
+static struct regulator_init_data ricoh619_ldo7 = {
+ .constraints = {
+ .name = "RICOH_LDO7",
+ .min_uV = 900000,
+ .max_uV = 3500000,
+ .apply_uV = 1,
+
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ricoh619_ldo7_supply),
+ .consumer_supplies = ricoh619_ldo7_supply,
+};
+
+static struct regulator_init_data ricoh619_ldo8 = {
+ .constraints = {
+ .name = "RICOH_LDO8",
+ .min_uV = 900000,
+ .max_uV = 3500000,
+ .apply_uV = 1,
+
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ricoh619_ldo8_supply),
+ .consumer_supplies = ricoh619_ldo8_supply,
+};
+
+static struct regulator_init_data ricoh619_ldo9 = {
+ .constraints = {
+ .name = "RICOH_LDO9",
+ .min_uV = 900000,
+ .max_uV = 3500000,
+ .apply_uV = 1,
+
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ricoh619_ldo9_supply),
+ .consumer_supplies = ricoh619_ldo9_supply,
+};
+
+static struct regulator_init_data ricoh619_ldo10 = {
+ .constraints = {
+ .name = "RICOH_LDO10",
+ .min_uV = 900000,
+ .max_uV = 3500000,
+ .apply_uV = 1,
+
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ricoh619_ldo10_supply),
+ .consumer_supplies = ricoh619_ldo10_supply,
+};
+
+/* */
+static struct regulator_init_data ricoh619_ldortc1 = {
+ .constraints = {
+ .name = "RICOH_LDORTC1",
+ .min_uV = 1700000,
+ .max_uV = 3500000,
+ .apply_uV = 1,
+
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ricoh619_ldortc1_supply),
+ .consumer_supplies = ricoh619_ldortc1_supply,
+};
+
+static struct ricoh619_battery_platform_data ricoh619_power_battery = {
+ .irq = IRQ_BOARD_BASE,
+ .alarm_vol_mv = 3300,
+ .multiple =0,
+ .monitor_time = 1,
+};
+
+static struct rtc_time rk_time = { // 2012.1.1 12:00:00 Saturday
+ .tm_wday = 6,
+ .tm_year = 111,
+ .tm_mon = 0,
+ .tm_mday = 1,
+ .tm_hour = 12,
+ .tm_min = 0,
+ .tm_sec = 0,
+};
+
+static struct ricoh619_rtc_platform_data ricoh619_rtc_data = {
+ .irq = IRQ_BOARD_BASE ,
+ .time = &rk_time,
+};
+
+#define RICOH_REG(_id, _data) \
+{ \
+ .id = RICOH619_ID_##_id, \
+ .name = "ricoh619-regulator", \
+ .platform_data = _data, \
+} \
+
+static struct ricoh619_pwrkey_platform_data ricoh619_pwrkey_data= {
+ .irq = IRQ_BOARD_BASE + RICOH619_IRQ_POWER_ON,
+ .delay_ms = 20,
+};
+
+static struct ricoh619_subdev_info ricoh619_devs[] = {
+ RICOH_REG(DC1, &ricoh619_dcdc1),
+ RICOH_REG(DC2, &ricoh619_dcdc2),
+ RICOH_REG(DC3, &ricoh619_dcdc3),
+ RICOH_REG(DC4, &ricoh619_dcdc4),
+ RICOH_REG(DC5, &ricoh619_dcdc5),
+
+ RICOH_REG(LDO1, &ricoh619_ldo1),
+ RICOH_REG(LDO2, &ricoh619_ldo2),
+ RICOH_REG(LDO3, &ricoh619_ldo3),
+ RICOH_REG(LDO4, &ricoh619_ldo4),
+ RICOH_REG(LDO5, &ricoh619_ldo5),
+ RICOH_REG(LDO6, &ricoh619_ldo6),
+ RICOH_REG(LDO7, &ricoh619_ldo7),
+ RICOH_REG(LDO8, &ricoh619_ldo8),
+ RICOH_REG(LDO9, &ricoh619_ldo9),
+ RICOH_REG(LDO10, &ricoh619_ldo10),
+ RICOH_REG(LDORTC1, &ricoh619_ldortc1),
+
+ {
+ .id = 16,
+ .name ="ricoh619-battery",
+ .platform_data = &ricoh619_power_battery,
+ },
+
+ {
+ .id = 17,
+ .name ="rtc_ricoh619",
+ .platform_data = &ricoh619_rtc_data,
+ },
+
+ {
+ .id = 18,
+ .name ="ricoh619-pwrkey",
+ .platform_data = &ricoh619_pwrkey_data,
+ },
+
+};
+
+#define RICOH_GPIO_INIT(_init_apply, _output_mode, _output_val, _led_mode, _led_func) \
+{ \
+ .output_mode_en = _output_mode, \
+ .output_val = _output_val, \
+ .init_apply = _init_apply, \
+ .led_mode = _led_mode, \
+ .led_func = _led_func, \
+} \
+
+struct ricoh619_gpio_init_data ricoh_gpio_data[] = {
+ RICOH_GPIO_INIT(0, 1, 0, 0, 1),
+ RICOH_GPIO_INIT(0, 0, 0, 0, 0),
+ RICOH_GPIO_INIT(0, 0, 0, 0, 0),
+ RICOH_GPIO_INIT(0, 0, 0, 0, 0),
+ RICOH_GPIO_INIT(0, 0, 0, 0, 0),
+};
+
+static struct ricoh619_platform_data ricoh619_data={
+ .irq_base = IRQ_BOARD_BASE,
+// .init_port = RICOH619_HOST_IRQ,
+ .num_subdevs = ARRAY_SIZE(ricoh619_devs),
+ .subdevs = ricoh619_devs,
+ .pre_init = ricoh619_pre_init,
+ .post_init = ricoh619_post_init,
+ //.gpio_base = RICOH619_GPIO_EXPANDER_BASE,
+ .gpio_init_data = ricoh_gpio_data,
+ .num_gpioinit_data = ARRAY_SIZE(ricoh_gpio_data),
+ .enable_shutdown_pin = 0,
+};
+
+void __sramfunc board_pmu_ricoh619_suspend(void)
+{
+ #ifdef CONFIG_CLK_SWITCH_TO_32K
+ sram_gpio_set_value(pmic_sleep, GPIO_HIGH);
+ #endif
+}
+void __sramfunc board_pmu_ricoh619_resume(void)
+{
+ #ifdef CONFIG_CLK_SWITCH_TO_32K
+ sram_gpio_set_value(pmic_sleep, GPIO_LOW);
+ sram_udelay(2000);
+ #endif
+}
+
+
+#endif
+
+
+
+
#include <linux/mfd/tps65910.h>
#include <linux/regulator/act8846.h>
#include <linux/mfd/rk808.h>
+#include <linux/mfd/ricoh619.h>
#include <linux/regulator/rk29-pwm-regulator.h>
#ifdef CONFIG_CW2015_BATTERY
#include "board-pmu-rk808.c"
#endif
+#ifdef CONFIG_MFD_RICOH619
+#define PMU_POWER_SLEEP RK30_PIN0_PA1
+#define RICOH619_HOST_IRQ RK30_PIN0_PB3
+
+static struct pmu_info ricoh619_dcdc_info[] = {
+ {
+ .name = "vdd_cpu", //arm
+ .min_uv = 1000000,
+ .max_uv = 1000000,
+ .suspend_vol = 900000,
+ },
+ {
+ .name = "vdd_core", //logic
+ .min_uv = 1000000,
+ .max_uv = 1000000,
+ .suspend_vol = 900000,
+ },
+
+ {
+ .name = "ricoh_dc3", //vcc18
+ .min_uv = 1800000,
+ .max_uv = 1800000,
+ .suspend_vol = 1800000,
+ },
+
+ {
+ .name = "ricoh_dc4", //vccio
+ .min_uv = 3300000,
+ .max_uv = 3300000,
+ .suspend_vol = 3300000,
+ },
+
+ {
+ .name = "ricoh_dc5", //ddr
+ .min_uv = 1200000,
+ .max_uv = 1200000,
+ .suspend_vol = 1200000,
+ },
+
+};
+static struct pmu_info ricoh619_ldo_info[] = {
+ {
+ .name = "ricoh_ldo1", //vcc30
+ .min_uv = 3000000,
+ .max_uv = 3000000,
+ },
+ {
+ .name = "ricoh_ldo2", //vcca33
+ .min_uv = 3300000,
+ .max_uv = 3300000,
+ },
+ {
+ .name = "ricoh_ldo3", //vcctp
+ .min_uv = 3300000,
+ .max_uv = 3300000,
+ },
+ {
+ .name = "ricoh_ldo4", //vccsd
+ .min_uv = 3300000,
+ .max_uv = 3300000,
+ },
+ {
+ .name = "ricoh_ldo5", //vcc18_cif
+ .min_uv = 1800000,
+ .max_uv = 1800000,
+ },
+ {
+ .name = "ricoh_ldo6", //vdd12
+ .min_uv = 1200000,
+ .max_uv = 1200000,
+ },
+ {
+ .name = "ricoh_ldo7", //vcc28_cif
+ .min_uv = 2800000,
+ .max_uv = 2800000,
+ },
+ {
+ .name = "ricoh_ldo8", //vcc25
+ .min_uv = 2500000,
+ .max_uv = 2500000,
+ },
+ {
+ .name = "ricoh_ldo9", //vdd10
+ .min_uv = 1000000,
+ .max_uv = 1000000,
+ },
+ {
+ .name = "ricoh_ldo10", //vcca18
+ .min_uv = 1800000,
+ .max_uv = 1800000,
+ },
+
+ };
+
+#include "board-pmu-ricoh619.c"
+#endif
+
static struct i2c_board_info __initdata i2c1_info[] = {
},
#endif
+#if defined (CONFIG_MFD_RICOH619)
+ {
+ .type = "ricoh619",
+ .addr = 0x32,
+ .flags = 0,
+ .irq = RICOH619_HOST_IRQ,
+ .platform_data=&ricoh619_data,
+ },
+#endif
+
#if defined (CONFIG_RTC_HYM8563)
{
.type = "rtc_hym8563",
void __sramfunc board_pmu_suspend(void)
{
- #if defined (CONFIG_MFD_WM831X_I2C)
- if(pmic_is_wm8326())
- board_pmu_wm8326_suspend();
- #endif
- #if defined (CONFIG_MFD_TPS65910)
- if(pmic_is_tps65910())
- board_pmu_tps65910_suspend();
- #endif
- #if defined (CONFIG_REGULATOR_ACT8846)
- if(pmic_is_act8846())
- board_pmu_act8846_suspend();
- #endif
- #if defined (CONFIG_MFD_RK808)
- if(pmic_is_rk808())
- board_pmu_rk808_suspend();
- #endif
+#if defined (CONFIG_MFD_WM831X_I2C)
+ if(pmic_is_wm8326())
+ board_pmu_wm8326_suspend();
+#endif
+#if defined (CONFIG_MFD_TPS65910)
+ if(pmic_is_tps65910())
+ board_pmu_tps65910_suspend();
+#endif
+#if defined (CONFIG_REGULATOR_ACT8846)
+ if(pmic_is_act8846())
+ board_pmu_act8846_suspend();
+#endif
+#if defined (CONFIG_MFD_RK808)
+ if(pmic_is_rk808())
+ board_pmu_rk808_suspend();
+#endif
+#if defined (CONFIG_MFD_RICOH619)
+ if(pmic_is_ricoh619())
+ board_pmu_ricoh619_suspend();
+#endif
}
void __sramfunc board_pmu_resume(void)
{
- #if defined (CONFIG_MFD_WM831X_I2C)
- if(pmic_is_wm8326())
- board_pmu_wm8326_resume();
- #endif
- #if defined (CONFIG_MFD_TPS65910)
- if(pmic_is_tps65910())
- board_pmu_tps65910_resume();
- #endif
- #if defined (CONFIG_REGULATOR_ACT8846)
- if(pmic_is_act8846())
- board_pmu_act8846_resume();
- #endif
- #if defined (CONFIG_MFD_RK808)
- if(pmic_is_rk808())
- board_pmu_rk808_resume();
- #endif
+#if defined (CONFIG_MFD_WM831X_I2C)
+ if(pmic_is_wm8326())
+ board_pmu_wm8326_resume();
+#endif
+#if defined (CONFIG_MFD_TPS65910)
+ if(pmic_is_tps65910())
+ board_pmu_tps65910_resume();
+#endif
+#if defined (CONFIG_REGULATOR_ACT8846)
+ if(pmic_is_act8846())
+ board_pmu_act8846_resume();
+#endif
+#if defined (CONFIG_MFD_RK808)
+ if(pmic_is_rk808())
+ board_pmu_rk808_resume();
+#endif
+#if defined (CONFIG_MFD_RICOH619)
+ if(pmic_is_ricoh619())
+ board_pmu_ricoh619_resume();
+#endif
}
rk808_device_shutdown();//rk808 shutdown
}
#endif
+ #if defined(CONFIG_MFD_RICOH619)
+ if(pmic_is_ricoh619()){
+ ricoh619_power_off(); //ricoh619 shutdown
+ }
+ #endif
gpio_direction_output(POWER_ON_PIN, GPIO_LOW);
while (1);
PMIC_TYPE_ACT8931 =3,
PMIC_TYPE_ACT8846 =3,
PMIC_TYPE_RK808 =4,
+ PMIC_TYPE_RICOH619 =5,
PMIC_TYPE_MAX,
};
extern __sramdata int g_pmic_type;
#define pmic_is_act8931() (g_pmic_type == PMIC_TYPE_ACT8931)
#define pmic_is_act8846() (g_pmic_type == PMIC_TYPE_ACT8846)
#define pmic_is_rk808() (g_pmic_type == PMIC_TYPE_RK808)
+#define pmic_is_ricoh619() (g_pmic_type == PMIC_TYPE_RICOH619)
struct pmu_info {
char *name;
To compile this driver as a module, choose M here. The module will
be called twl6030_pwrbutton.
+config INPUT_RICOH619_PWRKEY
+ tristate "RICOH RC5T619 PMU PWRKEY driver"
+ depends on MFD_RICOH619
+ default n
+ help
+ If you say yes here you get support for the RICOH RC5T619 PWRKEY module.
+
+ This driver can also be built as a module. If so, the module
+ will be called rc5t619-pwrkey.
+
config INPUT_TWL4030_VIBRA
tristate "Support for TWL4030 Vibrator"
depends on TWL4030_CORE
obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o
obj-$(CONFIG_INPUT_YEALINK) += yealink.o
obj-$(CONFIG_INPUT_LPSENSOR_AL3006) += al3006.o
+obj-$(CONFIG_INPUT_RICOH619_PWRKEY) += ricoh619-pwrkey.o
+
--- /dev/null
+/*\r
+* driver/input/misc/ricoh619-pwrkey.c\r
+*\r
+* Power Key driver for RICOH RC5T619 power management chip.\r
+*\r
+* Copyright (C) 2012-2013 RICOH COMPANY,LTD\r
+*\r
+*\r
+* This program is free software; you can redistribute it and/or modify\r
+* it under the terms of the GNU General Public License as published by\r
+* the Free Software Foundation; either version 2 of the License, or\r
+* (at your option) any later version.\r
+*\r
+* This program is distributed in the hope that it will be useful, but WITHOUT\r
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
+* more details.\r
+*\r
+* You should have received a copy of the GNU General Public License\r
+* along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+*\r
+*/\r
+#include <linux/module.h>\r
+#include <linux/init.h>\r
+#include <linux/kernel.h>\r
+#include <linux/errno.h>\r
+#include <linux/input.h>\r
+#include <linux/interrupt.h>\r
+#include <linux/platform_device.h>\r
+#include <linux/mfd/ricoh619.h>\r
+#include <linux/spinlock.h>\r
+#include <linux/timer.h>\r
+#include <linux/pm.h>\r
+#include <linux/slab.h>\r
+#include <linux/pm_runtime.h>\r
+#include <linux/workqueue.h>\r
+#include <linux/gpio.h>\r
+\r
+#include <linux/mfd/ricoh619.h>\r
+\r
+#define RICOH619_ONKEY_TRIGGER_LEVEL 0\r
+#define RICOH619_ONKEY_OFF_IRQ 0\r
+\r
+struct ricoh619_pwrkey {\r
+ struct device * dev;\r
+ struct input_dev *pwr;\r
+ #if RICOH619_ONKEY_TRIGGER_LEVEL\r
+ struct timer_list timer;\r
+ #endif\r
+ struct workqueue_struct * workqueue;\r
+ struct work_struct work;\r
+ unsigned long delay;\r
+ int key_irq;\r
+ bool pressed_first;\r
+ struct ricoh619_pwrkey_platform_data *pdata;\r
+ spinlock_t lock;\r
+};\r
+\r
+struct ricoh619_pwrkey *g_pwrkey;\r
+//static int test_set = 0;\r
+\r
+#if RICOH619_ONKEY_TRIGGER_LEVEL\r
+void ricoh619_pwrkey_timer(unsigned long t)\r
+{\r
+ queue_work(g_pwrkey->workqueue, &g_pwrkey->work);\r
+}\r
+#endif\r
+\r
+extern int pwrkey_wakeup;\r
+static void ricoh619_irq_work(struct work_struct * work)\r
+{\r
+ unsigned long flags;\r
+ uint8_t val;\r
+\r
+// printk("PMU: %s: \n",__func__);\r
+ //spin_lock_irqsave(&g_pwrkey->lock, flags);\r
+\r
+ if(pwrkey_wakeup){\r
+// printk("PMU: %s: pwrkey_wakeup\n",__func__);\r
+ pwrkey_wakeup = 0;\r
+ input_event(g_pwrkey->pwr, EV_KEY, KEY_POWER, 1);\r
+ input_event(g_pwrkey->pwr, EV_SYN, 0, 0);\r
+ input_event(g_pwrkey->pwr, EV_KEY, KEY_POWER, 0);\r
+ input_event(g_pwrkey->pwr, EV_SYN, 0, 0);\r
+ \r
+ return;\r
+ }\r
+ ricoh619_read(g_pwrkey->dev->parent, RICOH619_INT_MON_SYS, &val);\r
+ dev_dbg(g_pwrkey->dev, "pwrkey is pressed?(0x%x): 0x%x\n", RICOH619_INT_MON_SYS, val);\r
+// printk("PMU: %s: val=0x%x\n",__func__,val);\r
+ val &= 0x1;\r
+ if(val){\r
+ #if (RICOH619_ONKEY_TRIGGER_LEVEL)\r
+ g_pwrkey->timer.expires = jiffies + g_pwrkey->delay;\r
+ dd_timer(&g_pwrkey->timer);\r
+ #endif\r
+ if (!g_pwrkey->pressed_first){\r
+ g_pwrkey->pressed_first = true;\r
+// printk("PMU1: %s: Power Key!!!\n",__func__);\r
+ //input_report_key(g_pwrkey->pwr, KEY_POWER, 1);\r
+ //input_sync(g_pwrkey->pwr);\r
+ input_event(g_pwrkey->pwr, EV_KEY, KEY_POWER, 1);\r
+ input_event(g_pwrkey->pwr, EV_SYN, 0, 0);\r
+ }\r
+ }\r
+ else{\r
+ if (g_pwrkey->pressed_first){\r
+// printk("PMU2: %s: Power Key!!!\n",__func__);\r
+ //input_report_key(g_pwrkey->pwr, KEY_POWER, 0);\r
+ //input_sync(g_pwrkey->pwr);\r
+ input_event(g_pwrkey->pwr, EV_KEY, KEY_POWER, 0);\r
+ input_event(g_pwrkey->pwr, EV_SYN, 0, 0);\r
+ }\r
+ g_pwrkey->pressed_first = false;\r
+ }\r
+\r
+ //spin_unlock_irqrestore(&g_pwrkey->lock, flags);\r
+}\r
+extern struct ricoh619 *g_ricoh619;\r
+static irqreturn_t pwrkey_irq(int irq, void *_pwrkey)\r
+{\r
+// printk("PMU: %s: \n",__func__);\r
+ struct ricoh619 *ricoh619 = g_ricoh619;\r
+ #if (RICOH619_ONKEY_TRIGGER_LEVEL)\r
+ g_pwrkey->timer.expires = jiffies + g_pwrkey->delay;\r
+ add_timer(&g_pwrkey->timer);\r
+ #else\r
+ queue_work(g_pwrkey->workqueue, &g_pwrkey->work);\r
+ #endif\r
+ ricoh619_clr_bits(g_ricoh619->dev, RICOH619_INT_IR_SYS, 0x1); //clr power-on interrupt\r
+ return IRQ_HANDLED;\r
+}\r
+\r
+#if RICOH619_ONKEY_OFF_IRQ\r
+static irqreturn_t pwrkey_irq_off(int irq, void *_pwrkey)\r
+{\r
+ dev_warn(g_pwrkey->dev, "ONKEY is pressed long time!\n");\r
+ return IRQ_HANDLED;\r
+}\r
+#endif\r
+\r
+static int __devinit ricoh619_pwrkey_probe(struct platform_device *pdev)\r
+{\r
+ struct input_dev *pwr;\r
+ int key_irq;\r
+ int err;\r
+ struct ricoh619_pwrkey *pwrkey;\r
+ struct ricoh619_pwrkey_platform_data *pdata = pdev->dev.platform_data;\r
+ uint8_t val;\r
+\r
+// printk("PMU: %s: \n",__func__);\r
+\r
+ if (!pdata) {\r
+ dev_err(&pdev->dev, "power key platform data not supplied\n");\r
+ return -EINVAL;\r
+ }\r
+ key_irq = (pdata->irq + RICOH619_IRQ_POWER_ON);\r
+ printk(KERN_INFO "PMU1: %s: key_irq=%d\n", __func__, key_irq);\r
+ pwrkey = kzalloc(sizeof(*pwrkey), GFP_KERNEL);\r
+ if (!pwrkey)\r
+ return -ENOMEM;\r
+\r
+ pwrkey->dev = &pdev->dev;\r
+ pwrkey->pdata = pdata;\r
+ pwrkey->pressed_first = false;\r
+ pwrkey->delay = HZ / 1000 * pdata->delay_ms;\r
+ g_pwrkey = pwrkey;\r
+ pwr = input_allocate_device();\r
+ if (!pwr) {\r
+ dev_dbg(&pdev->dev, "Can't allocate power button\n");\r
+ err = -ENOMEM;\r
+ goto free_pwrkey;\r
+ }\r
+ input_set_capability(pwr, EV_KEY, KEY_POWER);\r
+ pwr->name = "ricoh619_pwrkey";\r
+ pwr->phys = "ricoh619_pwrkey/input0";\r
+ pwr->dev.parent = &pdev->dev;\r
+\r
+ #if RICOH619_ONKEY_TRIGGER_LEVEL\r
+ init_timer(&pwrkey->timer);\r
+ pwrkey->timer.function = ricoh619_pwrkey_timer;\r
+ #endif\r
+\r
+ spin_lock_init(&pwrkey->lock);\r
+ err = input_register_device(pwr);\r
+ if (err) {\r
+ dev_dbg(&pdev->dev, "Can't register power key: %d\n", err);\r
+ goto free_input_dev;\r
+ }\r
+ pwrkey->key_irq = key_irq;\r
+ pwrkey->pwr = pwr;\r
+ platform_set_drvdata(pdev, pwrkey);\r
+\r
+ // Check if power-key is pressed at boot up\r
+ err = ricoh619_read(pwrkey->dev->parent, RICOH619_INT_MON_SYS, &val);\r
+ if (err < 0) {\r
+ dev_err(&pdev->dev, "Key-press status at boot failed rc=%d\n",\r
+ err);\r
+ goto unreg_input_dev;\r
+ }\r
+ val &= 0x1;\r
+ if (val) {\r
+ input_report_key(pwrkey->pwr, KEY_POWER, 1);\r
+// printk(KERN_INFO "******KEY_POWER:1\n");\r
+ input_sync(pwrkey->pwr);\r
+ pwrkey->pressed_first = true;\r
+ }\r
+\r
+ #if !(RICOH619_ONKEY_TRIGGER_LEVEL)\r
+ ricoh619_set_bits(pwrkey->dev->parent, RICOH619_PWR_IRSEL, 0x1); //trigger both edge\r
+ #endif\r
+\r
+ err = request_threaded_irq(key_irq, NULL, pwrkey_irq,\r
+ IRQF_ONESHOT, "ricoh619_pwrkey", pwrkey);\r
+ if (err < 0) {\r
+ dev_err(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",\r
+ key_irq, err);\r
+ goto unreg_input_dev;\r
+ }\r
+\r
+ #if RICOH619_ONKEY_OFF_IRQ\r
+ err = request_threaded_irq(key_irq + RICOH619_IRQ_ONKEY_OFF, NULL,\r
+ pwrkey_irq_off, IRQF_ONESHOT,\r
+ "ricoh619_pwrkey_off", pwrkey);\r
+ if (err < 0) {\r
+ dev_err(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",\r
+ key_irq + RICOH619_IRQ_ONKEY_OFF, err);\r
+ free_irq(key_irq, pwrkey);\r
+ goto unreg_input_dev;\r
+ }\r
+ #endif\r
+\r
+ pwrkey->workqueue = create_singlethread_workqueue("ricoh619_pwrkey");\r
+ INIT_WORK(&pwrkey->work, ricoh619_irq_work);\r
+\r
+ /* Enable power key IRQ */\r
+ /* trigger both edge */\r
+ ricoh619_set_bits(pwrkey->dev->parent, RICOH619_PWR_IRSEL, 0x1);\r
+ /* Enable system interrupt */\r
+ ricoh619_set_bits(pwrkey->dev->parent, RICOH619_INTC_INTEN, 0x1);\r
+ /* Enable power-on interrupt */\r
+ ricoh619_set_bits(pwrkey->dev->parent, RICOH619_INT_EN_SYS, 0x1);\r
+// printk(KERN_INFO "PMU: %s is OK!\n", __func__);\r
+ return 0;\r
+\r
+unreg_input_dev:\r
+ input_unregister_device(pwr);\r
+ pwr = NULL;\r
+\r
+free_input_dev:\r
+ input_free_device(pwr);\r
+ free_pwrkey:\r
+ kfree(pwrkey);\r
+\r
+ return err;\r
+}\r
+\r
+static int __devexit ricoh619_pwrkey_remove(struct platform_device *pdev)\r
+{\r
+ struct ricoh619_pwrkey *pwrkey = platform_get_drvdata(pdev);\r
+\r
+ flush_workqueue(pwrkey->workqueue);\r
+ destroy_workqueue(pwrkey->workqueue);\r
+ free_irq(pwrkey->key_irq, pwrkey);\r
+ input_unregister_device(pwrkey->pwr);\r
+ kfree(pwrkey);\r
+\r
+ return 0;\r
+}\r
+\r
+#ifdef CONFIG_PM\r
+static int ricoh619_pwrkey_suspend(struct device *dev)\r
+{\r
+ struct ricoh619_pwrkey *info = dev_get_drvdata(dev);\r
+\r
+// printk(KERN_INFO "PMU: %s\n", __func__);\r
+\r
+ if (info->key_irq)\r
+ disable_irq(info->key_irq);\r
+ cancel_work_sync(&info->work);\r
+ flush_workqueue(info->workqueue);\r
+\r
+ return 0;\r
+}\r
+\r
+static int ricoh619_pwrkey_resume(struct device *dev)\r
+{\r
+ struct ricoh619_pwrkey *info = dev_get_drvdata(dev);\r
+\r
+// printk(KERN_INFO "PMU: %s\n", __func__);\r
+ queue_work(info->workqueue, &info->work);\r
+ if (info->key_irq)\r
+ enable_irq(info->key_irq);\r
+\r
+ return 0;\r
+}\r
+\r
+static const struct dev_pm_ops ricoh619_pwrkey_pm_ops = {\r
+ .suspend = ricoh619_pwrkey_suspend,\r
+ .resume = ricoh619_pwrkey_resume,\r
+};\r
+#endif\r
+\r
+static struct platform_driver ricoh619_pwrkey_driver = {\r
+ .probe = ricoh619_pwrkey_probe,\r
+ .remove = __devexit_p(ricoh619_pwrkey_remove),\r
+ .driver = {\r
+ .name = "ricoh619-pwrkey",\r
+ .owner = THIS_MODULE,\r
+#ifdef CONFIG_PM\r
+ .pm = &ricoh619_pwrkey_pm_ops,\r
+#endif\r
+ },\r
+};\r
+\r
+static int __init ricoh619_pwrkey_init(void)\r
+{\r
+ return platform_driver_register(&ricoh619_pwrkey_driver);\r
+}\r
+subsys_initcall_sync(ricoh619_pwrkey_init);\r
+\r
+static void __exit ricoh619_pwrkey_exit(void)\r
+{\r
+ platform_driver_unregister(&ricoh619_pwrkey_driver);\r
+}\r
+module_exit(ricoh619_pwrkey_exit);\r
+\r
+\r
+MODULE_ALIAS("platform:ricoh619-pwrkey");\r
+MODULE_AUTHOR("zhangqing <zhangqing@rock-chips.com>");\r
+MODULE_DESCRIPTION("ricoh619 Power Key");\r
+MODULE_LICENSE("GPL v2");
\ No newline at end of file
if you say yes here you get support for the RK808 series of
Power Management chips.
+config MFD_RICOH619
+ bool "Ricoh RC5T619 Power Management system device"
+ depends on I2C && GPIOLIB && GENERIC_HARDIRQS
+ select MFD_CORE
+ default n
+ help
+ If you say yes here you get support for the RICOH619 Power
+ Management system device.
+ This driver provides common support for accessing the device,
+ additional drivers must be enabled in order to use the
+ functionality of the device.
+
config AIC3262_CODEC
bool "Support TI Codec Aic3262"
select MFD_CORE
obj-$(CONFIG_MFD_RK610) += rk610-core.o
obj-$(CONFIG_MFD_RK808) += rk808.o rk808-irq.o
obj-$(CONFIG_MFD_RK616) += rk616-core.o
+obj-$(CONFIG_MFD_RICOH619) += ricoh619.o ricoh619-irq.o
--- /dev/null
+/*
+ * driver/mfd/ricoh619-irq.c
+ *
+ * Interrupt driver for RICOH RC5T619 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 <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/i2c.h>
+#include <linux/mfd/ricoh619.h>
+
+
+enum int_type {
+ SYS_INT = 0x1,
+ DCDC_INT = 0x2,
+ RTC_INT = 0x4,
+ ADC_INT = 0x8,
+ GPIO_INT = 0x10,
+ CHG_INT = 0x40,
+};
+
+static int gpedge_add[] = {
+ RICOH619_GPIO_GPEDGE1,
+ RICOH619_GPIO_GPEDGE2
+};
+
+static int irq_en_add[] = {
+ RICOH619_INT_EN_SYS,
+ RICOH619_INT_EN_DCDC,
+ RICOH619_INT_EN_RTC,
+ RICOH619_INT_EN_ADC1,
+ RICOH619_INT_EN_ADC2,
+ RICOH619_INT_EN_ADC3,
+ RICOH619_INT_EN_GPIO,
+ RICOH619_INT_EN_GPIO2,
+ RICOH619_INT_MSK_CHGCTR,
+ RICOH619_INT_MSK_CHGSTS1,
+ RICOH619_INT_MSK_CHGSTS2,
+ RICOH619_INT_MSK_CHGERR,
+ RICOH619_INT_MSK_CHGEXTIF
+};
+
+static int irq_mon_add[] = {
+ RICOH619_INT_IR_SYS, //RICOH619_INT_MON_SYS,
+ RICOH619_INT_IR_DCDC, //RICOH619_INT_MON_DCDC,
+ RICOH619_INT_IR_RTC, //RICOH619_INT_MON_RTC,
+ RICOH619_INT_IR_ADCL,
+ RICOH619_INT_IR_ADCH,
+ RICOH619_INT_IR_ADCEND,
+ RICOH619_INT_IR_GPIOR,
+ RICOH619_INT_IR_GPIOF,
+ RICOH619_INT_IR_CHGCTR, //RICOH619_INT_MON_CHGCTR,
+ RICOH619_INT_IR_CHGSTS1, //RICOH619_INT_MON_CHGSTS1,
+ RICOH619_INT_IR_CHGSTS2, //RICOH619_INT_MON_CHGSTS2,
+ RICOH619_INT_IR_CHGERR, //RICOH619_INT_MON_CHGERR
+ RICOH619_INT_IR_CHGEXTIF //RICOH619_INT_MON_CHGEXTIF
+};
+
+static int irq_clr_add[] = {
+ RICOH619_INT_IR_SYS,
+ RICOH619_INT_IR_DCDC,
+ RICOH619_INT_IR_RTC,
+ RICOH619_INT_IR_ADCL,
+ RICOH619_INT_IR_ADCH,
+ RICOH619_INT_IR_ADCEND,
+ RICOH619_INT_IR_GPIOR,
+ RICOH619_INT_IR_GPIOF,
+ RICOH619_INT_IR_CHGCTR,
+ RICOH619_INT_IR_CHGSTS1,
+ RICOH619_INT_IR_CHGSTS2,
+ RICOH619_INT_IR_CHGERR,
+ RICOH619_INT_IR_CHGEXTIF
+};
+
+static int main_int_type[] = {
+ SYS_INT,
+ DCDC_INT,
+ RTC_INT,
+ ADC_INT,
+ ADC_INT,
+ ADC_INT,
+ GPIO_INT,
+ GPIO_INT,
+ CHG_INT,
+ CHG_INT,
+ CHG_INT,
+ CHG_INT,
+ CHG_INT,
+};
+
+struct ricoh619_irq_data {
+ u8 int_type;
+ u8 master_bit;
+ u8 int_en_bit;
+ u8 mask_reg_index;
+ int grp_index;
+};
+
+#define RICOH619_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 ricoh619_irq_data ricoh619_irqs[RICOH619_NR_IRQS] = {
+ [RICOH619_IRQ_POWER_ON] = RICOH619_IRQ(SYS_INT, 0, 0, 0, 0),
+ [RICOH619_IRQ_EXTIN] = RICOH619_IRQ(SYS_INT, 0, 1, 1, 0),
+ [RICOH619_IRQ_PRE_VINDT] = RICOH619_IRQ(SYS_INT, 0, 2, 2, 0),
+ [RICOH619_IRQ_PREOT] = RICOH619_IRQ(SYS_INT, 0, 3, 3, 0),
+ [RICOH619_IRQ_POWER_OFF] = RICOH619_IRQ(SYS_INT, 0, 4, 4, 0),
+ [RICOH619_IRQ_NOE_OFF] = RICOH619_IRQ(SYS_INT, 0, 5, 5, 0),
+ [RICOH619_IRQ_WD] = RICOH619_IRQ(SYS_INT, 0, 6, 6, 0),
+
+ [RICOH619_IRQ_DC1LIM] = RICOH619_IRQ(DCDC_INT, 1, 0, 0, 1),
+ [RICOH619_IRQ_DC2LIM] = RICOH619_IRQ(DCDC_INT, 1, 1, 1, 1),
+ [RICOH619_IRQ_DC3LIM] = RICOH619_IRQ(DCDC_INT, 1, 2, 2, 1),
+ [RICOH619_IRQ_DC4LIM] = RICOH619_IRQ(DCDC_INT, 1, 3, 3, 1),
+ [RICOH619_IRQ_DC5LIM] = RICOH619_IRQ(DCDC_INT, 1, 4, 4, 1),
+
+ [RICOH619_IRQ_CTC] = RICOH619_IRQ(RTC_INT, 2, 0, 0, 2),
+ [RICOH619_IRQ_DALE] = RICOH619_IRQ(RTC_INT, 2, 1, 6, 2),
+
+ [RICOH619_IRQ_ILIMLIR] = RICOH619_IRQ(ADC_INT, 3, 0, 0, 3),
+ [RICOH619_IRQ_VBATLIR] = RICOH619_IRQ(ADC_INT, 3, 1, 1, 3),
+ [RICOH619_IRQ_VADPLIR] = RICOH619_IRQ(ADC_INT, 3, 2, 2, 3),
+ [RICOH619_IRQ_VUSBLIR] = RICOH619_IRQ(ADC_INT, 3, 3, 3, 3),
+ [RICOH619_IRQ_VSYSLIR] = RICOH619_IRQ(ADC_INT, 3, 4, 4, 3),
+ [RICOH619_IRQ_VTHMLIR] = RICOH619_IRQ(ADC_INT, 3, 5, 5, 3),
+ [RICOH619_IRQ_AIN1LIR] = RICOH619_IRQ(ADC_INT, 3, 6, 6, 3),
+ [RICOH619_IRQ_AIN0LIR] = RICOH619_IRQ(ADC_INT, 3, 7, 7, 3),
+
+ [RICOH619_IRQ_ILIMHIR] = RICOH619_IRQ(ADC_INT, 3, 8, 0, 4),
+ [RICOH619_IRQ_VBATHIR] = RICOH619_IRQ(ADC_INT, 3, 9, 1, 4),
+ [RICOH619_IRQ_VADPHIR] = RICOH619_IRQ(ADC_INT, 3, 10, 2, 4),
+ [RICOH619_IRQ_VUSBHIR] = RICOH619_IRQ(ADC_INT, 3, 11, 3, 4),
+ [RICOH619_IRQ_VSYSHIR] = RICOH619_IRQ(ADC_INT, 3, 12, 4, 4),
+ [RICOH619_IRQ_VTHMHIR] = RICOH619_IRQ(ADC_INT, 3, 13, 5, 4),
+ [RICOH619_IRQ_AIN1HIR] = RICOH619_IRQ(ADC_INT, 3, 14, 6, 4),
+ [RICOH619_IRQ_AIN0HIR] = RICOH619_IRQ(ADC_INT, 3, 15, 7, 4),
+
+ [RICOH619_IRQ_ADC_ENDIR] = RICOH619_IRQ(ADC_INT, 3, 16, 0, 5),
+
+ [RICOH619_IRQ_GPIO0] = RICOH619_IRQ(GPIO_INT, 4, 0, 0, 6),
+ [RICOH619_IRQ_GPIO1] = RICOH619_IRQ(GPIO_INT, 4, 1, 1, 6),
+ [RICOH619_IRQ_GPIO2] = RICOH619_IRQ(GPIO_INT, 4, 2, 2, 6),
+ [RICOH619_IRQ_GPIO3] = RICOH619_IRQ(GPIO_INT, 4, 3, 3, 6),
+ [RICOH619_IRQ_GPIO4] = RICOH619_IRQ(GPIO_INT, 4, 4, 4, 6),
+
+ [RICOH619_IRQ_FVADPDETSINT] = RICOH619_IRQ(CHG_INT, 6, 0, 0, 8),
+ [RICOH619_IRQ_FVUSBDETSINT] = RICOH619_IRQ(CHG_INT, 6, 1, 1, 8),
+ [RICOH619_IRQ_FVADPLVSINT] = RICOH619_IRQ(CHG_INT, 6, 2, 2, 8),
+ [RICOH619_IRQ_FVUSBLVSINT] = RICOH619_IRQ(CHG_INT, 6, 3, 3, 8),
+ [RICOH619_IRQ_FWVADPSINT] = RICOH619_IRQ(CHG_INT, 6, 4, 4, 8),
+ [RICOH619_IRQ_FWVUSBSINT] = RICOH619_IRQ(CHG_INT, 6, 5, 5, 8),
+
+ [RICOH619_IRQ_FONCHGINT] = RICOH619_IRQ(CHG_INT, 6, 6, 0, 9),
+ [RICOH619_IRQ_FCHGCMPINT] = RICOH619_IRQ(CHG_INT, 6, 7, 1, 9),
+ [RICOH619_IRQ_FBATOPENINT] = RICOH619_IRQ(CHG_INT, 6, 8, 2, 9),
+ [RICOH619_IRQ_FSLPMODEINT] = RICOH619_IRQ(CHG_INT, 6, 9, 3, 9),
+ [RICOH619_IRQ_FBTEMPJTA1INT] = RICOH619_IRQ(CHG_INT, 6, 10, 4, 9),
+ [RICOH619_IRQ_FBTEMPJTA2INT] = RICOH619_IRQ(CHG_INT, 6, 11, 5, 9),
+ [RICOH619_IRQ_FBTEMPJTA3INT] = RICOH619_IRQ(CHG_INT, 6, 12, 6, 9),
+ [RICOH619_IRQ_FBTEMPJTA4INT] = RICOH619_IRQ(CHG_INT, 6, 13, 7, 9),
+
+ [RICOH619_IRQ_FCURTERMINT] = RICOH619_IRQ(CHG_INT, 6, 14, 0, 10),
+ [RICOH619_IRQ_FVOLTERMINT] = RICOH619_IRQ(CHG_INT, 6, 15, 1, 10),
+ [RICOH619_IRQ_FICRVSINT] = RICOH619_IRQ(CHG_INT, 6, 16, 2, 10),
+ [RICOH619_IRQ_FPOOR_CHGCURINT] = RICOH619_IRQ(CHG_INT, 6, 17, 3, 10),
+ [RICOH619_IRQ_FOSCFDETINT1] = RICOH619_IRQ(CHG_INT, 6, 18, 4, 10),
+ [RICOH619_IRQ_FOSCFDETINT2] = RICOH619_IRQ(CHG_INT, 6, 19, 5, 10),
+ [RICOH619_IRQ_FOSCFDETINT3] = RICOH619_IRQ(CHG_INT, 6, 20, 6, 10),
+ [RICOH619_IRQ_FOSCMDETINT] = RICOH619_IRQ(CHG_INT, 6, 21, 7, 10),
+
+ [RICOH619_IRQ_FDIEOFFINT] = RICOH619_IRQ(CHG_INT, 6, 22, 0, 11),
+ [RICOH619_IRQ_FDIEERRINT] = RICOH619_IRQ(CHG_INT, 6, 23, 1, 11),
+ [RICOH619_IRQ_FBTEMPERRINT] = RICOH619_IRQ(CHG_INT, 6, 24, 2, 11),
+ [RICOH619_IRQ_FVBATOVINT] = RICOH619_IRQ(CHG_INT, 6, 25, 3, 11),
+ [RICOH619_IRQ_FTTIMOVINT] = RICOH619_IRQ(CHG_INT, 6, 26, 4, 11),
+ [RICOH619_IRQ_FRTIMOVINT] = RICOH619_IRQ(CHG_INT, 6, 27, 5, 11),
+ [RICOH619_IRQ_FVADPOVSINT] = RICOH619_IRQ(CHG_INT, 6, 28, 6, 11),
+ [RICOH619_IRQ_FVUSBOVSINT] = RICOH619_IRQ(CHG_INT, 6, 29, 7, 11),
+
+ [RICOH619_IRQ_FGCDET] = RICOH619_IRQ(CHG_INT, 6, 30, 0, 12),
+ [RICOH619_IRQ_FPCDET] = RICOH619_IRQ(CHG_INT, 6, 31, 1, 12),
+ [RICOH619_IRQ_FWARN_ADP] = RICOH619_IRQ(CHG_INT, 6, 32, 3, 12),
+
+};
+
+static void ricoh619_irq_lock(struct irq_data *irq_data)
+{
+ struct ricoh619 *ricoh619 = irq_data_get_irq_chip_data(irq_data);
+
+ mutex_lock(&ricoh619->irq_lock);
+}
+
+static void ricoh619_irq_unmask(struct irq_data *irq_data)
+{
+ struct ricoh619 *ricoh619 = irq_data_get_irq_chip_data(irq_data);
+ unsigned int __irq = irq_data->irq - ricoh619->irq_base;
+ const struct ricoh619_irq_data *data = &ricoh619_irqs[__irq];
+
+ ricoh619->group_irq_en[data->master_bit] |= (1 << data->grp_index);
+ if (ricoh619->group_irq_en[data->master_bit])
+ ricoh619->intc_inten_reg |= 1 << data->master_bit;
+
+ if (data->master_bit == 6) /* if Charger */
+ ricoh619->irq_en_reg[data->mask_reg_index]
+ &= ~(1 << data->int_en_bit);
+ else
+ ricoh619->irq_en_reg[data->mask_reg_index]
+ |= 1 << data->int_en_bit;
+}
+
+static void ricoh619_irq_mask(struct irq_data *irq_data)
+{
+ struct ricoh619 *ricoh619 = irq_data_get_irq_chip_data(irq_data);
+ unsigned int __irq = irq_data->irq - ricoh619->irq_base;
+ const struct ricoh619_irq_data *data = &ricoh619_irqs[__irq];
+
+ ricoh619->group_irq_en[data->master_bit] &= ~(1 << data->grp_index);
+ if (!ricoh619->group_irq_en[data->master_bit])
+ ricoh619->intc_inten_reg &= ~(1 << data->master_bit);
+
+ if (data->master_bit == 6) /* if Charger */
+ ricoh619->irq_en_reg[data->mask_reg_index]
+ |= 1 << data->int_en_bit;
+ else
+ ricoh619->irq_en_reg[data->mask_reg_index]
+ &= ~(1 << data->int_en_bit);
+}
+
+static void ricoh619_irq_sync_unlock(struct irq_data *irq_data)
+{
+ struct ricoh619 *ricoh619 = irq_data_get_irq_chip_data(irq_data);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ricoh619->gpedge_reg); i++) {
+ if (ricoh619->gpedge_reg[i] != ricoh619->gpedge_cache[i]) {
+ if (!WARN_ON(ricoh619_write(ricoh619->dev,
+ gpedge_add[i],
+ ricoh619->gpedge_reg[i])))
+ ricoh619->gpedge_cache[i] =
+ ricoh619->gpedge_reg[i];
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(ricoh619->irq_en_reg); i++) {
+ if (ricoh619->irq_en_reg[i] != ricoh619->irq_en_cache[i]) {
+ if (!WARN_ON(ricoh619_write(ricoh619->dev,
+ irq_en_add[i],
+ ricoh619->irq_en_reg[i])))
+ ricoh619->irq_en_cache[i] =
+ ricoh619->irq_en_reg[i];
+ }
+ }
+
+ if (ricoh619->intc_inten_reg != ricoh619->intc_inten_cache) {
+ if (!WARN_ON(ricoh619_write(ricoh619->dev,
+ RICOH619_INTC_INTEN, ricoh619->intc_inten_reg)))
+ ricoh619->intc_inten_cache = ricoh619->intc_inten_reg;
+ }
+
+ mutex_unlock(&ricoh619->irq_lock);
+}
+
+static int ricoh619_irq_set_type(struct irq_data *irq_data, unsigned int type)
+{
+ struct ricoh619 *ricoh619 = irq_data_get_irq_chip_data(irq_data);
+ unsigned int __irq = irq_data->irq - ricoh619->irq_base;
+ const struct ricoh619_irq_data *data = &ricoh619_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;
+
+ ricoh619->gpedge_reg[gpedge_index] &= ~(3 << gpedge_bit_pos);
+ ricoh619->gpedge_reg[gpedge_index] |= (val << gpedge_bit_pos);
+ ricoh619_irq_unmask(irq_data);
+ }
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int ricoh619_irq_set_wake(struct irq_data *irq_data, unsigned int on)
+{
+ struct ricoh619 *ricoh619 = irq_data_get_irq_chip_data(irq_data);
+ return irq_set_irq_wake(ricoh619->chip_irq, on); //i2c->irq
+}
+#else
+#define ricoh619_irq_set_wake NULL
+#endif
+
+static irqreturn_t ricoh619_irq(int irq, void *data)
+{
+ struct ricoh619 *ricoh619 = data;
+ u8 int_sts[MAX_INTERRUPT_MASKS];
+ u8 master_int;
+ int i;
+ int ret;
+ unsigned int rtc_int_sts = 0;
+
+ /* Clear the status */
+ for (i = 0; i < MAX_INTERRUPT_MASKS; i++)
+ int_sts[i] = 0;
+
+ ret = ricoh619_read(ricoh619->dev, RICOH619_INTC_INTMON,
+ &master_int);
+// printk("PMU1: %s: master_int=0x%x\n", __func__, master_int);
+ if (ret < 0) {
+ dev_err(ricoh619->dev, "Error in reading reg 0x%02x "
+ "error: %d\n", RICOH619_INTC_INTMON, ret);
+ return IRQ_HANDLED;
+ }
+
+/* Mask Charger Interrupt */
+ if((CHG_INT | ADC_INT) & master_int){
+ for (i=8; i < MAX_INTERRUPT_MASKS; i++) {
+ ret = ricoh619_write(ricoh619->dev,
+ irq_en_add[i], 0xff);
+ if (ret < 0) {
+ dev_err(ricoh619->dev,
+ "Error in write reg 0x%02x "
+ "error: %d\n",
+ irq_en_add[i], ret);
+ }
+ }
+ //Disable ADC interrupt
+ for (i=3; i < 6; i++) {
+ ret = ricoh619_write(ricoh619->dev, irq_en_add[i], 0x0);
+ if (ret < 0) {
+ dev_err(ricoh619->dev, "Error in write reg 0x%02x "
+ "error: %d\n", irq_en_add[i],
+ ret);
+ }
+ }
+ }
+
+ for (i = 0; i < MAX_INTERRUPT_MASKS; ++i) {
+ /* Even if INTC_INTMON register = 1, INT signal might not output
+ because INTC_INTMON register indicates only interrupt facter level.
+ So remove the following procedure */
+// if (!(master_int & main_int_type[i]))
+// continue;
+
+ ret = ricoh619_read(ricoh619->dev,
+ irq_mon_add[i], &int_sts[i]);
+// printk("PMU2: %s: int_sts[%d]=0x%x\n", __func__,i, int_sts[i]);
+ if (ret < 0) {
+ dev_err(ricoh619->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) {
+ // Changes status bit position from RTCCNT2 to RTCCNT1
+ rtc_int_sts = 0;
+ if (int_sts[i] & 0x1)
+ rtc_int_sts |= BIT(6);
+ if (int_sts[i] & 0x4)
+ rtc_int_sts |= BIT(0);
+ }
+
+ ret = ricoh619_write(ricoh619->dev,
+ irq_clr_add[i], ~int_sts[i]);
+ if (ret < 0) {
+ dev_err(ricoh619->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[6] |= int_sts[7];
+
+ /* Call interrupt handler if enabled */
+ for (i = 0; i < RICOH619_NR_IRQS; ++i) {
+ const struct ricoh619_irq_data *data = &ricoh619_irqs[i];
+ if ((int_sts[data->mask_reg_index] & (1 << data->int_en_bit)) &&
+ (ricoh619->group_irq_en[data->master_bit] &
+ (1 << data->grp_index)))
+ handle_nested_irq(ricoh619->irq_base + i);
+ }
+
+// printk(KERN_INFO "PMU: %s: out\n", __func__);
+ return IRQ_HANDLED;
+}
+
+static struct irq_chip ricoh619_irq_chip = {
+ .name = "ricoh619",
+ .irq_mask = ricoh619_irq_mask,
+ .irq_unmask = ricoh619_irq_unmask,
+ .irq_bus_lock = ricoh619_irq_lock,
+ .irq_bus_sync_unlock = ricoh619_irq_sync_unlock,
+ .irq_set_type = ricoh619_irq_set_type,
+ .irq_set_wake = ricoh619_irq_set_wake,
+};
+
+int ricoh619_irq_init(struct ricoh619 *ricoh619, int irq,
+ int irq_base)
+{
+ int i, ret;
+
+ if (!irq_base) {
+ dev_warn(ricoh619->dev, "No interrupt support on IRQ base\n");
+ return -EINVAL;
+ }
+
+ mutex_init(&ricoh619->irq_lock);
+
+ /* Initialize all locals to 0 */
+ for (i = 0; i < 8; i++) {
+ ricoh619->irq_en_cache[i] = 0;
+ ricoh619->irq_en_reg[i] = 0;
+ }
+ // Charger Mask register must be set to 1 for masking Int output.
+ for (i = 8; i < MAX_INTERRUPT_MASKS; i++) {
+ ricoh619->irq_en_cache[i] = 0xff;
+ ricoh619->irq_en_reg[i] = 0xff;
+ }
+
+ ricoh619->intc_inten_cache = 0;
+ ricoh619->intc_inten_reg = 0;
+ for (i = 0; i < MAX_GPEDGE_REG; i++) {
+ ricoh619->gpedge_cache[i] = 0;
+ ricoh619->gpedge_reg[i] = 0;
+ }
+
+ /* Initailize all int register to 0 */
+ for (i = 0; i < MAX_INTERRUPT_MASKS; i++) {
+ ret = ricoh619_write(ricoh619->dev,
+ irq_en_add[i],
+ ricoh619->irq_en_reg[i]);
+ if (ret < 0)
+ dev_err(ricoh619->dev, "Error in writing reg 0x%02x "
+ "error: %d\n", irq_en_add[i], ret);
+ }
+
+ for (i = 0; i < MAX_GPEDGE_REG; i++) {
+ ret = ricoh619_write(ricoh619->dev,
+ gpedge_add[i],
+ ricoh619->gpedge_reg[i]);
+ if (ret < 0)
+ dev_err(ricoh619->dev, "Error in writing reg 0x%02x "
+ "error: %d\n", gpedge_add[i], ret);
+ }
+
+ ret = ricoh619_write(ricoh619->dev, RICOH619_INTC_INTEN, 0x0);
+ if (ret < 0)
+ dev_err(ricoh619->dev, "Error in writing reg 0x%02x "
+ "error: %d\n", RICOH619_INTC_INTEN, ret);
+
+ /* Clear all interrupts in case they woke up active. */
+ for (i = 0; i < MAX_INTERRUPT_MASKS; i++) {
+ ret = ricoh619_write(ricoh619->dev,
+ irq_clr_add[i], 0);
+ if (ret < 0)
+ dev_err(ricoh619->dev, "Error in writing reg 0x%02x "
+ "error: %d\n", irq_clr_add[i], ret);
+ }
+
+ ricoh619->irq_base = irq_base;
+ ricoh619->chip_irq = irq;
+
+ for (i = 0; i < RICOH619_NR_IRQS; i++) {
+ int __irq = i + ricoh619->irq_base;
+ irq_set_chip_data(__irq, ricoh619);
+ irq_set_chip_and_handler(__irq, &ricoh619_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, ricoh619_irq,
+ IRQ_TYPE_EDGE_FALLING|IRQF_DISABLED|IRQF_ONESHOT,
+ "ricoh619", ricoh619);
+ if (ret < 0)
+ dev_err(ricoh619->dev, "Error in registering interrupt "
+ "error: %d\n", ret);
+/*
+ if (!ret) {
+ device_init_wakeup(ricoh619->dev, 1);
+ enable_irq_wake(irq);
+ }
+*/
+
+ return ret;
+}
+
+int ricoh619_irq_exit(struct ricoh619 *ricoh619)
+{
+ if (ricoh619->chip_irq)
+ free_irq(ricoh619->chip_irq, ricoh619);
+ return 0;
+}
+
--- /dev/null
+/*
+ * driver/mfd/ricoh619.c
+ *
+ * Core driver implementation to access RICOH RC5T619 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+/*#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/ricoh619.h>
+
+
+struct ricoh619 *g_ricoh619;
+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 __ricoh619_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, "ricoh619: reg read reg=%x, val=%x\n",
+ reg, *val);
+ return 0;
+}
+
+static inline int __ricoh619_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, "ricoh619: reg read reg=%x, val=%x\n",
+ reg + i, *(val + i));
+ }
+ return 0;
+}
+
+static inline int __ricoh619_write(struct i2c_client *client,
+ u8 reg, uint8_t val)
+{
+ int ret;
+
+ dev_dbg(&client->dev, "ricoh619: 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 __ricoh619_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, "ricoh619: 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_ricoh619(struct device *dev, int bank)
+{
+ struct ricoh619 *ricoh619 = dev_get_drvdata(dev);
+ int ret;
+
+ if (bank != (bank & 1))
+ return -EINVAL;
+ if (bank == ricoh619->bank_num)
+ return 0;
+ ret = __ricoh619_write(to_i2c_client(dev), RICOH619_REG_BANKSEL, bank);
+ if (!ret)
+ ricoh619->bank_num = bank;
+
+ return ret;
+}
+
+int ricoh619_write(struct device *dev, u8 reg, uint8_t val)
+{
+ struct ricoh619 *ricoh619 = dev_get_drvdata(dev);
+ int ret = 0;
+
+ mutex_lock(&ricoh619->io_lock);
+ ret = set_bank_ricoh619(dev, 0);
+ if( !ret )
+ ret = __ricoh619_write(to_i2c_client(dev), reg, val);
+ mutex_unlock(&ricoh619->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_write);
+
+int ricoh619_write_bank1(struct device *dev, u8 reg, uint8_t val)
+{
+ struct ricoh619 *ricoh619 = dev_get_drvdata(dev);
+ int ret = 0;
+
+ mutex_lock(&ricoh619->io_lock);
+ ret = set_bank_ricoh619(dev, 1);
+ if( !ret )
+ ret = __ricoh619_write(to_i2c_client(dev), reg, val);
+ mutex_unlock(&ricoh619->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_write_bank1);
+
+int ricoh619_bulk_writes(struct device *dev, u8 reg, u8 len, uint8_t *val)
+{
+ struct ricoh619 *ricoh619 = dev_get_drvdata(dev);
+ int ret = 0;
+
+ mutex_lock(&ricoh619->io_lock);
+ ret = set_bank_ricoh619(dev, 0);
+ if( !ret )
+ ret = __ricoh619_bulk_writes(to_i2c_client(dev), reg, len, val);
+ mutex_unlock(&ricoh619->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_bulk_writes);
+
+int ricoh619_bulk_writes_bank1(struct device *dev, u8 reg, u8 len, uint8_t *val)
+{
+ struct ricoh619 *ricoh619 = dev_get_drvdata(dev);
+ int ret = 0;
+
+ mutex_lock(&ricoh619->io_lock);
+ ret = set_bank_ricoh619(dev, 1);
+ if( !ret )
+ ret = __ricoh619_bulk_writes(to_i2c_client(dev), reg, len, val);
+ mutex_unlock(&ricoh619->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_bulk_writes_bank1);
+
+int ricoh619_read(struct device *dev, u8 reg, uint8_t *val)
+{
+ struct ricoh619 *ricoh619 = dev_get_drvdata(dev);
+ int ret = 0;
+
+ mutex_lock(&ricoh619->io_lock);
+ ret = set_bank_ricoh619(dev, 0);
+ if( !ret )
+ ret = __ricoh619_read(to_i2c_client(dev), reg, val);
+ mutex_unlock(&ricoh619->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_read);
+
+int ricoh619_read_bank1(struct device *dev, u8 reg, uint8_t *val)
+{
+ struct ricoh619 *ricoh619 = dev_get_drvdata(dev);
+ int ret = 0;
+
+ mutex_lock(&ricoh619->io_lock);
+ ret = set_bank_ricoh619(dev, 1);
+ if( !ret )
+ ret = __ricoh619_read(to_i2c_client(dev), reg, val);
+ mutex_unlock(&ricoh619->io_lock);
+
+ return ret;
+}
+
+EXPORT_SYMBOL_GPL(ricoh619_read_bank1);
+
+int ricoh619_bulk_reads(struct device *dev, u8 reg, u8 len, uint8_t *val)
+{
+ struct ricoh619 *ricoh619 = dev_get_drvdata(dev);
+ int ret = 0;
+
+ mutex_lock(&ricoh619->io_lock);
+ ret = set_bank_ricoh619(dev, 0);
+ if( !ret )
+ ret = __ricoh619_bulk_reads(to_i2c_client(dev), reg, len, val);
+ mutex_unlock(&ricoh619->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_bulk_reads);
+
+int ricoh619_bulk_reads_bank1(struct device *dev, u8 reg, u8 len, uint8_t *val)
+{
+ struct ricoh619 *ricoh619 = dev_get_drvdata(dev);
+ int ret = 0;
+
+ mutex_lock(&ricoh619->io_lock);
+ ret = set_bank_ricoh619(dev, 1);
+ if( !ret )
+ ret = __ricoh619_bulk_reads(to_i2c_client(dev), reg, len, val);
+ mutex_unlock(&ricoh619->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_bulk_reads_bank1);
+
+int ricoh619_set_bits(struct device *dev, u8 reg, uint8_t bit_mask)
+{
+ struct ricoh619 *ricoh619 = dev_get_drvdata(dev);
+ uint8_t reg_val;
+ int ret = 0;
+
+ mutex_lock(&ricoh619->io_lock);
+ ret = set_bank_ricoh619(dev, 0);
+ if (!ret) {
+ ret = __ricoh619_read(to_i2c_client(dev), reg, ®_val);
+ if (ret)
+ goto out;
+
+ if ((reg_val & bit_mask) != bit_mask) {
+ reg_val |= bit_mask;
+ ret = __ricoh619_write(to_i2c_client(dev), reg,
+ reg_val);
+ }
+ }
+out:
+ mutex_unlock(&ricoh619->io_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_set_bits);
+
+int ricoh619_clr_bits(struct device *dev, u8 reg, uint8_t bit_mask)
+{
+ struct ricoh619 *ricoh619 = dev_get_drvdata(dev);
+ uint8_t reg_val;
+ int ret = 0;
+
+ mutex_lock(&ricoh619->io_lock);
+ ret = set_bank_ricoh619(dev, 0);
+ if( !ret ){
+ ret = __ricoh619_read(to_i2c_client(dev), reg, ®_val);
+ if (ret)
+ goto out;
+
+ if (reg_val & bit_mask) {
+ reg_val &= ~bit_mask;
+ ret = __ricoh619_write(to_i2c_client(dev), reg,
+ reg_val);
+ }
+ }
+out:
+ mutex_unlock(&ricoh619->io_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_clr_bits);
+
+int ricoh619_update(struct device *dev, u8 reg, uint8_t val, uint8_t mask)
+{
+ struct ricoh619 *ricoh619 = dev_get_drvdata(dev);
+ uint8_t reg_val;
+ int ret = 0;
+
+ mutex_lock(&ricoh619->io_lock);
+ ret = set_bank_ricoh619(dev, 0);
+ if( !ret ){
+ ret = __ricoh619_read(ricoh619->client, reg, ®_val);
+ if (ret)
+ goto out;
+
+ if ((reg_val & mask) != val) {
+ reg_val = (reg_val & ~mask) | (val & mask);
+ ret = __ricoh619_write(ricoh619->client, reg, reg_val);
+ }
+ }
+out:
+ mutex_unlock(&ricoh619->io_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_update);
+
+int ricoh619_update_bank1(struct device *dev, u8 reg, uint8_t val, uint8_t mask)
+{
+ struct ricoh619 *ricoh619 = dev_get_drvdata(dev);
+ uint8_t reg_val;
+ int ret = 0;
+
+ mutex_lock(&ricoh619->io_lock);
+ ret = set_bank_ricoh619(dev, 1);
+ if( !ret ){
+ ret = __ricoh619_read(ricoh619->client, reg, ®_val);
+ if (ret)
+ goto out;
+
+ if ((reg_val & mask) != val) {
+ reg_val = (reg_val & ~mask) | (val & mask);
+ ret = __ricoh619_write(ricoh619->client, reg, reg_val);
+ }
+ }
+out:
+ mutex_unlock(&ricoh619->io_lock);
+ return ret;
+}
+
+static struct i2c_client *ricoh619_i2c_client;
+int ricoh619_power_off(void)
+{
+ int ret;
+ uint8_t val;
+ int err = -1;
+ struct ricoh619 *ricoh619 = g_ricoh619;
+
+ val = g_soc;
+ val &= 0x7f;
+ ret = ricoh619_write(ricoh619->dev, RICOH619_PSWR, val);
+ if (ret < 0)
+ dev_err(ricoh619->dev, "Error in writing PSWR_REG\n");
+
+ if (g_fg_on_mode == 0) {
+ ret = ricoh619_clr_bits(ricoh619->dev,
+ RICOH619_FG_CTRL, 0x01);
+ if (ret < 0)
+ dev_err(ricoh619->dev, "Error in writing FG_CTRL\n");
+ }
+
+ if (!ricoh619_i2c_client)
+ return -EINVAL;
+//__ricoh618_write(ricoh618_i2c_client, RICOH618_PWR_REP_CNT, 0x0); //Not repeat power ON after power off(Power Off/N_OE)
+// __ricoh618_write(ricoh618_i2c_client, RICOH618_PWR_SLP_CNT, 0x1); //Power OFF
+ ret = ricoh619_clr_bits(ricoh619->dev,RICOH619_PWR_REP_CNT,(0x1<<0));//Not repeat power ON after power off(Power Off/N_OE)
+ ret = ricoh619_set_bits(ricoh619->dev, RICOH619_PWR_SLP_CNT,(0x1<<0));//Power OFF
+ if (ret < 0) {
+ printk("ricoh619 power off error!\n");
+ return err;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ricoh619_power_off);
+
+static int ricoh619_gpio_get(struct gpio_chip *gc, unsigned offset)
+{
+ struct ricoh619 *ricoh619 = container_of(gc, struct ricoh619, gpio_chip);
+ uint8_t val;
+ int ret;
+
+ ret = ricoh619_read(ricoh619->dev, RICOH619_GPIO_MON_IOIN, &val);
+ if (ret < 0)
+ return ret;
+
+ return ((val & (0x1 << offset)) != 0);
+}
+
+static void ricoh619_gpio_set(struct gpio_chip *gc, unsigned offset,
+ int value)
+{
+ struct ricoh619 *ricoh619 = container_of(gc, struct ricoh619, gpio_chip);
+ if (value)
+ ricoh619_set_bits(ricoh619->dev, RICOH619_GPIO_IOOUT,
+ 1 << offset);
+ else
+ ricoh619_clr_bits(ricoh619->dev, RICOH619_GPIO_IOOUT,
+ 1 << offset);
+}
+
+static int ricoh619_gpio_input(struct gpio_chip *gc, unsigned offset)
+{
+ struct ricoh619 *ricoh619 = container_of(gc, struct ricoh619, gpio_chip);
+
+ return ricoh619_clr_bits(ricoh619->dev, RICOH619_GPIO_IOSEL,
+ 1 << offset);
+}
+
+static int ricoh619_gpio_output(struct gpio_chip *gc, unsigned offset,
+ int value)
+{
+ struct ricoh619 *ricoh619 = container_of(gc, struct ricoh619, gpio_chip);
+
+ ricoh619_gpio_set(gc, offset, value);
+ return ricoh619_set_bits(ricoh619->dev, RICOH619_GPIO_IOSEL,
+ 1 << offset);
+}
+
+static int ricoh619_gpio_to_irq(struct gpio_chip *gc, unsigned off)
+{
+ struct ricoh619 *ricoh619 = container_of(gc, struct ricoh619, gpio_chip);
+
+ if ((off >= 0) && (off < 8))
+ return ricoh619->irq_base + RICOH619_IRQ_GPIO0 + off;
+
+ return -EIO;
+}
+
+
+static void __devinit ricoh619_gpio_init(struct ricoh619 *ricoh619,
+ 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 = ricoh619_set_bits(ricoh619->dev,
+ RICOH619_GPIO_IOOUT, 1 << i);
+ else
+ /* output L */
+ ret = ricoh619_clr_bits(ricoh619->dev,
+ RICOH619_GPIO_IOOUT, 1 << i);
+ if (!ret)
+ ret = ricoh619_set_bits(ricoh619->dev,
+ RICOH619_GPIO_IOSEL, 1 << i);
+ } else
+ /* GPIO input mode */
+ ret = ricoh619_clr_bits(ricoh619->dev,
+ RICOH619_GPIO_IOSEL, 1 << i);
+
+ /* if LED function enabled in OTP */
+ if (ginit->led_mode) {
+ /* LED Mode 1 */
+ if (i == 0) /* GP0 */
+ ret = ricoh619_set_bits(ricoh619->dev,
+ RICOH619_GPIO_LED_FUNC,
+ 0x04 | (ginit->led_func & 0x03));
+ if (i == 1) /* GP1 */
+ ret = ricoh619_set_bits(ricoh619->dev,
+ RICOH619_GPIO_LED_FUNC,
+ 0x40 | (ginit->led_func & 0x03) << 4);
+
+ }
+
+
+ if (ret < 0)
+ dev_err(ricoh619->dev, "Gpio %d init "
+ "dir configuration failed: %d\n", i, ret);
+
+ }
+
+ ricoh619->gpio_chip.owner = THIS_MODULE;
+ ricoh619->gpio_chip.label = ricoh619->client->name;
+ ricoh619->gpio_chip.dev = ricoh619->dev;
+ ricoh619->gpio_chip.base = pdata->gpio_base;
+ ricoh619->gpio_chip.ngpio = RICOH619_NR_GPIO;
+ ricoh619->gpio_chip.can_sleep = 1;
+
+ ricoh619->gpio_chip.direction_input = ricoh619_gpio_input;
+ ricoh619->gpio_chip.direction_output = ricoh619_gpio_output;
+ ricoh619->gpio_chip.set = ricoh619_gpio_set;
+ ricoh619->gpio_chip.get = ricoh619_gpio_get;
+ ricoh619->gpio_chip.to_irq = ricoh619_gpio_to_irq;
+
+ ret = gpiochip_add(&ricoh619->gpio_chip);
+ if (ret)
+ dev_warn(ricoh619->dev, "GPIO registration failed: %d\n", ret);
+}
+
+static int ricoh619_remove_subdev(struct device *dev, void *unused)
+{
+ platform_device_unregister(to_platform_device(dev));
+ return 0;
+}
+
+static int ricoh619_remove_subdevs(struct ricoh619 *ricoh619)
+{
+ return device_for_each_child(ricoh619->dev, NULL,
+ ricoh619_remove_subdev);
+}
+
+static int __devinit ricoh619_add_subdevs(struct ricoh619 *ricoh619,
+ 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 = ricoh619->dev;
+ pdev->dev.platform_data = subdev->platform_data;
+
+ ret = platform_device_add(pdev);
+ if (ret)
+ goto failed;
+ }
+ return 0;
+
+failed:
+ ricoh619_remove_subdevs(ricoh619);
+ 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 = __ricoh619_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 ricoh619 *ricoh = s->private;
+ struct i2c_client *client = ricoh->client;
+
+ seq_printf(s, "RICOH619 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 ricoh619_debuginit(struct ricoh619 *ricoh)
+{
+ (void)debugfs_create_file("ricoh619", 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 = __ricoh619_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 ricoh619_debuginit(struct ricoh619 *ricoh)
+{
+ struct i2c_client *client = ricoh->client;
+
+ printk(KERN_INFO "RICOH619 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 ricoh619_noe_init(struct ricoh619 *ricoh)
+{
+ struct i2c_client *client = ricoh->client;
+
+ __ricoh619_write(client, RICOH619_PWR_NOE_TIMSET, 0x0); //N_OE timer setting to 128mS
+ __ricoh619_write(client, RICOH619_PWR_REP_CNT, 0x1); //Repeat power ON after reset (Power Off/N_OE)
+}
+
+static int ricoh619_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ricoh619 *ricoh619;
+ struct ricoh619_platform_data *pdata = client->dev.platform_data;
+ int ret;
+ uint8_t control;
+ printk(KERN_INFO "PMU: %s:\n", __func__);
+
+ ricoh619 = kzalloc(sizeof(struct ricoh619), GFP_KERNEL);
+ if (ricoh619 == NULL)
+ return -ENOMEM;
+
+ ricoh619->client = client;
+ ricoh619->dev = &client->dev;
+ i2c_set_clientdata(client, ricoh619);
+
+ mutex_init(&ricoh619->io_lock);
+
+ ret = ricoh619_read(ricoh619->dev, 0x36, &control);
+ if ((control < 0) || (control == 0xff)) {
+ printk(KERN_INFO "The device is not ricoh619\n");
+ return 0;
+ }
+ /***************set noe time 128ms**************/
+ ret = ricoh619_set_bits(ricoh619->dev,0x11,(0x1 <<3));
+ ret = ricoh619_clr_bits(ricoh619->dev,0x11,(0x7 <<0));
+ ret = ricoh619_clr_bits(ricoh619->dev,0x11,(0x1 <<3));
+ /**********************************************/
+
+ /***************set PKEY long press time 0sec*******/
+ ret = ricoh619_set_bits(ricoh619->dev,0x10,(0x1 <<7));
+ ret = ricoh619_clr_bits(ricoh619->dev,0x10,(0x1 <<3));
+ ret = ricoh619_clr_bits(ricoh619->dev,0x10,(0x1 <<7));
+ /**********************************************/
+
+ ricoh619->bank_num = 0;
+
+// ret = pdata->init_port(client->irq); // For init PMIC_IRQ port
+ if (client->irq) {
+ ret = ricoh619_irq_init(ricoh619, client->irq, pdata->irq_base);
+ if (ret) {
+ dev_err(&client->dev, "IRQ init failed: %d\n", ret);
+ goto err_irq_init;
+ }
+ }
+
+ ret = ricoh619_add_subdevs(ricoh619, pdata);
+ if (ret) {
+ dev_err(&client->dev, "add devices failed: %d\n", ret);
+ goto err_add_devs;
+ }
+ ricoh619_noe_init(ricoh619);
+
+ g_ricoh619 = ricoh619;
+ if (pdata && pdata->pre_init) {
+ ret = pdata->pre_init(ricoh619);
+ if (ret != 0) {
+ dev_err(ricoh619->dev, "pre_init() failed: %d\n", ret);
+ goto err;
+ }
+ }
+
+ //ricoh619_gpio_init(ricoh619, pdata);
+
+ ricoh619_debuginit(ricoh619);
+
+ if (pdata && pdata->post_init) {
+ ret = pdata->post_init(ricoh619);
+ if (ret != 0) {
+ dev_err(ricoh619->dev, "post_init() failed: %d\n", ret);
+ goto err;
+ }
+ }
+
+ ricoh619_i2c_client = client;
+ return 0;
+err:
+ mfd_remove_devices(ricoh619->dev);
+ kfree(ricoh619);
+err_add_devs:
+ if (client->irq)
+ ricoh619_irq_exit(ricoh619);
+err_irq_init:
+ kfree(ricoh619);
+ return ret;
+}
+
+static int __devexit ricoh619_i2c_remove(struct i2c_client *client)
+{
+ struct ricoh619 *ricoh619 = i2c_get_clientdata(client);
+
+ if (client->irq)
+ ricoh619_irq_exit(ricoh619);
+
+ ricoh619_remove_subdevs(ricoh619);
+ kfree(ricoh619);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ricoh619_i2c_suspend(struct i2c_client *client, pm_message_t state)
+{
+ if (client->irq)
+ disable_irq(client->irq);
+ return 0;
+}
+
+int pwrkey_wakeup;
+static int ricoh619_i2c_resume(struct i2c_client *client)
+{
+ uint8_t reg_val;
+ int ret;
+
+ ret = __ricoh619_read(client, RICOH619_INT_IR_SYS, ®_val);
+ if(reg_val & 0x01) { //If PWR_KEY wakeup
+// printk("PMU: %s: PWR_KEY Wakeup\n",__func__);
+ pwrkey_wakeup = 1;
+ __ricoh619_write(client, RICOH619_INT_IR_SYS, 0x0); //Clear PWR_KEY IRQ
+ }
+
+ enable_irq(client->irq);
+ return 0;
+}
+
+#endif
+
+static const struct i2c_device_id ricoh619_i2c_id[] = {
+ {"ricoh619", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, ricoh619_i2c_id);
+
+static struct i2c_driver ricoh619_i2c_driver = {
+ .driver = {
+ .name = "ricoh619",
+ .owner = THIS_MODULE,
+ },
+ .probe = ricoh619_i2c_probe,
+ .remove = __devexit_p(ricoh619_i2c_remove),
+#ifdef CONFIG_PM
+ .suspend = ricoh619_i2c_suspend,
+ .resume = ricoh619_i2c_resume,
+#endif
+ .id_table = ricoh619_i2c_id,
+};
+
+
+static int __init ricoh619_i2c_init(void)
+{
+ int ret = -ENODEV;
+ ret = i2c_add_driver(&ricoh619_i2c_driver);
+ if (ret != 0)
+ pr_err("Failed to register I2C driver: %d\n", ret);
+
+ return ret;
+}
+
+subsys_initcall_sync(ricoh619_i2c_init);
+
+static void __exit ricoh619_i2c_exit(void)
+{
+ i2c_del_driver(&ricoh619_i2c_driver);
+}
+
+module_exit(ricoh619_i2c_exit);
+
+MODULE_DESCRIPTION("RICOH RC5T619 PMU multi-function core driver");
+MODULE_AUTHOR("zhangqing <zhangqing@rock-chips.com>");
+MODULE_LICENSE("GPL");
Say Y here to enable support for the power management unit
provided by the Wolfson Microelectronics WM8350 PMIC.
+config BATTERY_RICOH619
+ tristate "Ricoh RC5T619 PMIC battery driver"
+ depends on MFD_RICOH619 && I2C && GENERIC_HARDIRQS
+ help
+ Say Y to enable support for the battery control of the Ricoh RC5T619
+ Power Management device.
+
config TEST_POWER
tristate "Test power driver"
help
obj-$(CONFIG_PLAT_RK) += rk29_charger_display.o
obj-$(CONFIG_BATTERY_RK30_ADC_FAC) += rk30_factory_adc_battery.o
obj-$(CONFIG_CW2015_BATTERY) += cw2015_battery.o
-
+obj-$(CONFIG_BATTERY_RICOH619) += ricoh619-battery.o
--- /dev/null
+/*
+ * drivers/power/ricoh619-battery.c
+ *
+ * Charger driver for RICOH RC5T619 power management chip.
+ *
+ * Copyright (C) 2012-2013 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+#include <linux/power_supply.h>
+#include <linux/mfd/ricoh619.h>
+#include <linux/power/ricoh619_battery.h>
+#include <linux/power/ricoh61x_battery_init.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+
+/* define for function */
+#define ENABLE_FUEL_GAUGE_FUNCTION
+#define ENABLE_LOW_BATTERY_DETECTION
+#define ENABLE_FACTORY_MODE
+#define ENABLE_FG_KEEP_ON_MODE
+
+/* define for current limit. unit is mA */
+/* if value is "0", these settings set by OTP */
+#define RICOH619_MAX_CHARGE_CURRENT 0 /* mA */
+#define RICOH619_MAX_ADP_CURRENT 0 /* mA */
+#define RICOH619_MAX_USB_CURRENT 0 /* mA */
+#define RICOH619_CHARGE_COMPLETION_CURRENT 200 /* mA Range 50~200
+ * (Step 50) */
+#define RICOH619_FULL_CHARGING_VOLTAGE 0 /* mv can set 4050,
+ * 4100, 4150, 4200,
+ * 4350(default 4100) */
+#define RICOH619_RE_CHARGING_VOLTAGE 0 /* mv can set 3850,
+ * 3900, 3950, 4000,
+ * 4100(default 3900) */
+
+/* FG setting */
+#define CUTOFF_VOL 0 /* mV "0" means cutoff
+ * voltage = original
+ * OCV table value */
+#define RICOH619_REL1_SEL_VALUE 64 /* mv Range 0~240
+ * (Step 16) */
+
+enum int_type {
+ SYS_INT = 0x01,
+ DCDC_INT = 0x02,
+ ADC_INT = 0x08,
+ GPIO_INT = 0x10,
+ CHG_INT = 0x40,
+};
+
+#ifdef ENABLE_FUEL_GAUGE_FUNCTION
+/* define for FG parameter */
+#define RICOH619_MONITOR_START_TIME 15
+#define RICOH619_FG_RESET_TIME 6
+#define RICOH619_FG_STABLE_TIME 120
+#define RICOH619_DISPLAY_UPDATE_TIME 60
+#define RICOH619_SOCA_DISP_UPDATE_TIME 60
+#define RICOH619_MAX_RESET_SOC_DIFF 5
+
+/* define for FG status */
+enum {
+ RICOH619_SOCA_START,
+ RICOH619_SOCA_UNSTABLE,
+ RICOH619_SOCA_FG_RESET,
+ RICOH619_SOCA_DISP,
+ RICOH619_SOCA_STABLE,
+ RICOH619_SOCA_ZERO,
+};
+#endif
+
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+#define LOW_BATTERY_DETECTION_TIME 10
+#endif
+
+struct ricoh619_soca_info {
+ int Rbat;
+ int n_cap;
+ int ocv_table[11];
+ int soc; /* Latest FG SOC value */
+ int displayed_soc;
+ int status; /* SOCA status 0: Not initial; 5: Finished */
+ int stable_count;
+ int chg_status; /* chg_status */
+ int soc_delta; /* soc delta for status3(DISP) */
+ int cc_delta;
+ int last_soc;
+ int ready_fg;
+ int reset_count;
+ int reset_soc[3];
+};
+
+struct ricoh619_battery_info {
+ struct device *dev;
+ struct power_supply battery;
+ struct delayed_work monitor_work;
+ struct delayed_work usb_work;
+ struct delayed_work displayed_work;
+ struct delayed_work charge_stable_work;
+ struct delayed_work changed_work;
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+ struct delayed_work low_battery_work;
+#endif
+
+ struct work_struct irq_work; /* for Charging & VUSB/VADP */
+ struct work_struct usb_irq_work; /* for ADC_VUSB */
+
+ struct workqueue_struct *monitor_wqueue;
+ struct workqueue_struct *workqueue; /* for Charging & VUSB/VADP */
+ struct workqueue_struct *usb_workqueue; /* for ADC_VUSB */
+
+#ifdef ENABLE_FACTORY_MODE
+ struct delayed_work factory_mode_work;
+ struct workqueue_struct *factory_mode_wqueue;
+#endif
+
+ struct mutex lock;
+ unsigned long monitor_time;
+ int adc_vdd_mv;
+ int multiple;
+ int alarm_vol_mv;
+ int status;
+ int min_voltage;
+ int max_voltage;
+ int cur_voltage;
+ int capacity;
+ int battery_temp;
+ int time_to_empty;
+ int time_to_full;
+ int chg_ctr;
+ int chg_stat1;
+ unsigned present:1;
+ u16 delay;
+ struct ricoh619_soca_info *soca;
+ int first_pwon;
+ bool entry_factory_mode;
+};
+
+int charger_irq;
+/* this value is for mfd fucntion */
+int g_soc;
+int g_fg_on_mode;
+
+static void ricoh619_battery_work(struct work_struct *work)
+{
+ struct ricoh619_battery_info *info = container_of(work,
+ struct ricoh619_battery_info, monitor_work.work);
+
+ RICOH_FG_DBG("PMU: %s\n", __func__);
+ power_supply_changed(&info->battery);
+ queue_delayed_work(info->monitor_wqueue, &info->monitor_work,
+ info->monitor_time);
+}
+
+#ifdef ENABLE_FUEL_GAUGE_FUNCTION
+static int measure_vbatt_FG(struct ricoh619_battery_info *info, int *data);
+static int measure_Ibatt_FG(struct ricoh619_battery_info *info, int *data);
+static int calc_capacity(struct ricoh619_battery_info *info);
+static int get_OCV_init_Data(struct ricoh619_battery_info *info, int index);
+static int get_OCV_voltage(struct ricoh619_battery_info *info, int index);
+static int get_check_fuel_gauge_reg(struct ricoh619_battery_info *info,
+ int Reg_h, int Reg_l, int enable_bit);
+static int calc_capacity_in_period(struct ricoh619_battery_info *info,
+ int *cc_cap, bool *is_charging);
+
+/* check charge status.
+ * if CHG not Complete && SOC == 100 -> Stop charge
+ * if CHG Complete && SOC =! 100 -> SOC reset
+ */
+static int check_charge_status(struct ricoh619_battery_info *info)
+{
+ uint8_t status;
+ uint8_t supply_state;
+ uint8_t charge_state;
+ int ret = 0;
+ int current_SOC;
+
+ /* get power supply status */
+ ret = ricoh619_read(info->dev->parent, CHGSTATE_REG, &status);
+ if (ret < 0) {
+ dev_err(info->dev,
+ "Error in reading the control register\n");
+ return ret;
+ }
+
+
+ charge_state = (status & 0x1F);
+ supply_state = ((status & 0xC0) >> 6);
+
+ current_SOC = (info->soca->displayed_soc + 50)/100;
+
+ if (charge_state == CHG_STATE_CHG_COMPLETE) {
+ /* check SOC */
+ if (current_SOC != 100) {
+ ret = ricoh619_write(info->dev->parent,
+ FG_CTRL_REG, 0x51);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in writing the control register\n");
+ return ret;
+ }
+ info->soca->ready_fg = 0;
+
+ info->soca->displayed_soc = 100 * 100;
+
+ info->soca->status = RICOH619_SOCA_STABLE;
+ }
+
+ } else { /* chg not complete */
+ if (current_SOC == 100) {
+ ret = ricoh619_clr_bits(info->dev->parent,
+ CHGCTL1_REG, 0x03);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in writing the control register\n");
+ return ret;
+ }
+ info->soca->status = RICOH619_SOCA_STABLE;
+ } else {
+ ret = ricoh619_set_bits(info->dev->parent,
+ CHGCTL1_REG, 0x03);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in writing the control register\n");
+ return ret;
+ }
+ }
+ }
+ return ret;
+}
+
+static int calc_ocv(struct ricoh619_battery_info *info)
+{
+ int Vbat = 0;
+ int Ibat = 0;
+ int ret;
+ int ocv;
+
+ ret = measure_vbatt_FG(info, &Vbat);
+ ret = measure_Ibatt_FG(info, &Ibat);
+
+ ocv = Vbat - Ibat * info->soca->Rbat;
+
+ return ocv;
+}
+
+/**
+* Calculate Capacity in a period
+* - read CC_SUM & FA_CAP from Coulom Counter
+* - and calculate Capacity.
+* @cc_cap: capacity in a period, unit 0.01%
+* @is_charging: Flag of charging current direction
+* TRUE : charging (plus)
+* FALSE: discharging (minus)
+**/
+static int calc_capacity_in_period(struct ricoh619_battery_info *info,
+ int *cc_cap, bool *is_charging)
+{
+ int err;
+ uint8_t cc_sum_reg[4];
+ uint8_t cc_clr[4] = {0, 0, 0, 0};
+ uint8_t fa_cap_reg[2];
+ uint16_t fa_cap;
+ uint32_t cc_sum;
+
+ *is_charging = true; /* currrent state initialize -> charging */
+
+ if (info->entry_factory_mode)
+ return 0;
+
+ /* Disable Charging/Completion Interrupt */
+ err = ricoh619_set_bits(info->dev->parent,
+ RICOH619_INT_MSK_CHGSTS1, 0x01);
+ if (err < 0)
+ goto out;
+
+ /* In suspend - disable charging */
+ err = ricoh619_set_bits(info->dev->parent, RICOH619_CHG_CTL1, 0x08);
+ if (err < 0)
+ goto out;
+ /* CC_pause enter */
+ err = ricoh619_write(info->dev->parent, CC_CTRL_REG, 0x01);
+ if (err < 0)
+ goto out;
+ /* Read CC_SUM */
+ err = ricoh619_bulk_reads(info->dev->parent,
+ CC_SUMREG3_REG, 4, cc_sum_reg);
+ if (err < 0)
+ goto out;
+
+ /* CC_SUM <- 0 */
+ err = ricoh619_bulk_writes(info->dev->parent,
+ CC_SUMREG3_REG, 4, cc_clr);
+ if (err < 0)
+ goto out;
+
+ /* CC_pause exist */
+ err = ricoh619_write(info->dev->parent, CC_CTRL_REG, 0);
+ if (err < 0)
+ goto out;
+ /* out suspend - enable charging */
+ err = ricoh619_clr_bits(info->dev->parent, RICOH619_CHG_CTL1, 0x08);
+ if (err < 0)
+ goto out;
+
+ udelay(1000);
+
+ /* Clear Charging Interrupt status */
+ err = ricoh619_clr_bits(info->dev->parent,
+ RICOH619_INT_IR_CHGSTS1, 0x01);
+ if (err < 0)
+ goto out;
+
+ /* ricoh619_read(info->dev->parent, RICOH619_INT_IR_CHGSTS1, &val);
+ RICOH_FG_DBG("INT_IR_CHGSTS1 = 0x%x\n",val); */
+
+ /* Enable Charging Interrupt */
+ err = ricoh619_clr_bits(info->dev->parent,
+ RICOH619_INT_MSK_CHGSTS1, 0x01);
+ if (err < 0)
+ goto out;
+
+ /* Read FA_CAP */
+ err = ricoh619_bulk_reads(info->dev->parent,
+ FA_CAP_H_REG, 2, fa_cap_reg);
+ if (err < 0)
+ goto out;
+
+ /* fa_cap = *(uint16_t*)fa_cap_reg & 0x7fff; */
+ fa_cap = (fa_cap_reg[0] << 8 | fa_cap_reg[1]) & 0x7fff;
+
+ /* calculation two's complement of CC_SUM */
+ cc_sum = cc_sum_reg[0] << 24 | cc_sum_reg[1] << 16 |
+ cc_sum_reg[2] << 8 | cc_sum_reg[3];
+
+ /* cc_sum = *(uint32_t*)cc_sum_reg; */
+ if (cc_sum & 0x80000000) {
+ cc_sum = (cc_sum^0xffffffff)+0x01;
+ *is_charging = false; /* discharge */
+ }
+
+ *cc_cap = cc_sum*25/9/fa_cap; /* CC_SUM/3600/FA_CAP */
+
+ return 0;
+out:
+ dev_err(info->dev, "Error !!-----\n");
+ return err;
+}
+
+static void ricoh619_displayed_work(struct work_struct *work)
+{
+ int err;
+ uint8_t val;
+ int soc_round;
+ int last_soc_round;
+ int last_disp_round;
+ int displayed_soc_temp;
+ int cc_cap = 0;
+ bool is_charging = true;
+
+ struct ricoh619_battery_info *info = container_of(work,
+ struct ricoh619_battery_info, displayed_work.work);
+
+ if (info->entry_factory_mode) {
+ info->soca->status = RICOH619_SOCA_STABLE;
+ info->soca->displayed_soc = -EINVAL;
+ info->soca->ready_fg = 0;
+ return;
+ }
+
+ mutex_lock(&info->lock);
+
+ if ((RICOH619_SOCA_START == info->soca->status)
+ || (RICOH619_SOCA_STABLE == info->soca->status))
+ info->soca->ready_fg = 1;
+
+ if (RICOH619_SOCA_STABLE == info->soca->status) {
+ info->soca->soc = calc_capacity(info) * 100;
+ info->soca->displayed_soc = info->soca->soc;
+ } else if (RICOH619_SOCA_DISP == info->soca->status) {
+
+ info->soca->soc = calc_capacity(info) * 100;
+
+ soc_round = info->soca->soc / 100;
+ last_soc_round = info->soca->last_soc / 100;
+ last_disp_round = (info->soca->displayed_soc + 50) / 100;
+
+ info->soca->soc_delta =
+ info->soca->soc_delta + (soc_round - last_soc_round);
+
+ info->soca->last_soc = info->soca->soc;
+
+ /* six case */
+ if (last_disp_round == soc_round) {
+ /* if SOC == DISPLAY move to stable */
+ info->soca->displayed_soc = info->soca->soc ;
+ info->soca->status = RICOH619_SOCA_STABLE;
+
+ } else if ((soc_round == 100) || (soc_round == 0)) {
+ /* if SOC is 0% or 100% , finish display state*/
+ info->soca->displayed_soc = info->soca->soc ;
+ info->soca->status = RICOH619_SOCA_STABLE;
+
+ } else if ((info->soca->chg_status) ==
+ (POWER_SUPPLY_STATUS_CHARGING)) {
+ /* Charge */
+ if (last_disp_round < soc_round) {
+ /* Case 1 : Charge, Display < SOC */
+ if (info->soca->soc_delta >= 1) {
+ info->soca->displayed_soc
+ = (last_disp_round
+ + info->soca->soc_delta)*100;
+ info->soca->soc_delta = 0;
+ } else {
+ info->soca->displayed_soc
+ = (last_disp_round + 1)*100;
+ }
+
+ if (last_disp_round >= soc_round) {
+ info->soca->displayed_soc
+ = info->soca->soc ;
+ info->soca->status
+ = RICOH619_SOCA_STABLE;
+ }
+ } else if (last_disp_round > soc_round) {
+ /* Case 2 : Charge, Display > SOC */
+ if (info->soca->soc_delta >= 3) {
+ info->soca->displayed_soc =
+ (last_disp_round + 1)*100;
+ info->soca->soc_delta = 0;
+ }
+ if (last_disp_round <= soc_round) {
+ info->soca->displayed_soc
+ = info->soca->soc ;
+ info->soca->status
+ = RICOH619_SOCA_STABLE;
+ }
+ }
+ } else {
+ /* Dis-Charge */
+ if (last_disp_round > soc_round) {
+ /* Case 3 : Dis-Charge, Display > SOC */
+ if (info->soca->soc_delta <= -1) {
+ info->soca->displayed_soc
+ = (last_disp_round
+ + info->soca->soc_delta)*100;
+ info->soca->soc_delta = 0;
+ } else {
+ info->soca->displayed_soc
+ = (last_disp_round - 1)*100;
+ }
+ if (last_disp_round <= soc_round) {
+ info->soca->displayed_soc
+ = info->soca->soc ;
+ info->soca->status
+ = RICOH619_SOCA_STABLE;
+ }
+ } else if (last_disp_round < soc_round) {
+ /* dis Charge, Display < SOC */
+ if (info->soca->soc_delta <= -3) {
+ info->soca->displayed_soc
+ = (last_disp_round - 1)*100;
+ info->soca->soc_delta = 0;
+ }
+ if (last_disp_round >= soc_round) {
+ info->soca->displayed_soc
+ = info->soca->soc ;
+ info->soca->status
+ = RICOH619_SOCA_STABLE;
+ }
+ }
+ }
+ } else if (RICOH619_SOCA_UNSTABLE == info->soca->status
+ || RICOH619_SOCA_FG_RESET == info->soca->status) {
+ /* No update */
+ } else if (RICOH619_SOCA_START == info->soca->status) {
+ err = ricoh619_read(info->dev->parent, PSWR_REG, &val);
+ val &= 0x7f;
+ if (info->first_pwon) {
+ info->soca->soc = calc_capacity(info) * 100;
+ if ((info->soca->soc == 0) && (calc_ocv(info)
+ < get_OCV_voltage(info, 0))) {
+ info->soca->displayed_soc = 0;
+ info->soca->status = RICOH619_SOCA_ZERO;
+ } else {
+ info->soca->displayed_soc = info->soca->soc;
+ info->soca->status = RICOH619_SOCA_UNSTABLE;
+ }
+ } else if (g_fg_on_mode && (val == 0x7f)) {
+ info->soca->soc = calc_capacity(info) * 100;
+ if ((info->soca->soc == 0) && (calc_ocv(info)
+ < get_OCV_voltage(info, 0))) {
+ info->soca->displayed_soc = 0;
+ info->soca->status = RICOH619_SOCA_ZERO;
+ } else {
+ info->soca->displayed_soc = info->soca->soc;
+ info->soca->status = RICOH619_SOCA_STABLE;
+ }
+ } else {
+ info->soca->soc = val * 100;
+ if ((err < 0) || (val == 0)) {
+ dev_err(info->dev,
+ "Error in reading PSWR_REG %d\n", err);
+ info->soca->soc
+ = calc_capacity(info) * 100 + 50;
+ }
+
+ err = calc_capacity_in_period(info, &cc_cap,
+ &is_charging);
+ if (err < 0)
+ dev_err(info->dev, "Read cc_sum Error !!-----\n");
+
+ info->soca->cc_delta
+ = (is_charging == true) ? cc_cap : -cc_cap;
+ if (calc_ocv(info) < get_OCV_voltage(info, 0)) {
+ info->soca->displayed_soc = 0;
+ info->soca->status = RICOH619_SOCA_ZERO;
+ } else {
+ displayed_soc_temp
+ = info->soca->soc + info->soca->cc_delta;
+ displayed_soc_temp
+ = min(10000, displayed_soc_temp);
+ displayed_soc_temp = max(0, displayed_soc_temp);
+ info->soca->displayed_soc = displayed_soc_temp;
+ info->soca->status = RICOH619_SOCA_UNSTABLE;
+ }
+ }
+ } else if (RICOH619_SOCA_ZERO == info->soca->status) {
+ if (calc_ocv(info) > get_OCV_voltage(info, 0)) {
+ err = ricoh619_write(info->dev->parent,
+ FG_CTRL_REG, 0x51);
+ if (err < 0)
+ dev_err(info->dev, "Error in writing the control register\n");
+ info->soca->status = RICOH619_SOCA_STABLE;
+ info->soca->ready_fg = 0;
+ }
+ info->soca->displayed_soc = 0;
+ }
+
+ /* Ceck charge status */
+ err = check_charge_status(info);
+ if (err < 0)
+ dev_err(info->dev, "Error in writing the control register\n");
+
+ if (g_fg_on_mode
+ && (info->soca->status == RICOH619_SOCA_STABLE)) {
+ err = ricoh619_write(info->dev->parent, PSWR_REG, 0x7f);
+ if (err < 0)
+ dev_err(info->dev, "Error in writing PSWR_REG\n");
+ g_soc = 0x7F;
+ } else {
+ val = (info->soca->displayed_soc + 50)/100;
+ val &= 0x7f;
+ err = ricoh619_write(info->dev->parent, PSWR_REG, val);
+ if (err < 0)
+ dev_err(info->dev, "Error in writing PSWR_REG\n");
+
+ g_soc = (info->soca->displayed_soc + 50)/100;
+
+ err = calc_capacity_in_period(info, &cc_cap, &is_charging);
+ if (err < 0)
+ dev_err(info->dev, "Read cc_sum Error !!-----\n");
+ }
+
+ if (0 == info->soca->ready_fg)
+ queue_delayed_work(info->monitor_wqueue, &info->displayed_work,
+ RICOH619_FG_RESET_TIME * HZ);
+ else if (RICOH619_SOCA_DISP == info->soca->status)
+ queue_delayed_work(info->monitor_wqueue, &info->displayed_work,
+ RICOH619_SOCA_DISP_UPDATE_TIME * HZ);
+ else
+ queue_delayed_work(info->monitor_wqueue, &info->displayed_work,
+ RICOH619_DISPLAY_UPDATE_TIME * HZ);
+
+ mutex_unlock(&info->lock);
+
+ return;
+}
+
+static void ricoh619_stable_charge_countdown_work(struct work_struct *work)
+{
+ int ret;
+ int max = 0;
+ int min = 100;
+ int i;
+ struct ricoh619_battery_info *info = container_of(work,
+ struct ricoh619_battery_info, charge_stable_work.work);
+
+ if (info->entry_factory_mode)
+ return;
+
+ mutex_lock(&info->lock);
+ if (RICOH619_SOCA_FG_RESET == info->soca->status)
+ info->soca->ready_fg = 1;
+
+ if (2 <= info->soca->stable_count) {
+ if (3 == info->soca->stable_count
+ && RICOH619_SOCA_FG_RESET == info->soca->status) {
+ ret = ricoh619_write(info->dev->parent,
+ FG_CTRL_REG, 0x51);
+ if (ret < 0)
+ dev_err(info->dev, "Error in writing the control register\n");
+ info->soca->ready_fg = 0;
+ }
+ info->soca->stable_count = info->soca->stable_count - 1;
+ queue_delayed_work(info->monitor_wqueue,
+ &info->charge_stable_work,
+ RICOH619_FG_STABLE_TIME * HZ / 10);
+ } else if (0 >= info->soca->stable_count) {
+ /* Finished queue, ignore */
+ } else if (1 == info->soca->stable_count) {
+ if (RICOH619_SOCA_UNSTABLE == info->soca->status) {
+ /* Judge if FG need reset or Not */
+ info->soca->soc = calc_capacity(info) * 100;
+ if (info->chg_ctr != 0) {
+ queue_delayed_work(info->monitor_wqueue,
+ &info->charge_stable_work,
+ RICOH619_FG_STABLE_TIME * HZ / 10);
+ mutex_unlock(&info->lock);
+ return;
+ }
+ /* Do reset setting */
+ ret = ricoh619_write(info->dev->parent,
+ FG_CTRL_REG, 0x51);
+ if (ret < 0)
+ dev_err(info->dev, "Error in writing the control register\n");
+
+ info->soca->ready_fg = 0;
+ info->soca->status = RICOH619_SOCA_FG_RESET;
+
+ /* Delay for addition Reset Time (6s) */
+ queue_delayed_work(info->monitor_wqueue,
+ &info->charge_stable_work,
+ RICOH619_FG_RESET_TIME*HZ);
+ } else if (RICOH619_SOCA_FG_RESET == info->soca->status) {
+ info->soca->reset_soc[2] = info->soca->reset_soc[1];
+ info->soca->reset_soc[1] = info->soca->reset_soc[0];
+ info->soca->reset_soc[0] = calc_capacity(info) * 100;
+ info->soca->reset_count++;
+
+ if (info->soca->reset_count > 10) {
+ /* Reset finished; */
+ info->soca->soc = info->soca->reset_soc[0];
+ info->soca->stable_count = 0;
+ goto adjust;
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (max < info->soca->reset_soc[i]/100)
+ max = info->soca->reset_soc[i]/100;
+ if (min > info->soca->reset_soc[i]/100)
+ min = info->soca->reset_soc[i]/100;
+ }
+
+ if ((info->soca->reset_count > 3) && ((max - min)
+ < RICOH619_MAX_RESET_SOC_DIFF)) {
+ /* Reset finished; */
+ info->soca->soc = info->soca->reset_soc[0];
+ info->soca->stable_count = 0;
+ goto adjust;
+ } else {
+ /* Do reset setting */
+ ret = ricoh619_write(info->dev->parent,
+ FG_CTRL_REG, 0x51);
+ if (ret < 0)
+ dev_err(info->dev, "Error in writing the control register\n");
+
+ info->soca->ready_fg = 0;
+
+ /* Delay for addition Reset Time (6s) */
+ queue_delayed_work(info->monitor_wqueue,
+ &info->charge_stable_work,
+ RICOH619_FG_RESET_TIME*HZ);
+ }
+ /* Finished queue From now, select FG as result; */
+ } else if (RICOH619_SOCA_START == info->soca->status) {
+ /* Normal condition */
+ } else { /* other state ZERO/DISP/STABLE */
+ info->soca->stable_count = 0;
+ }
+
+ mutex_unlock(&info->lock);
+ return;
+
+adjust:
+ info->soca->last_soc = info->soca->soc;
+ info->soca->status = RICOH619_SOCA_DISP;
+
+ }
+ mutex_unlock(&info->lock);
+ return;
+}
+
+/* Initial setting of FuelGauge SOCA function */
+static int ricoh619_init_fgsoca(struct ricoh619_battery_info *info)
+{
+ int i;
+ int err;
+ uint8_t val;
+ uint8_t val2;
+
+ for (i = 0; i <= 10; i = i+1) {
+ info->soca->ocv_table[i] = get_OCV_voltage(info, i);
+ RICOH_FG_DBG("PMU: %s : * %d0%% voltage = %d uV\n",
+ __func__, i, info->soca->ocv_table[i]);
+ }
+
+ for (i = 0; i < 3; i = i+1)
+ info->soca->reset_soc[i] = 0;
+ info->soca->reset_count = 0;
+
+ if (info->first_pwon) {
+
+ err = ricoh619_read(info->dev->parent, CHGISET_REG, &val);
+ if (err < 0)
+ dev_err(info->dev,
+ "Error in read CHGISET_REG%d\n", err);
+
+ err = ricoh619_write(info->dev->parent, CHGISET_REG, 0);
+ if (err < 0)
+ dev_err(info->dev,
+ "Error in writing CHGISET_REG%d\n", err);
+ msleep(1000);
+
+
+ err = ricoh619_write(info->dev->parent,
+ FG_CTRL_REG, 0x51);
+ if (err < 0)
+ dev_err(info->dev, "Error in writing the control register\n");
+
+ msleep(6000);
+
+ err = ricoh619_write(info->dev->parent, CHGISET_REG, val);
+ if (err < 0)
+ dev_err(info->dev,
+ "Error in writing CHGISET_REG%d\n", err);
+ }
+
+ /* Rbat : Transfer */
+ info->soca->Rbat = get_OCV_init_Data(info, 12) * 1000 / 512
+ * 5000 / 4095;
+ info->soca->n_cap = get_OCV_init_Data(info, 11);
+
+ info->soca->displayed_soc = 0;
+ info->soca->ready_fg = 0;
+ info->soca->soc_delta = 0;
+ info->soca->status = RICOH619_SOCA_START;
+ /* stable count down 11->2, 1: reset; 0: Finished; */
+ info->soca->stable_count = 11;
+
+#ifdef ENABLE_FG_KEEP_ON_MODE
+ g_fg_on_mode = 1;
+#else
+ g_fg_on_mode = 0;
+#endif
+
+ /* Start first Display job */
+ queue_delayed_work(info->monitor_wqueue, &info->displayed_work,
+ RICOH619_FG_RESET_TIME*HZ);
+
+ /* Start first Waiting stable job */
+ queue_delayed_work(info->monitor_wqueue, &info->charge_stable_work,
+ RICOH619_FG_STABLE_TIME*HZ/10);
+
+ RICOH_FG_DBG("PMU: %s : * Rbat = %d mOhm n_cap = %d mAH\n",
+ __func__, info->soca->Rbat, info->soca->n_cap);
+ return 1;
+}
+#endif
+
+static void ricoh619_changed_work(struct work_struct *work)
+{
+ struct ricoh619_battery_info *info = container_of(work,
+ struct ricoh619_battery_info, changed_work.work);
+
+ RICOH_FG_DBG("PMU: %s\n", __func__);
+ power_supply_changed(&info->battery);
+
+ return;
+}
+
+#ifdef ENABLE_FACTORY_MODE
+/*------------------------------------------------------*/
+/* Factory Mode */
+/* Check Battery exist or not */
+/* If not, disabled Rapid to Complete State change */
+/*------------------------------------------------------*/
+static int ricoh619_factory_mode(struct ricoh619_battery_info *info)
+{
+ int ret = 0;
+ uint8_t val = 0;
+
+ ret = ricoh619_read(info->dev->parent, RICOH619_INT_MON_CHGCTR, &val);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in reading the control register\n");
+ return ret;
+ }
+ if (!(val & 0x01)) /* No Adapter connected */
+ return ret;
+
+ /* Rapid to Complete State change disable */
+ ret = ricoh619_write(info->dev->parent, RICOH619_CHG_CTL1, 0xe3);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in writing the control register\n");
+ return ret;
+ }
+
+ /* Wait 1s for checking Charging State */
+ queue_delayed_work(info->factory_mode_wqueue, &info->factory_mode_work,
+ 1*HZ);
+
+ return ret;
+}
+
+static void check_charging_state_work(struct work_struct *work)
+{
+ struct ricoh619_battery_info *info = container_of(work,
+ struct ricoh619_battery_info, factory_mode_work.work);
+
+ int ret = 0;
+ uint8_t val = 0;
+ int chargeCurrent = 0;
+
+ ret = ricoh619_read(info->dev->parent, CHGSTATE_REG, &val);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in reading the control register\n");
+ return;
+ }
+
+
+ chargeCurrent = get_check_fuel_gauge_reg(info, CC_AVERAGE1_REG,
+ CC_AVERAGE0_REG, 0x3fff);
+ if (chargeCurrent < 0) {
+ dev_err(info->dev, "Error in reading the FG register\n");
+ return;
+ }
+
+ /* Repid State && Charge Current about 0mA */
+ if (((chargeCurrent > 0x3ffc && chargeCurrent < 0x3fff)
+ || chargeCurrent < 0x05) && val == 0x43) {
+ RICOH_FG_DBG("PMU:%s --- No battery !! Enter Factory mode ---\n"
+ , __func__);
+ info->entry_factory_mode = true;
+ return; /* Factory Mode */
+ }
+
+ /* Return Normal Mode --> Rapid to Complete State change enable */
+ ret = ricoh619_write(info->dev->parent, RICOH619_CHG_CTL1, 0xa3);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in writing the control register\n");
+ return;
+ }
+ RICOH_FG_DBG("PMU:%s --- Battery exist !! Return Normal mode ---0x%2x\n"
+ , __func__, val);
+
+ return;
+}
+#endif /* ENABLE_FACTORY_MODE */
+
+static int Calc_Linear_Interpolation(int x0, int y0, int x1, int y1, int y)
+{
+ int alpha;
+ int x;
+
+ alpha = (y - y0)*100 / (y1 - y0);
+
+ x = ((100 - alpha) * x0 + alpha * x1) / 100;
+
+ return x;
+}
+
+static int ricoh619_set_OCV_table(struct ricoh619_battery_info *info)
+{
+ int ret = 0;
+ int ocv_table[11];
+ int i, j;
+ int available_cap;
+ int temp;
+ int start_par;
+ int percent_step;
+ int OCV_percent_new[11];
+
+ if (CUTOFF_VOL == 0) { /* normal version */
+ } else { /*Slice cutoff voltage version. */
+
+ /* get ocv table. this table is calculated by Apprication */
+ for (i = 0; i <= 10; i = i+1) {
+ temp = (battery_init_para[i*2]<<8)
+ | (battery_init_para[i*2+1]);
+ /* conversion unit 1 Unit is 1.22mv (5000/4095 mv) */
+ temp = ((temp * 50000 * 10 / 4095) + 5) / 10;
+ ocv_table[i] = temp;
+ }
+
+
+ /* Check Start % */
+ for (i = 1; i < 11; i++) {
+ if (ocv_table[i] >= CUTOFF_VOL * 10) {
+ /* unit is 0.001% */
+ start_par = Calc_Linear_Interpolation(
+ (i-1)*1000, ocv_table[i-1], i*1000,
+ ocv_table[i], (CUTOFF_VOL * 10));
+ i = 11;
+ }
+ }
+ /* calc new ocv percent */
+ percent_step = (10000 - start_par) / 10;
+
+ for (i = 0; i < 11; i++) {
+ OCV_percent_new[i]
+ = start_par + percent_step*(i - 0);
+ }
+
+ /* calc new ocv voltage */
+ for (i = 0; i < 11; i++) {
+ for (j = 1; j < 11; j++) {
+ if (1000*j >= OCV_percent_new[i]) {
+ temp = Calc_Linear_Interpolation(
+ ocv_table[j-1], (j-1)*1000,
+ ocv_table[j] , j*1000,
+ OCV_percent_new[i]);
+
+ temp = temp * 4095 / 50000;
+
+ battery_init_para[i*2 + 1] = temp;
+ battery_init_para[i*2] = temp >> 8;
+
+ j = 11;
+ }
+ }
+ }
+
+ /* calc available capacity */
+ /* get avilable capacity */
+ /* battery_init_para23-24 is designe capacity */
+ available_cap = (battery_init_para[22]<<8)
+ | (battery_init_para[23]);
+
+ available_cap = available_cap
+ * ((10000 - start_par) / 100) / 100 ;
+
+
+ battery_init_para[23] = available_cap;
+ battery_init_para[22] = available_cap >> 8;
+
+ }
+ ret = ricoh619_bulk_writes_bank1(info->dev->parent,
+ BAT_INIT_TOP_REG, 32, battery_init_para);
+ if (ret < 0) {
+ dev_err(info->dev, "batterry initialize error\n");
+ return ret;
+ }
+
+ return 1;
+}
+
+/* Initial setting of battery */
+static int ricoh619_init_battery(struct ricoh619_battery_info *info)
+{
+ int ret = 0;
+ uint8_t val;
+ /* Need to implement initial setting of batery and error */
+ /* -------------------------- */
+#ifdef ENABLE_FUEL_GAUGE_FUNCTION
+
+ /* set kanwa state */
+ if (RICOH619_REL1_SEL_VALUE > 240)
+ val = 0x0F;
+ else
+ val = RICOH619_REL1_SEL_VALUE / 16 ;
+
+ val = 0x20 + val;
+
+ ret = ricoh619_write_bank1(info->dev->parent, BAT_REL_SEL_REG, val);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in writing the OCV Tabler\n");
+ return ret;
+ }
+
+ ret = ricoh619_read(info->dev->parent, FG_CTRL_REG, &val);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in reading the control register\n");
+ return ret;
+ }
+
+ val = (val & 0x10) >> 4;
+ info->first_pwon = (val == 0) ? 1 : 0;
+
+ ret = ricoh619_set_OCV_table(info);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in writing the OCV Tabler\n");
+ return ret;
+ }
+
+ ret = ricoh619_write(info->dev->parent, FG_CTRL_REG, 0x11);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in writing the control register\n");
+ return ret;
+ }
+
+#endif
+
+ if (info->alarm_vol_mv < 2700 || info->alarm_vol_mv > 3400) {
+ dev_err(info->dev, "alarm_vol_mv is out of range!\n");
+ return -1;
+ }
+
+ return ret;
+}
+
+/* Initial setting of charger */
+static int ricoh619_init_charger(struct ricoh619_battery_info *info)
+{
+ int err;
+ uint8_t val;
+ uint8_t val2;
+
+ info->chg_ctr = 0;
+ info->chg_stat1 = 0;
+
+ /* In suspend - disable charging */
+ err = ricoh619_clr_bits(info->dev->parent,CHGCTL1_REG, 0x03);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing the control register\n");
+ goto free_device;
+ }
+
+ if (RICOH619_MAX_ADP_CURRENT != 0) {
+ /* Change ADP Current to 2.5A. */
+ err = ricoh619_write(info->dev->parent, 0xb6,
+ (RICOH619_MAX_ADP_CURRENT-1)/100);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing INT_MSK_CHGSTS1 %d\n",
+ err);
+ goto free_device;
+ }
+ }
+
+ if (RICOH619_MAX_USB_CURRENT != 0) {
+ /* Set Max Change USB Current (0xB7) */
+ err = ricoh619_write(info->dev->parent, REGISET2_REG,
+ (RICOH619_MAX_USB_CURRENT-1)/100);
+ if (err < 0) {
+ dev_err(info->dev,
+ "Error in writing RICOH619_MAX_USB_CURRENT %d\n", err);
+ goto free_device;
+ }
+ }
+
+ /* Set Charge competion current (0xB8) */
+ /* this value for bit 4-0 */
+ if (RICOH619_MAX_CHARGE_CURRENT != 0) {
+ val = (RICOH619_MAX_CHARGE_CURRENT-1)/100;
+ } else {
+ err = ricoh619_read(info->dev->parent, CHGISET_REG, &val);
+ if (err < 0) {
+ dev_err(info->dev,
+ "Error in read RICOH619_MAX_CHARGE_CURRENT %d\n", err);
+ goto free_device;
+ }
+ val &= 0x3F;
+ }
+
+ /* Set Charge competion current (0xB8) */
+ /* this value for bit 7-6 */
+ if(RICOH619_CHARGE_COMPLETION_CURRENT != 0) {
+ val2 = (RICOH619_CHARGE_COMPLETION_CURRENT - 50) / 50;
+ } else {
+ err = ricoh619_read(info->dev->parent, CHGISET_REG, &val2);
+ if (err < 0) {
+ dev_err(info->dev,
+ "Error in read RICOH619_MAX_CHARGE_CURRENT %d\n", err);
+ goto free_device;
+ }
+ val2 &= 0xC0;
+ }
+ val = val + (val2 << 6);
+ err = ricoh619_write(info->dev->parent, CHGISET_REG, val);
+ if (err < 0) {
+ dev_err(info->dev,
+ "Error in writing RICOH619_MAX_CHARGE_CURRENT %d\n", err);
+ goto free_device;
+ }
+
+ /* Change Charger Voltege to 4.2V. Recharge Point to 4.1V */
+ /* for define FULL charging voltage (bit 6~4)*/
+ if (RICOH619_FULL_CHARGING_VOLTAGE != 0) {
+ if (RICOH619_FULL_CHARGING_VOLTAGE < 4050)
+ val2 = 0x00;
+ else if (RICOH619_FULL_CHARGING_VOLTAGE > 4200)
+ val2 = 0x04;
+ else
+ val2 = (RICOH619_FULL_CHARGING_VOLTAGE - 4050) / 50;
+ } else {
+ err = ricoh619_read(info->dev->parent, BATSET2_REG, &val2);
+ if (err < 0) {
+ dev_err(info->dev,
+ "Error in read RICOH619_FULL_CHARGE_VOLTAGE %d\n", err);
+ goto free_device;
+ }
+ val2 &= 0x70;
+ }
+
+ /* for define re-charging voltage (bit 2~0)*/
+ if (RICOH619_RE_CHARGING_VOLTAGE != 0) {
+ if (RICOH619_RE_CHARGING_VOLTAGE < 3850)
+ val = 0x00;
+ else if (RICOH619_RE_CHARGING_VOLTAGE > 4000)
+ val = 0x04;
+ else
+ val = (RICOH619_RE_CHARGING_VOLTAGE - 3850) / 50;
+ } else {
+ err = ricoh619_read(info->dev->parent, BATSET2_REG, &val);
+ if (err < 0) {
+ dev_err(info->dev,
+ "Error in read RICOH619_RE_CHARGE_VOLTAGE %d\n", err);
+ goto free_device;
+ }
+ val &= 0x07;
+ }
+
+ val = val + (val2 << 4);
+
+ err = ricoh619_write(info->dev->parent, BATSET2_REG, val);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing RICOH619_RE_CHARGE_VOLTAGE %d\n",
+ err);
+ goto free_device;
+ }
+
+ /* out suspend - enable charging */
+ err = ricoh619_set_bits(info->dev->parent,CHGCTL1_REG, 0x03);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing the control register\n");
+ goto free_device;
+ }
+
+ /* Set rising edge setting ([1:0]=01b)for INT in charging */
+ /* and rising edge setting ([3:2]=01b)for charge completion */
+ err = ricoh619_read(info->dev->parent, RICOH619_CHG_STAT_DETMOD1, &val);
+ if (err < 0) {
+ dev_err(info->dev, "Error in reading CHG_STAT_DETMOD1 %d\n",
+ err);
+ goto free_device;
+ }
+ val &= 0xf0;
+ val |= 0x05;
+ err = ricoh619_write(info->dev->parent, RICOH619_CHG_STAT_DETMOD1, val);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing CHG_STAT_DETMOD1 %d\n",
+ err);
+ goto free_device;
+ }
+
+ /* Unmask In charging/charge completion */
+ err = ricoh619_write(info->dev->parent, RICOH619_INT_MSK_CHGSTS1, 0xfc);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing INT_MSK_CHGSTS1 %d\n",
+ err);
+ goto free_device;
+ }
+
+ /* Set both edge for VUSB([3:2]=11b)/VADP([1:0]=11b) detect */
+ err = ricoh619_read(info->dev->parent, RICOH619_CHG_CTRL_DETMOD1, &val);
+ if (err < 0) {
+ dev_err(info->dev, "Error in reading CHG_CTRL_DETMOD1 %d\n",
+ err);
+ goto free_device;
+ }
+ val &= 0xf0;
+ val |= 0x0f;
+ err = ricoh619_write(info->dev->parent, RICOH619_CHG_CTRL_DETMOD1, val);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing CHG_CTRL_DETMOD1 %d\n",
+ err);
+ goto free_device;
+ }
+
+ /* Unmask In VUSB/VADP completion */
+ err = ricoh619_write(info->dev->parent, RICOH619_INT_MSK_CHGCTR, 0xfc);
+ if (err < 0) {
+ dev_err(info->dev, "Error in writing INT_MSK_CHGSTS1 %d\n",
+ err);
+ goto free_device;
+ }
+
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+ /* Set ADRQ=00 to stop ADC */
+ ricoh619_write(info->dev->parent, RICOH619_ADC_CNT3, 0x0);
+ /* Enable VSYS threshold Low interrupt */
+ ricoh619_write(info->dev->parent, RICOH619_INT_EN_ADC1, 0x10);
+ /* Set ADC auto conversion interval 250ms */
+ ricoh619_write(info->dev->parent, RICOH619_ADC_CNT2, 0x0);
+ /* Enable VSYS pin conversion in auto-ADC */
+ ricoh619_write(info->dev->parent, RICOH619_ADC_CNT1, 0x10);
+ /* Set VSYS threshold low voltage = 3.50v */
+ ricoh619_write(info->dev->parent, RICOH619_ADC_VSYS_THL, 0x77);
+ /* Start auto-mode & average 4-time conversion mode for ADC */
+ ricoh619_write(info->dev->parent, RICOH619_ADC_CNT3, 0x28);
+ /* Enable master ADC INT */
+ ricoh619_set_bits(info->dev->parent, RICOH619_INTC_INTEN, ADC_INT);
+#endif
+
+free_device:
+ return err;
+}
+
+
+static int get_power_supply_status(struct ricoh619_battery_info *info)
+{
+ uint8_t status;
+ uint8_t supply_state;
+ uint8_t charge_state;
+ int ret = 0;
+
+ /* get power supply status */
+ ret = ricoh619_read(info->dev->parent, CHGSTATE_REG, &status);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in reading the control register\n");
+ return ret;
+ }
+
+ charge_state = (status & 0x1F);
+ supply_state = ((status & 0xC0) >> 6);
+
+ if (supply_state == SUPPLY_STATE_BAT) {
+ info->soca->chg_status = POWER_SUPPLY_STATUS_DISCHARGING;
+ } else {
+ switch (charge_state) {
+ case CHG_STATE_CHG_OFF:
+ info->soca->chg_status
+ = POWER_SUPPLY_STATUS_DISCHARGING;
+ break;
+ case CHG_STATE_CHG_READY_VADP:
+ info->soca->chg_status
+ = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ case CHG_STATE_CHG_TRICKLE:
+ info->soca->chg_status
+ = POWER_SUPPLY_STATUS_CHARGING;
+ break;
+ case CHG_STATE_CHG_RAPID:
+ info->soca->chg_status
+ = POWER_SUPPLY_STATUS_CHARGING;
+ break;
+ case CHG_STATE_CHG_COMPLETE:
+ info->soca->chg_status
+ = POWER_SUPPLY_STATUS_FULL;
+ break;
+ case CHG_STATE_SUSPEND:
+ info->soca->chg_status
+ = POWER_SUPPLY_STATUS_DISCHARGING;
+ break;
+ case CHG_STATE_VCHG_OVER_VOL:
+ info->soca->chg_status
+ = POWER_SUPPLY_STATUS_DISCHARGING;
+ break;
+ case CHG_STATE_BAT_ERROR:
+ info->soca->chg_status
+ = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ case CHG_STATE_NO_BAT:
+ info->soca->chg_status
+ = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ case CHG_STATE_BAT_OVER_VOL:
+ info->soca->chg_status
+ = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ case CHG_STATE_BAT_TEMP_ERR:
+ info->soca->chg_status
+ = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ case CHG_STATE_DIE_ERR:
+ info->soca->chg_status
+ = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ case CHG_STATE_DIE_SHUTDOWN:
+ info->soca->chg_status
+ = POWER_SUPPLY_STATUS_DISCHARGING;
+ break;
+ case CHG_STATE_NO_BAT2:
+ info->soca->chg_status
+ = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ case CHG_STATE_CHG_READY_VUSB:
+ info->soca->chg_status
+ = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ default:
+ info->soca->chg_status
+ = POWER_SUPPLY_STATUS_UNKNOWN;
+ break;
+ }
+ }
+
+ return info->soca->chg_status;
+}
+
+static void charger_irq_work(struct work_struct *work)
+{
+ struct ricoh619_battery_info *info
+ = container_of(work, struct ricoh619_battery_info, irq_work);
+ int ret = 0;
+ RICOH_FG_DBG("PMU:%s In\n", __func__);
+
+ power_supply_changed(&info->battery);
+
+ mutex_lock(&info->lock);
+ info->chg_ctr = 0;
+ info->chg_stat1 = 0;
+
+ /* Enable Interrupt for VADP */
+ ret = ricoh619_clr_bits(info->dev->parent,
+ RICOH619_INT_MSK_CHGCTR, 0x01);
+ if (ret < 0)
+ dev_err(info->dev,
+ "%s(): Error in enable charger mask INT %d\n",
+ __func__, ret);
+
+ /* Enable Interrupt for Charging & complete */
+ ret = ricoh619_write(info->dev->parent, RICOH619_INT_MSK_CHGSTS1, 0xfc);
+ if (ret < 0)
+ dev_err(info->dev,
+ "%s(): Error in enable charger mask INT %d\n",
+ __func__, ret);
+
+ mutex_unlock(&info->lock);
+ RICOH_FG_DBG("PMU:%s Out\n", __func__);
+}
+
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+static void low_battery_irq_work(struct work_struct *work)
+{
+ struct ricoh619_battery_info *info = container_of(work,
+ struct ricoh619_battery_info, low_battery_work.work);
+
+ int ret = 0;
+
+ RICOH_FG_DBG("PMU:%s In\n", __func__);
+
+ power_supply_changed(&info->battery);
+
+ /* Enable VADP threshold Low interrupt */
+ ricoh619_write(info->dev->parent, RICOH619_INT_EN_ADC1, 0x10);
+ if (ret < 0)
+ dev_err(info->dev,
+ "%s(): Error in enable adc mask INT %d\n",
+ __func__, ret);
+}
+#endif
+
+static void usb_det_irq_work(struct work_struct *work)
+{
+ struct ricoh619_battery_info *info = container_of(work,
+ struct ricoh619_battery_info, usb_irq_work);
+ int ret = 0;
+ uint8_t sts;
+ int time =0;
+
+ RICOH_FG_DBG("PMU:%s In\n", __func__);
+
+ power_supply_changed(&info->battery);
+
+ mutex_lock(&info->lock);
+
+ /* Enable Interrupt for VUSB */
+ ret = ricoh619_clr_bits(info->dev->parent,
+ RICOH619_INT_MSK_CHGCTR, 0x02);
+ if (ret < 0)
+ dev_err(info->dev,
+ "%s(): Error in enable charger mask INT %d\n",
+ __func__, ret);
+
+ mutex_unlock(&info->lock);
+
+ ret = ricoh619_read(info->dev->parent, RICOH619_INT_MON_CHGCTR, &sts);
+ if (ret < 0)
+ dev_err(info->dev, "Error in reading the control register\n");
+
+ sts &= 0x02;
+ if (sts) {
+
+ } else {
+ /*********************/
+ /* No process ?? */
+ /*********************/
+ }
+
+ RICOH_FG_DBG("PMU:%s Out\n", __func__);
+}
+
+extern void rk28_send_wakeup_key(void);
+static irqreturn_t charger_in_isr(int irq, void *battery_info)
+{
+ struct ricoh619_battery_info *info = battery_info;
+ printk("PMU:%s\n", __func__);
+
+ info->chg_stat1 |= 0x01;
+ queue_work(info->workqueue, &info->irq_work);
+ rk28_send_wakeup_key();
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t charger_complete_isr(int irq, void *battery_info)
+{
+ struct ricoh619_battery_info *info = battery_info;
+ printk("PMU:%s\n", __func__);
+
+ info->chg_stat1 |= 0x02;
+ queue_work(info->workqueue, &info->irq_work);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t charger_usb_isr(int irq, void *battery_info)
+{
+ struct ricoh619_battery_info *info = battery_info;
+ printk("PMU:%s\n", __func__);
+
+ info->chg_ctr |= 0x02;
+ queue_work(info->usb_workqueue, &info->usb_irq_work);
+ rk28_send_wakeup_key();
+
+ if (RICOH619_SOCA_UNSTABLE == info->soca->status
+ || RICOH619_SOCA_FG_RESET == info->soca->status)
+ info->soca->stable_count = 11;
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t charger_adp_isr(int irq, void *battery_info)
+{
+ struct ricoh619_battery_info *info = battery_info;
+ struct ricoh619 *ricoh619 = g_ricoh619;
+ printk("PMU:%s\n", __func__);
+
+ info->chg_ctr |= 0x01;
+ queue_work(info->workqueue, &info->irq_work);
+ rk28_send_wakeup_key();
+ /* clr usb det irq */
+ ricoh619_clr_bits(ricoh619->dev, RICOH619_INT_IR_CHGCTR,
+ info->chg_ctr);
+
+ /* set adp limit current 2A */
+ ricoh619_write(ricoh619->dev, 0xb6, 0x13);
+ /* set charge current 2A */
+ ricoh619_write(ricoh619->dev, 0xb8, 0x13);
+
+ if (RICOH619_SOCA_UNSTABLE == info->soca->status
+ || RICOH619_SOCA_FG_RESET == info->soca->status)
+ info->soca->stable_count = 11;
+
+ return IRQ_HANDLED;
+}
+
+
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+/*************************************************************/
+/* for Detecting Low Battery */
+/*************************************************************/
+
+static irqreturn_t adc_vsysl_isr(int irq, void *battery_info)
+{
+
+ struct ricoh619_battery_info *info = battery_info;
+
+#if 0
+ RICOH_FG_DBG("PMU:%s\n", __func__);
+
+ queue_delayed_work(info->monitor_wqueue, &info->low_battery_work,
+ LOW_BATTERY_DETECTION_TIME*HZ);
+
+#endif
+
+ RICOH_FG_DBG("PMU:%s\n", __func__);
+ ricoh619_write(info->dev->parent, RICOH619_INT_EN_ADC1, 0x10);
+ rk28_send_wakeup_key();
+
+ return IRQ_HANDLED;
+}
+#endif
+
+
+#ifdef ENABLE_FUEL_GAUGE_FUNCTION
+static int get_check_fuel_gauge_reg(struct ricoh619_battery_info *info,
+ int Reg_h, int Reg_l, int enable_bit)
+{
+ uint8_t get_data_h, get_data_l;
+ int old_data, current_data;
+ int i;
+ int ret = 0;
+
+ old_data = 0;
+
+ for (i = 0; i < 5 ; i++) {
+ ret = ricoh619_read(info->dev->parent, Reg_h, &get_data_h);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in reading the control register\n");
+ return ret;
+ }
+
+ ret = ricoh619_read(info->dev->parent, Reg_l, &get_data_l);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in reading the control register\n");
+ return ret;
+ }
+
+ current_data = ((get_data_h & 0xff) << 8) | (get_data_l & 0xff);
+ current_data = (current_data & enable_bit);
+
+ if (current_data == old_data)
+ return current_data;
+ else
+ old_data = current_data;
+ }
+
+ return current_data;
+}
+
+static int calc_capacity(struct ricoh619_battery_info *info)
+{
+ uint8_t capacity;
+ int temp;
+ int ret = 0;
+
+ /* get remaining battery capacity from fuel gauge */
+ ret = ricoh619_read(info->dev->parent, SOC_REG, &capacity);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in reading the control register\n");
+ return ret;
+ }
+
+ temp = capacity;
+
+ return temp; /* Unit is 1% */
+}
+
+static int get_battery_temp(struct ricoh619_battery_info *info)
+{
+ int ret = 0;
+ int sign_bit;
+
+ ret = get_check_fuel_gauge_reg(info, TEMP_1_REG, TEMP_2_REG, 0x0fff);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in reading the fuel gauge control register\n");
+ return ret;
+ }
+
+ /* bit3 of 0xED(TEMP_1) is sign_bit */
+ sign_bit = ((ret & 0x0800) >> 11);
+
+ ret = (ret & 0x07ff);
+
+ if (sign_bit == 0) /* positive value part */
+ /* conversion unit */
+ /* 1 unit is 0.0625 degree and retun unit
+ * should be 0.1 degree,
+ */
+ ret = ret * 625 / 1000;
+ else /*negative value part */
+ ret = -1 * ret * 625 / 1000;
+
+ return ret;
+}
+
+static int get_time_to_empty(struct ricoh619_battery_info *info)
+{
+ int ret = 0;
+
+ ret = get_check_fuel_gauge_reg(info, TT_EMPTY_H_REG, TT_EMPTY_L_REG,
+ 0xffff);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in reading the fuel gauge control register\n");
+ return ret;
+ }
+
+ /* conversion unit */
+ /* 1unit is 1miniute and return nnit should be 1 second */
+ ret = ret * 60;
+
+ return ret;
+}
+
+static int get_time_to_full(struct ricoh619_battery_info *info)
+{
+ int ret = 0;
+
+ ret = get_check_fuel_gauge_reg(info, TT_FULL_H_REG, TT_FULL_L_REG,
+ 0xffff);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in reading the fuel gauge control register\n");
+ return ret;
+ }
+
+ ret = ret * 60;
+
+ return ret;
+}
+
+/* battery voltage is get from Fuel gauge */
+static int measure_vbatt_FG(struct ricoh619_battery_info *info, int *data)
+{
+ int ret = 0;
+
+ ret = get_check_fuel_gauge_reg(info, VOLTAGE_1_REG, VOLTAGE_2_REG,
+ 0x0fff);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in reading the fuel gauge control register\n");
+ return ret;
+ }
+
+ *data = ret;
+ /* conversion unit 1 Unit is 1.22mv (5000/4095 mv) */
+ *data = *data * 50000 / 4095;
+ /* return unit should be 1uV */
+ *data = *data * 100;
+
+ return ret;
+}
+
+static int measure_Ibatt_FG(struct ricoh619_battery_info *info, int *data)
+{
+ int ret = 0;
+
+ ret = get_check_fuel_gauge_reg(info, CC_AVERAGE1_REG,
+ CC_AVERAGE0_REG, 0x3fff);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in reading the fuel gauge control register\n");
+ return ret;
+ }
+
+ *data = (ret > 0x1fff) ? (ret - 0x4000) : ret;
+ return ret;
+}
+
+static int get_OCV_init_Data(struct ricoh619_battery_info *info, int index)
+{
+ int ret = 0;
+ ret = (battery_init_para[index*2]<<8) | (battery_init_para[index*2+1]);
+ return ret;
+}
+
+static int get_OCV_voltage(struct ricoh619_battery_info *info, int index)
+{
+ int ret = 0;
+ ret = get_OCV_init_Data(info, index);
+ /* conversion unit 1 Unit is 1.22mv (5000/4095 mv) */
+ ret = ret * 50000 / 4095;
+ /* return unit should be 1uV */
+ ret = ret * 100;
+ return ret;
+}
+
+#else
+/* battery voltage is get from ADC */
+static int measure_vbatt_ADC(struct ricoh619_battery_info *info, int *data)
+{
+ int i;
+ uint8_t data_l = 0, data_h = 0;
+ int ret;
+
+ /* ADC interrupt enable */
+ ret = ricoh619_set_bits(info->dev->parent, INTEN_REG, 0x08);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in setting the control register bit\n");
+ goto err;
+ }
+
+ /* enable interrupt request of single mode */
+ ret = ricoh619_set_bits(info->dev->parent, EN_ADCIR3_REG, 0x01);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in setting the control register bit\n");
+ goto err;
+ }
+
+ /* single request */
+ ret = ricoh619_write(info->dev->parent, ADCCNT3_REG, 0x10);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in writing the control register\n");
+ goto err;
+ }
+
+ for (i = 0; i < 5; i++) {
+ usleep(1000);
+ RICOH_FG_DBG("ADC conversion times: %d\n", i);
+ /* read completed flag of ADC */
+ ret = ricoh619_read(info->dev->parent, EN_ADCIR3_REG, &data_h);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in reading the control register\n");
+ goto err;
+ }
+
+ if (data_h & 0x01)
+ goto done;
+ }
+
+ dev_err(info->dev, "ADC conversion too long!\n");
+ goto err;
+
+done:
+ ret = ricoh619_read(info->dev->parent, VBATDATAH_REG, &data_h);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in reading the control register\n");
+ goto err;
+ }
+
+ ret = ricoh619_read(info->dev->parent, VBATDATAL_REG, &data_l);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in reading the control register\n");
+ goto err;
+ }
+
+ *data = ((data_h & 0xff) << 4) | (data_l & 0x0f);
+ /* conversion unit 1 Unit is 1.22mv (5000/4095 mv) */
+ *data = *data * 5000 / 4095;
+ /* return unit should be 1uV */
+ *data = *data * 1000;
+
+ return 0;
+
+err:
+ return -1;
+}
+#endif
+
+/*
+static void ricoh619_external_power_changed(struct power_supply *psy)
+{
+ struct ricoh619_battery_info *info;
+
+ info = container_of(psy, struct ricoh619_battery_info, battery);
+ queue_delayed_work(info->monitor_wqueue,
+ &info->changed_work, HZ / 2);
+ return;
+}
+*/
+
+static int ricoh619_batt_get_prop(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct ricoh619_battery_info *info = dev_get_drvdata(psy->dev->parent);
+ int data = 0;
+ int ret = 0;
+ uint8_t status;
+
+ mutex_lock(&info->lock);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ ret = ricoh619_read(info->dev->parent, CHGSTATE_REG, &status);
+ if (ret < 0) {
+ dev_err(info->dev, "Error in reading the control register\n");
+ mutex_unlock(&info->lock);
+ return ret;
+ }
+ if (psy->type == POWER_SUPPLY_TYPE_MAINS)
+ val->intval = (status & 0x40 ? 1 : 0);
+ else if (psy->type == POWER_SUPPLY_TYPE_USB)
+ val->intval = (status & 0x80 ? 1 : 0);
+ break;
+ /* this setting is same as battery driver of 584 */
+ case POWER_SUPPLY_PROP_STATUS:
+ ret = get_power_supply_status(info);
+ val->intval = ret;
+ info->status = ret;
+ /* RICOH_FG_DBG("Power Supply Status is %d\n",
+ info->status); */
+ break;
+
+ /* this setting is same as battery driver of 584 */
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = info->present;
+ break;
+
+ /* current voltage is get from fuel gauge */
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ /* return real vbatt Voltage */
+#ifdef ENABLE_FUEL_GAUGE_FUNCTION
+ if (info->soca->ready_fg)
+ ret = measure_vbatt_FG(info, &data);
+ else {
+ val->intval = -EINVAL;
+ RICOH_FG_DBG( "battery voltage is not ready\n");
+ break;
+ }
+#else
+ ret = measure_vbatt_ADC(info, &data);
+#endif
+ val->intval = data;
+ /* convert unit uV -> mV */
+ info->cur_voltage = data / 1000;
+ RICOH_FG_DBG( "battery voltage is %d mV\n",
+ info->cur_voltage);
+ break;
+
+#ifdef ENABLE_FUEL_GAUGE_FUNCTION
+ /* current battery capacity is get from fuel gauge */
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = (info->soca->displayed_soc + 50)/100;
+ info->capacity = (info->soca->displayed_soc + 50)/100;
+ /* RICOH_FG_DBG("battery capacity is %d%%\n",
+ info->capacity); */
+ break;
+
+ /* current temperature of battery */
+ case POWER_SUPPLY_PROP_TEMP:
+ if (info->soca->ready_fg) {
+ ret = get_battery_temp(info);
+ val->intval = ret;
+ info->battery_temp = ret/10;
+ RICOH_FG_DBG( "battery temperature is %d degree\n", info->battery_temp);
+ } else {
+ val->intval = -EINVAL;
+ RICOH_FG_DBG("battery temperature is not ready\n");
+ }
+ break;
+
+ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
+ if (info->soca->ready_fg) {
+ ret = get_time_to_empty(info);
+ val->intval = ret;
+ info->time_to_empty = ret/60;
+ RICOH_FG_DBG("time of empty battery is %d minutes\n", info->time_to_empty);
+ } else {
+ val->intval = -EINVAL;
+ RICOH_FG_DBG( "time of empty battery is not ready\n");
+ }
+ break;
+
+ case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
+ if (info->soca->ready_fg) {
+ ret = get_time_to_full(info);
+ val->intval = ret;
+ info->time_to_full = ret/60;
+ RICOH_FG_DBG( "time of full battery is %d minutes\n", info->time_to_full);
+ } else {
+ val->intval = -EINVAL;
+ RICOH_FG_DBG("time of full battery is not ready\n");
+ }
+ break;
+#endif
+ case POWER_SUPPLY_PROP_TECHNOLOGY:
+ val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+ ret = 0;
+ break;
+
+ case POWER_SUPPLY_PROP_HEALTH:
+ val->intval = POWER_SUPPLY_HEALTH_GOOD;
+ ret = 0;
+ break;
+
+ default:
+ mutex_unlock(&info->lock);
+ return -ENODEV;
+ }
+
+ mutex_unlock(&info->lock);
+
+ return ret;
+}
+
+static enum power_supply_property ricoh619_batt_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+
+#ifdef ENABLE_FUEL_GAUGE_FUNCTION
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
+ POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
+#endif
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_HEALTH,
+};
+
+static enum power_supply_property ricoh619_power_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
+struct power_supply powerac = {
+ .name = "acpwr",
+ .type = POWER_SUPPLY_TYPE_MAINS,
+ .properties = ricoh619_power_props,
+ .num_properties = ARRAY_SIZE(ricoh619_power_props),
+ .get_property = ricoh619_batt_get_prop,
+};
+
+struct power_supply powerusb = {
+ .name = "usbpwr",
+ .type = POWER_SUPPLY_TYPE_USB,
+ .properties = ricoh619_power_props,
+ .num_properties = ARRAY_SIZE(ricoh619_power_props),
+ .get_property = ricoh619_batt_get_prop,
+};
+
+static __devinit int ricoh619_battery_probe(struct platform_device *pdev)
+{
+ struct ricoh619_battery_info *info;
+ struct ricoh619_battery_platform_data *pdata;
+ int ret;
+
+ RICOH_FG_DBG("PMU: %s\n", __func__);
+
+ info = kzalloc(sizeof(struct ricoh619_battery_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+ info->soca = kzalloc(sizeof(struct ricoh619_soca_info), GFP_KERNEL);
+ if (!info->soca)
+ return -ENOMEM;
+
+ info->dev = &pdev->dev;
+ info->status = POWER_SUPPLY_STATUS_CHARGING;
+ pdata = pdev->dev.platform_data;
+ info->monitor_time = pdata->monitor_time * HZ;
+ info->alarm_vol_mv = pdata->alarm_vol_mv;
+ info->adc_vdd_mv = ADC_VDD_MV; /* 2800; */
+ info->min_voltage = MIN_VOLTAGE; /* 3100; */
+ info->max_voltage = MAX_VOLTAGE; /* 4200; */
+ info->delay = 500;
+ info->entry_factory_mode = false;
+
+ mutex_init(&info->lock);
+ platform_set_drvdata(pdev, info);
+
+ info->battery.name = "battery";
+ info->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+ info->battery.properties = ricoh619_batt_props;
+ info->battery.num_properties = ARRAY_SIZE(ricoh619_batt_props);
+ info->battery.get_property = ricoh619_batt_get_prop;
+ info->battery.set_property = NULL;
+/* info->battery.external_power_changed
+ = ricoh619_external_power_changed; */
+
+ /* Disable Charger/ADC interrupt */
+ ret = ricoh619_clr_bits(info->dev->parent, RICOH619_INTC_INTEN,
+ CHG_INT | ADC_INT);
+ if (ret)
+ goto out;
+
+ ret = ricoh619_init_battery(info);
+ if (ret)
+ goto out;
+
+#ifdef ENABLE_FACTORY_MODE
+ info->factory_mode_wqueue
+ = create_singlethread_workqueue("ricoh619_factory_mode");
+ INIT_DELAYED_WORK_DEFERRABLE(&info->factory_mode_work,
+ check_charging_state_work);
+
+ ret = ricoh619_factory_mode(info);
+ if (ret)
+ goto out;
+
+#endif
+
+ ret = power_supply_register(&pdev->dev, &info->battery);
+
+ if (ret)
+ info->battery.dev->parent = &pdev->dev;
+
+ ret = power_supply_register(&pdev->dev, &powerac);
+ ret = power_supply_register(&pdev->dev, &powerusb);
+
+ info->monitor_wqueue
+ = create_singlethread_workqueue("ricoh619_battery_monitor");
+ INIT_DELAYED_WORK_DEFERRABLE(&info->monitor_work,
+ ricoh619_battery_work);
+ INIT_DELAYED_WORK_DEFERRABLE(&info->displayed_work,
+ ricoh619_displayed_work);
+ INIT_DELAYED_WORK_DEFERRABLE(&info->charge_stable_work,
+ ricoh619_stable_charge_countdown_work);
+ INIT_DELAYED_WORK(&info->changed_work, ricoh619_changed_work);
+ queue_delayed_work(info->monitor_wqueue, &info->monitor_work,
+ RICOH619_MONITOR_START_TIME*HZ);
+
+
+ /* Charger IRQ workqueue settings */
+ charger_irq = pdata->irq;
+
+ info->workqueue = create_singlethread_workqueue("rc5t619_charger_in");
+ INIT_WORK(&info->irq_work, charger_irq_work);
+
+ ret = request_threaded_irq(charger_irq + RICOH619_IRQ_FONCHGINT,
+ NULL, charger_in_isr, IRQF_ONESHOT,
+ "rc5t619_charger_in", info);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Can't get CHG_INT IRQ for chrager: %d\n",
+ ret);
+ goto out;
+ }
+ info->workqueue = create_singlethread_workqueue("rc5t619_charger_in");
+ INIT_WORK(&info->irq_work, charger_irq_work);
+
+ ret = request_threaded_irq(charger_irq + RICOH619_IRQ_FCHGCMPINT,
+ NULL, charger_complete_isr,
+ IRQF_ONESHOT, "rc5t619_charger_comp",
+ info);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Can't get CHG_COMP IRQ for chrager: %d\n",
+ ret);
+ goto out;
+ }
+
+ ret = request_threaded_irq(charger_irq + RICOH619_IRQ_FVUSBDETSINT,
+ NULL, charger_usb_isr, IRQF_ONESHOT,
+ "rc5t619_usb_det", info);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Can't get USB_DET IRQ for chrager: %d\n",
+ ret);
+ goto out;
+ }
+
+ ret = request_threaded_irq(charger_irq + RICOH619_IRQ_FVADPDETSINT,
+ NULL, charger_adp_isr, IRQF_ONESHOT,
+ "rc5t619_adp_det", info);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "Can't get ADP_DET IRQ for chrager: %d\n", ret);
+ goto out;
+ }
+
+ info->usb_workqueue
+ = create_singlethread_workqueue("rc5t619_usb_det");
+ INIT_WORK(&info->usb_irq_work, usb_det_irq_work);
+
+
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+ ret = request_threaded_irq(charger_irq + RICOH619_IRQ_VSYSLIR,
+ NULL, adc_vsysl_isr, IRQF_ONESHOT,
+ "rc5t619_adc_vsysl", info);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "Can't get ADC_VSYSL IRQ for chrager: %d\n", ret);
+ goto out;
+ }
+ INIT_DELAYED_WORK_DEFERRABLE(&info->low_battery_work,
+ low_battery_irq_work);
+#endif
+
+ /* Charger init and IRQ setting */
+ ret = ricoh619_init_charger(info);
+ if (ret)
+ goto out;
+
+#ifdef ENABLE_FUEL_GAUGE_FUNCTION
+ ret = ricoh619_init_fgsoca(info);
+#endif
+
+ /* Enable Charger interrupt */
+ ricoh619_set_bits(info->dev->parent, RICOH619_INTC_INTEN, CHG_INT);
+
+ return 0;
+
+out:
+ kfree(info);
+ return ret;
+}
+
+static int __devexit ricoh619_battery_remove(struct platform_device *pdev)
+{
+ struct ricoh619_battery_info *info = platform_get_drvdata(pdev);
+ uint8_t val;
+ int ret;
+ int err;
+ int cc_cap = 0;
+ bool is_charging = true;
+
+ if (g_fg_on_mode
+ && (info->soca->status == RICOH619_SOCA_STABLE)) {
+ err = ricoh619_write(info->dev->parent, PSWR_REG, 0x7f);
+ if (err < 0)
+ dev_err(info->dev, "Error in writing PSWR_REG\n");
+ g_soc = 0x7f;
+ } else {
+ val = (info->soca->displayed_soc + 50)/100;
+ val &= 0x7f;
+ ret = ricoh619_write(info->dev->parent, PSWR_REG, val);
+ if (ret < 0)
+ dev_err(info->dev, "Error in writing PSWR_REG\n");
+
+ g_soc = (info->soca->displayed_soc + 50)/100;
+
+ ret = calc_capacity_in_period(info, &cc_cap, &is_charging);
+ if (ret < 0)
+ dev_err(info->dev, "Read cc_sum Error !!-----\n");
+ }
+
+ if (g_fg_on_mode == 0) {
+ ret = ricoh619_clr_bits(info->dev->parent,
+ FG_CTRL_REG, 0x01);
+ if (ret < 0)
+ dev_err(info->dev, "Error in clr FG EN\n");
+ }
+
+ cancel_delayed_work(&info->monitor_work);
+ cancel_delayed_work(&info->charge_stable_work);
+ cancel_delayed_work(&info->changed_work);
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+ cancel_delayed_work(&info->low_battery_work);
+#endif
+
+ flush_work(&info->irq_work);
+ flush_work(&info->usb_irq_work);
+
+ flush_workqueue(info->monitor_wqueue);
+ flush_workqueue(info->workqueue);
+ flush_workqueue(info->usb_workqueue);
+
+ destroy_workqueue(info->monitor_wqueue);
+ destroy_workqueue(info->workqueue);
+ destroy_workqueue(info->usb_workqueue);
+
+ power_supply_unregister(&info->battery);
+ kfree(info);
+ platform_set_drvdata(pdev, NULL);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ricoh619_battery_suspend(struct device *dev)
+{
+ struct ricoh619_battery_info *info = dev_get_drvdata(dev);
+ uint8_t val;
+ int ret;
+ int err;
+ int cc_cap = 0;
+ bool is_charging = true;
+
+ if (g_fg_on_mode
+ && (info->soca->status == RICOH619_SOCA_STABLE)) {
+ err = ricoh619_write(info->dev->parent, PSWR_REG, 0x7f);
+ if (err < 0)
+ dev_err(info->dev, "Error in writing PSWR_REG\n");
+ g_soc = 0x7F;
+ } else {
+ val = (info->soca->displayed_soc + 50)/100;
+ val &= 0x7f;
+ ret = ricoh619_write(info->dev->parent, PSWR_REG, val);
+ if (ret < 0)
+ dev_err(info->dev, "Error in writing PSWR_REG\n");
+
+ g_soc = (info->soca->displayed_soc + 50)/100;
+
+ ret = calc_capacity_in_period(info, &cc_cap, &is_charging);
+ if (ret < 0)
+ dev_err(info->dev, "Read cc_sum Error !!-----\n");
+ }
+
+ disable_irq(charger_irq + RICOH619_IRQ_FONCHGINT);
+ disable_irq(charger_irq + RICOH619_IRQ_FCHGCMPINT);
+ disable_irq(charger_irq + RICOH619_IRQ_FVUSBDETSINT);
+ disable_irq(charger_irq + RICOH619_IRQ_FVADPDETSINT);
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+ disable_irq(charger_irq + RICOH619_IRQ_VSYSLIR);
+#endif
+
+ cancel_delayed_work_sync(&info->monitor_work);
+ cancel_delayed_work_sync(&info->displayed_work);
+ cancel_delayed_work_sync(&info->charge_stable_work);
+ cancel_delayed_work_sync(&info->changed_work);
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+ cancel_delayed_work_sync(&info->low_battery_work);
+#endif
+ cancel_work_sync(&info->irq_work);
+ cancel_work_sync(&info->usb_irq_work);
+
+ flush_workqueue(info->monitor_wqueue);
+ flush_workqueue(info->workqueue);
+ flush_workqueue(info->usb_workqueue);
+
+ return 0;
+}
+
+static int ricoh619_battery_resume(struct device *dev)
+{
+ struct ricoh619_battery_info *info = dev_get_drvdata(dev);
+ uint8_t val;
+ int ret;
+ int displayed_soc_temp;
+ int cc_cap = 0;
+ bool is_charging = true;
+ int i;
+
+ if (info->entry_factory_mode) {
+ info->soca->displayed_soc = -EINVAL;
+ } else if (RICOH619_SOCA_STABLE == info->soca->status) {
+ info->soca->soc = calc_capacity(info) * 100;
+ info->soca->displayed_soc = info->soca->soc;
+ } else if (RICOH619_SOCA_ZERO == info->soca->status) {
+ if (calc_ocv(info) > get_OCV_voltage(info, 0)) {
+ ret = ricoh619_read(info->dev->parent, PSWR_REG, &val);
+ val &= 0x7f;
+ info->soca->soc = val * 100;
+ if ((ret < 0) || (val == 0)) {
+ dev_err(info->dev,
+ "Error in reading PSWR_REG %d\n", ret);
+ info->soca->soc
+ = calc_capacity(info) * 100 + 50;
+ }
+
+ ret = calc_capacity_in_period(info, &cc_cap,
+ &is_charging);
+ if (ret < 0)
+ dev_err(info->dev, "Read cc_sum Error !!-----\n");
+
+ info->soca->cc_delta
+ = (is_charging == true) ? cc_cap : -cc_cap;
+
+ displayed_soc_temp
+ = info->soca->soc + info->soca->cc_delta;
+ displayed_soc_temp = min(10000, displayed_soc_temp);
+ displayed_soc_temp = max(0, displayed_soc_temp);
+ info->soca->displayed_soc = displayed_soc_temp;
+
+ ret = ricoh619_write(info->dev->parent,
+ FG_CTRL_REG, 0x51);
+ if (ret < 0)
+ dev_err(info->dev, "Error in writing the control register\n");
+ info->soca->ready_fg = 0;
+ info->soca->status = RICOH619_SOCA_FG_RESET;
+
+ } else
+ info->soca->displayed_soc = 0;
+ } else {
+ ret = ricoh619_read(info->dev->parent, PSWR_REG, &val);
+ val &= 0x7f;
+ info->soca->soc = val * 100;
+ if ((ret < 0) || (val == 0)) {
+ dev_err(info->dev,
+ "Error in reading PSWR_REG %d\n", ret);
+ info->soca->soc
+ = calc_capacity(info) * 100 + 50;
+ }
+
+ ret = calc_capacity_in_period(info, &cc_cap, &is_charging);
+ if (ret < 0)
+ dev_err(info->dev, "Read cc_sum Error !!-----\n");
+
+ info->soca->cc_delta = (is_charging == true) ? cc_cap : -cc_cap;
+
+ displayed_soc_temp = info->soca->soc + info->soca->cc_delta;
+ displayed_soc_temp = min(10000, displayed_soc_temp);
+ displayed_soc_temp = max(0, displayed_soc_temp);
+ info->soca->displayed_soc = displayed_soc_temp;
+ if (RICOH619_SOCA_DISP == info->soca->status)
+ info->soca->last_soc = calc_capacity(info) * 100;
+ }
+
+ power_supply_changed(&info->battery);
+ queue_delayed_work(info->monitor_wqueue, &info->displayed_work, HZ);
+
+ if (RICOH619_SOCA_UNSTABLE == info->soca->status) {
+ info->soca->stable_count = 10;
+ queue_delayed_work(info->monitor_wqueue,
+ &info->charge_stable_work,
+ RICOH619_FG_STABLE_TIME*HZ/10);
+ } else if (RICOH619_SOCA_FG_RESET == info->soca->status) {
+ info->soca->stable_count = 1;
+
+ for (i = 0; i < 3; i = i+1)
+ info->soca->reset_soc[i] = 0;
+ info->soca->reset_count = 0;
+
+ queue_delayed_work(info->monitor_wqueue,
+ &info->charge_stable_work,
+ RICOH619_FG_RESET_TIME*HZ);
+ }
+
+ queue_delayed_work(info->monitor_wqueue, &info->monitor_work,
+ info->monitor_time);
+
+ enable_irq(charger_irq + RICOH619_IRQ_FONCHGINT);
+ enable_irq(charger_irq + RICOH619_IRQ_FCHGCMPINT);
+ enable_irq(charger_irq + RICOH619_IRQ_FVUSBDETSINT);
+ enable_irq(charger_irq + RICOH619_IRQ_FVADPDETSINT);
+#ifdef ENABLE_LOW_BATTERY_DETECTION
+ enable_irq(charger_irq + RICOH619_IRQ_VSYSLIR);
+#endif
+ return 0;
+}
+
+static const struct dev_pm_ops ricoh619_battery_pm_ops = {
+ .suspend = ricoh619_battery_suspend,
+ .resume = ricoh619_battery_resume,
+};
+#endif
+
+static struct platform_driver ricoh619_battery_driver = {
+ .driver = {
+ .name = "ricoh619-battery",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &ricoh619_battery_pm_ops,
+#endif
+ },
+ .probe = ricoh619_battery_probe,
+ .remove = __devexit_p(ricoh619_battery_remove),
+};
+
+static int __init ricoh619_battery_init(void)
+{
+ RICOH_FG_DBG("PMU: %s\n", __func__);
+ return platform_driver_register(&ricoh619_battery_driver);
+}
+subsys_initcall_sync(ricoh619_battery_init);
+
+static void __exit ricoh619_battery_exit(void)
+{
+ platform_driver_unregister(&ricoh619_battery_driver);
+}
+module_exit(ricoh619_battery_exit);
+
+MODULE_DESCRIPTION("RICOH619 Battery driver");
+MODULE_ALIAS("platform:ricoh619-battery");
+MODULE_LICENSE("GPL");
This driver provides support for the voltage regulators on the
WM8994 CODEC.
+config REGULATOR_RICOH619
+ tristate "RICOH 619 Power regulators"
+ depends on MFD_RICOH619
+ default n
+ help
+ This driver supports regulator driver for RICOH619 PMIC.
+
config REGULATOR_DA903X
tristate "Support regulators on Dialog Semiconductor DA9030/DA9034 PMIC"
depends on PMIC_DA903X
obj-$(CONFIG_REGULATOR_ACT8891) += act8891.o
obj-$(CONFIG_REGULATOR_ACT8931) += act8931.o
obj-$(CONFIG_REGULATOR_ACT8846) += act8846.o
+obj-$(CONFIG_REGULATOR_RICOH619) += ricoh619-regulator.o
ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
--- /dev/null
+/*
+ * drivers/regulator/ricoh619-regulator.c
+ *
+ * Regulator driver for RICOH619 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*#define DEBUG 1*/
+/*#define VERBOSE_DEBUG 1*/
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/ricoh619.h>
+#include <linux/regulator/ricoh619-regulator.h>
+
+struct ricoh619_regulator {
+ int id;
+ int sleep_id;
+ /* Regulator register address.*/
+ u8 reg_en_reg;
+ u8 en_bit;
+ u8 reg_disc_reg;
+ u8 disc_bit;
+ u8 vout_reg;
+ u8 vout_mask;
+ u8 vout_reg_cache;
+ u8 sleep_reg;
+ u8 eco_reg;
+ u8 eco_bit;
+ u8 eco_slp_reg;
+ u8 eco_slp_bit;
+
+ /* chip constraints on regulator behavior */
+ int min_uV;
+ int max_uV;
+ int step_uV;
+ int nsteps;
+
+ /* regulator specific turn-on delay */
+ u16 delay;
+
+ /* used by regulator core */
+ struct regulator_desc desc;
+
+ /* Device */
+ struct device *dev;
+};
+
+//static unsigned int ricoh619_suspend_status = 0;
+
+static inline struct device *to_ricoh619_dev(struct regulator_dev *rdev)
+{
+ return rdev_get_dev(rdev)->parent->parent;
+}
+
+static int ricoh619_regulator_enable_time(struct regulator_dev *rdev)
+{
+ struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+
+ return ri->delay;
+}
+
+static int ricoh619_reg_is_enabled(struct regulator_dev *rdev)
+{
+ struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+ struct device *parent = to_ricoh619_dev(rdev);
+ uint8_t control;
+ int ret;
+
+ ret = ricoh619_read(parent, ri->reg_en_reg, &control);
+ if (ret < 0) {
+ dev_err(&rdev->dev, "Error in reading the control register\n");
+ return ret;
+ }
+ return (((control >> ri->en_bit) & 1) == 1);
+}
+
+static int ricoh619_reg_enable(struct regulator_dev *rdev)
+{
+ struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+ struct device *parent = to_ricoh619_dev(rdev);
+ int ret;
+ ret = ricoh619_set_bits(parent, ri->reg_en_reg, (1 << ri->en_bit));
+ if (ret < 0) {
+ dev_err(&rdev->dev, "Error in updating the STATE register\n");
+ return ret;
+ }
+ udelay(ri->delay);
+ return ret;
+}
+
+static int ricoh619_reg_disable(struct regulator_dev *rdev)
+{
+ struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+ struct device *parent = to_ricoh619_dev(rdev);
+ int ret;
+ ret = ricoh619_clr_bits(parent, ri->reg_en_reg, (1 << ri->en_bit));
+ if (ret < 0)
+ dev_err(&rdev->dev, "Error in updating the STATE register\n");
+
+ return ret;
+}
+
+static int ricoh619_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+ struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+
+ return ri->min_uV + (ri->step_uV * index);
+}
+
+static int __ricoh619_set_s_voltage(struct device *parent,
+ struct ricoh619_regulator *ri, int min_uV, int max_uV)
+{
+ int vsel;
+ int ret;
+
+ if ((min_uV < ri->min_uV) || (max_uV > ri->max_uV))
+ return -EDOM;
+
+ vsel = (min_uV - ri->min_uV + ri->step_uV - 1)/ri->step_uV;
+ if (vsel > ri->nsteps)
+ return -EDOM;
+
+ ret = ricoh619_update(parent, ri->sleep_reg, vsel, ri->vout_mask);
+ if (ret < 0)
+ dev_err(ri->dev, "Error in writing the sleep register\n");
+ return ret;
+}
+
+static int __ricoh619_set_voltage(struct device *parent,
+ struct ricoh619_regulator *ri, int min_uV, int max_uV,
+ unsigned *selector)
+{
+ int vsel;
+ int ret;
+ uint8_t vout_val;
+
+ if ((min_uV < ri->min_uV) || (max_uV > ri->max_uV))
+ return -EDOM;
+
+ vsel = (min_uV - ri->min_uV + ri->step_uV - 1)/ri->step_uV;
+ if (vsel > ri->nsteps)
+ return -EDOM;
+
+ if (selector)
+ *selector = vsel;
+
+ vout_val = (ri->vout_reg_cache & ~ri->vout_mask) |
+ (vsel & ri->vout_mask);
+ ret = ricoh619_write(parent, ri->vout_reg, vout_val);
+ if (ret < 0)
+ dev_err(ri->dev, "Error in writing the Voltage register\n");
+ else
+ ri->vout_reg_cache = vout_val;
+
+ return ret;
+}
+
+static int ricoh619_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV, unsigned *selector)
+{
+ struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+ struct device *parent = to_ricoh619_dev(rdev);
+
+// if(ricoh619_suspend_status)
+// return -EBUSY;
+
+ return __ricoh619_set_voltage(parent, ri, min_uV, max_uV, selector);
+}
+
+static int ricoh619_set_suspend_voltage(struct regulator_dev *rdev,
+ int uV)
+{
+ struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+ struct device *parent = to_ricoh619_dev(rdev);
+
+ return __ricoh619_set_s_voltage(parent, ri, uV, uV);
+}
+
+static int ricoh619_get_voltage(struct regulator_dev *rdev)
+{
+ struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+ uint8_t vsel;
+
+ vsel = ri->vout_reg_cache & ri->vout_mask;
+ return ri->min_uV + vsel * ri->step_uV;
+}
+
+ int ricoh619_regulator_enable_eco_mode(struct regulator_dev *rdev)
+{
+ struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+ struct device *parent = to_ricoh619_dev(rdev);
+ int ret;
+
+ ret = ricoh619_set_bits(parent, ri->eco_reg, (1 << ri->eco_bit));
+ if (ret < 0)
+ dev_err(&rdev->dev, "Error Enable LDO eco mode\n");
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_regulator_enable_eco_mode);
+
+int ricoh619_regulator_disable_eco_mode(struct regulator_dev *rdev)
+{
+ struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+ struct device *parent = to_ricoh619_dev(rdev);
+ int ret;
+
+ ret = ricoh619_clr_bits(parent, ri->eco_reg, (1 << ri->eco_bit));
+ if (ret < 0)
+ dev_err(&rdev->dev, "Error Disable LDO eco mode\n");
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_regulator_disable_eco_mode);
+
+int ricoh619_regulator_enable_eco_slp_mode(struct regulator_dev *rdev)
+{
+ struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+ struct device *parent = to_ricoh619_dev(rdev);
+ int ret;
+
+ ret = ricoh619_set_bits(parent, ri->eco_slp_reg, (1 << ri->eco_slp_bit));
+ if (ret < 0)
+ dev_err(&rdev->dev, "Error Enable LDO eco mode in d during sleep\n");
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_regulator_enable_eco_slp_mode);
+
+int ricoh619_regulator_disable_eco_slp_mode(struct regulator_dev *rdev)
+{
+ struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+ struct device *parent = to_ricoh619_dev(rdev);
+ int ret;
+
+ ret = ricoh619_clr_bits(parent, ri->eco_slp_reg, (1 << ri->eco_slp_bit));
+ if (ret < 0)
+ dev_err(&rdev->dev, "Error Enable LDO eco mode in d during sleep\n");
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ricoh619_regulator_disable_eco_slp_mode);
+
+static unsigned int ricoh619_dcdc_get_mode(struct regulator_dev *rdev)
+{
+ struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+ struct device *parent = to_ricoh619_dev(rdev);
+ int ret;
+ uint8_t control;
+ u8 mask = 0x30;
+
+ ret = ricoh619_read(parent, ri->reg_en_reg,&control);
+ if (ret < 0) {
+ return ret;
+ }
+ control=(control & mask) >> 4;
+ switch (control) {
+ case 1:
+ return REGULATOR_MODE_FAST;
+ case 0:
+ return REGULATOR_MODE_NORMAL;
+ case 2:
+ return REGULATOR_MODE_STANDBY;
+ case 4:
+ return REGULATOR_MODE_NORMAL;
+ default:
+ return -1;
+ }
+
+}
+static int ricoh619_dcdc_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ struct ricoh619_regulator *ri = rdev_get_drvdata(rdev);
+ struct device *parent = to_ricoh619_dev(rdev);
+ int ret;
+ uint8_t control;
+
+ ret = ricoh619_read(parent, ri->reg_en_reg,&control);
+ switch(mode)
+ {
+ case REGULATOR_MODE_FAST:
+ return ricoh619_write(parent, ri->reg_en_reg, ((control & 0xef) | 0x10));
+ case REGULATOR_MODE_NORMAL:
+ return ricoh619_write(parent, ri->reg_en_reg, (control & 0xcf));
+ case REGULATOR_MODE_STANDBY:
+ return ricoh619_write(parent, ri->reg_en_reg, ((control & 0xdf) | 0x20));
+ default:
+ printk("error:pmu_619 only powersave pwm psm mode\n");
+ return -EINVAL;
+ }
+
+
+}
+
+static int ricoh619_dcdc_set_voltage_time_sel(struct regulator_dev *rdev, unsigned int old_selector,
+ unsigned int new_selector)
+{
+ int old_volt, new_volt;
+
+ old_volt = ricoh619_list_voltage(rdev, old_selector);
+ if (old_volt < 0)
+ return old_volt;
+
+ new_volt = ricoh619_list_voltage(rdev, new_selector);
+ if (new_volt < 0)
+ return new_volt;
+
+ return DIV_ROUND_UP(abs(old_volt - new_volt)*2, 14000);
+}
+
+
+static struct regulator_ops ricoh619_ops = {
+ .list_voltage = ricoh619_list_voltage,
+ .set_voltage = ricoh619_set_voltage,
+ .get_voltage = ricoh619_get_voltage,
+ .set_suspend_voltage = ricoh619_set_suspend_voltage,
+ .set_voltage_time_sel = ricoh619_dcdc_set_voltage_time_sel,
+ .get_mode = ricoh619_dcdc_get_mode,
+ .set_mode = ricoh619_dcdc_set_mode,
+ .enable = ricoh619_reg_enable,
+ .disable = ricoh619_reg_disable,
+ .is_enabled = ricoh619_reg_is_enabled,
+};
+
+#define RICOH619_REG(_id, _en_reg, _en_bit, _disc_reg, _disc_bit, _vout_reg, \
+ _vout_mask, _ds_reg, _min_uv, _max_uv, _step_uV, _nsteps, \
+ _ops, _delay, _eco_reg, _eco_bit, _eco_slp_reg, _eco_slp_bit) \
+{ \
+ .reg_en_reg = _en_reg, \
+ .en_bit = _en_bit, \
+ .reg_disc_reg = _disc_reg, \
+ .disc_bit = _disc_bit, \
+ .vout_reg = _vout_reg, \
+ .vout_mask = _vout_mask, \
+ .sleep_reg = _ds_reg, \
+ .min_uV = _min_uv, \
+ .max_uV = _max_uv , \
+ .step_uV = _step_uV, \
+ .nsteps = _nsteps, \
+ .delay = _delay, \
+ .id = RICOH619_ID_##_id, \
+ .sleep_id = RICOH619_DS_##_id, \
+ .eco_reg = _eco_reg, \
+ .eco_bit = _eco_bit, \
+ .eco_slp_reg = _eco_slp_reg, \
+ .eco_slp_bit = _eco_slp_bit, \
+ .desc = { \
+ .name = ricoh619_rails(_id), \
+ .id = RICOH619_ID_##_id, \
+ .n_voltages = _nsteps, \
+ .ops = &_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ }, \
+}
+
+static struct ricoh619_regulator ricoh619_regulator[] = {
+ RICOH619_REG(DC1, 0x2C, 0, 0x2C, 1, 0x36, 0xFF, 0x3B,
+ 600000, 3500000, 12500, 0xE8, ricoh619_ops, 500,
+ 0x00, 0, 0x00, 0),
+
+ RICOH619_REG(DC2, 0x2E, 0, 0x2E, 1, 0x37, 0xFF, 0x3C,
+ 600000, 3500000, 12500, 0xE8, ricoh619_ops, 500,
+ 0x00, 0, 0x00, 0),
+
+ RICOH619_REG(DC3, 0x30, 0, 0x30, 1, 0x38, 0xFF, 0x3D,
+ 600000, 3500000, 12500, 0xE8, ricoh619_ops, 500,
+ 0x00, 0, 0x00, 0),
+
+ RICOH619_REG(DC4, 0x32, 0, 0x32, 1, 0x39, 0xFF, 0x3E,
+ 600000, 3500000, 12500, 0xE8, ricoh619_ops, 500,
+ 0x00, 0, 0x00, 0),
+
+ RICOH619_REG(DC5, 0x34, 0, 0x34, 1, 0x3A, 0xFF, 0x3F,
+ 600000, 3500000, 12500, 0xE8, ricoh619_ops, 500,
+ 0x00, 0, 0x00, 0),
+
+ RICOH619_REG(LDO1, 0x44, 0, 0x46, 0, 0x4C, 0x7F, 0x58,
+ 900000, 3500000, 25000, 0x68, ricoh619_ops, 500,
+ 0x48, 0, 0x4A, 0),
+
+ RICOH619_REG(LDO2, 0x44, 1, 0x46, 1, 0x4D, 0x7F, 0x59,
+ 900000, 3500000, 25000, 0x68, ricoh619_ops, 500,
+ 0x48, 1, 0x4A, 1),
+
+ RICOH619_REG(LDO3, 0x44, 2, 0x46, 2, 0x4E, 0x7F, 0x5A,
+ 900000, 3500000, 25000, 0x68, ricoh619_ops, 500,
+ 0x48, 2, 0x4A, 2),
+
+ RICOH619_REG(LDO4, 0x44, 3, 0x46, 3, 0x4F, 0x7F, 0x5B,
+ 900000, 3500000, 25000, 0x68, ricoh619_ops, 500,
+ 0x48, 3, 0x4A, 3),
+
+ RICOH619_REG(LDO5, 0x44, 4, 0x46, 4, 0x50, 0x7F, 0x5C,
+ 600000, 3500000, 25000, 0x74, ricoh619_ops, 500,
+ 0x48, 4, 0x4A, 4),
+
+ RICOH619_REG(LDO6, 0x44, 5, 0x46, 5, 0x51, 0x7F, 0x5D,
+ 600000, 3500000, 25000, 0x74, ricoh619_ops, 500,
+ 0x48, 5, 0x4A, 5),
+
+ RICOH619_REG(LDO7, 0x44, 6, 0x46, 6, 0x52, 0x7F, 0x5E,
+ 900000, 3500000, 25000, 0x68, ricoh619_ops, 500,
+ 0x00, 0, 0x00, 0),
+
+ RICOH619_REG(LDO8, 0x44, 7, 0x46, 7, 0x53, 0x7F, 0x5F,
+ 900000, 3500000, 25000, 0x68, ricoh619_ops, 500,
+ 0x00, 0, 0x00, 0),
+
+ RICOH619_REG(LDO9, 0x45, 0, 0x47, 0, 0x54, 0x7F, 0x60,
+ 900000, 3500000, 25000, 0x68, ricoh619_ops, 500,
+ 0x00, 0, 0x00, 0),
+
+ RICOH619_REG(LDO10, 0x45, 1, 0x47, 1, 0x55, 0x7F, 0x61,
+ 900000, 3500000, 25000, 0x68, ricoh619_ops, 500,
+ 0x00, 0, 0x00, 0),
+
+ RICOH619_REG(LDORTC1, 0x45, 4, 0x00, 0, 0x56, 0x7F, 0x00,
+ 1700000, 3500000, 25000, 0x48, ricoh619_ops, 500,
+ 0x00, 0, 0x00, 0),
+
+ RICOH619_REG(LDORTC2, 0x45, 5, 0x00, 0, 0x57, 0x7F, 0x00,
+ 900000, 3500000, 25000, 0x68, ricoh619_ops, 500,
+ 0x00, 0, 0x00, 0),
+};
+static inline struct ricoh619_regulator *find_regulator_info(int id)
+{
+ struct ricoh619_regulator *ri;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ricoh619_regulator); i++) {
+ ri = &ricoh619_regulator[i];
+ if (ri->desc.id == id)
+ return ri;
+ }
+ return NULL;
+}
+
+static int ricoh619_regulator_preinit(struct device *parent,
+ struct ricoh619_regulator *ri,
+ struct ricoh619_regulator_platform_data *ricoh619_pdata)
+{
+ int ret = 0;
+
+ if (!ricoh619_pdata->init_apply)
+ return 0;
+/*
+ if (ricoh619_pdata->init_uV >= 0) {
+ ret = __ricoh619_set_voltage(parent, ri,
+ ricoh619_pdata->init_uV,
+ ricoh619_pdata->init_uV, 0);
+ if (ret < 0) {
+ dev_err(ri->dev, "Not able to initialize voltage %d "
+ "for rail %d err %d\n", ricoh619_pdata->init_uV,
+ ri->desc.id, ret);
+ return ret;
+ }
+ }
+*/
+ if (ricoh619_pdata->init_enable)
+ ret = ricoh619_set_bits(parent, ri->reg_en_reg,
+ (1 << ri->en_bit));
+ else
+ ret = ricoh619_clr_bits(parent, ri->reg_en_reg,
+ (1 << ri->en_bit));
+ if (ret < 0)
+ dev_err(ri->dev, "Not able to %s rail %d err %d\n",
+ (ricoh619_pdata->init_enable) ? "enable" : "disable",
+ ri->desc.id, ret);
+
+ return ret;
+}
+
+static inline int ricoh619_cache_regulator_register(struct device *parent,
+ struct ricoh619_regulator *ri)
+{
+ ri->vout_reg_cache = 0;
+ return ricoh619_read(parent, ri->vout_reg, &ri->vout_reg_cache);
+}
+
+static int __devinit ricoh619_regulator_probe(struct platform_device *pdev)
+{
+ struct ricoh619_regulator *ri = NULL;
+ struct regulator_dev *rdev;
+ struct ricoh619_regulator_platform_data *tps_pdata;
+ int id = pdev->id;
+ int err;
+
+ ri = find_regulator_info(id);
+ if (ri == NULL) {
+ dev_err(&pdev->dev, "invalid regulator ID specified\n");
+ return -EINVAL;
+ }
+ tps_pdata = pdev->dev.platform_data;
+ ri->dev = &pdev->dev;
+/*
+ err = ricoh619_cache_regulator_register(pdev->dev.parent, ri);
+ if (err) {
+ dev_err(&pdev->dev, "Fail in caching register\n");
+ return err;
+ }
+
+ err = ricoh619_regulator_preinit(pdev->dev.parent, ri, tps_pdata);
+ if (err) {
+ dev_err(&pdev->dev, "Fail in pre-initialisation\n");
+ return err;
+ }
+ */
+ rdev = regulator_register(&ri->desc, &pdev->dev,
+ &tps_pdata->regulator, ri);
+ if (IS_ERR_OR_NULL(rdev)) {
+ dev_err(&pdev->dev, "failed to register regulator %s\n",
+ ri->desc.name);
+ return PTR_ERR(rdev);
+ }
+
+ platform_set_drvdata(pdev, rdev);
+ return 0;
+}
+
+static int __devexit ricoh619_regulator_remove(struct platform_device *pdev)
+{
+ struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+ regulator_unregister(rdev);
+ return 0;
+}
+
+static struct platform_driver ricoh619_regulator_driver = {
+ .driver = {
+ .name = "ricoh619-regulator",
+ .owner = THIS_MODULE,
+ },
+ .probe = ricoh619_regulator_probe,
+ .remove = __devexit_p(ricoh619_regulator_remove),
+};
+
+static int __init ricoh619_regulator_init(void)
+{
+
+ return platform_driver_register(&ricoh619_regulator_driver);
+}
+subsys_initcall_sync(ricoh619_regulator_init);
+
+static void __exit ricoh619_regulator_exit(void)
+{
+ platform_driver_unregister(&ricoh619_regulator_driver);
+}
+module_exit(ricoh619_regulator_exit);
+
+MODULE_DESCRIPTION("RICOH619 regulator driver");
+MODULE_ALIAS("platform:ricoh619-regulator");
+MODULE_AUTHOR("zhangqing <zhangqing@rock-chips.com>");
+MODULE_LICENSE("GPL");
depends on MFD_RK808
help
enable rk808 rtc for system
+
+config RTC_DRV_RC5T619
+ tristate "RICOH RC5T619 PMU RTC driver"
+ depends on MFD_RICOH619
+ default n
+ help
+ If you say yes here you get support for the RICOH RC5T619 RTC module.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-rc5t619.
endif # RTC_CLASS
obj-$(CONFIG_RTC_M41T66) += rtc-m41t66.o
obj-$(CONFIG_TPS65910_RTC) += rtc-tps65910.o
obj-$(CONFIG_RK808_RTC) += rtc-rk808.o
+obj-$(CONFIG_RTC_DRV_RC5T619) += rtc-ricoh619.o
--- /dev/null
+/*
+ * drivers/rtc/rtc-ricoh619.c
+ *
+ * Real time clock driver for RICOH RC5T619 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/* #define debug 1 */
+/* #define verbose_debug 1 */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mfd/ricoh619.h>
+#include <linux/rtc/rtc-ricoh619.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+
+struct ricoh619_rtc {
+ unsigned long epoch_start;
+ int irq;
+ struct rtc_device *rtc;
+ bool irq_en;
+};
+
+static int ricoh619_read_regs(struct device *dev, int reg, int len,
+ uint8_t *val)
+{
+ int ret;
+
+ ret = ricoh619_bulk_reads(dev->parent, reg, len, val);
+ if (ret < 0) {
+ dev_err(dev->parent, "\n %s failed reading from 0x%02x\n",
+ __func__, reg);
+ WARN_ON(1);
+ }
+ return ret;
+}
+
+static int ricoh619_write_regs(struct device *dev, int reg, int len,
+ uint8_t *val)
+{
+ int ret;
+ ret = ricoh619_bulk_writes(dev->parent, reg, len, val);
+ if (ret < 0) {
+ dev_err(dev->parent, "\n %s failed writing\n", __func__);
+ WARN_ON(1);
+ }
+
+ return ret;
+}
+
+static int ricoh619_rtc_valid_tm(struct device *dev, struct rtc_time *tm)
+{
+ if (tm->tm_year >= (rtc_year_offset + 99)
+ || tm->tm_mon > 12
+ || tm->tm_mday < 1
+ || tm->tm_mday > rtc_month_days(tm->tm_mon,
+ tm->tm_year + os_ref_year)
+ || tm->tm_hour >= 24
+ || tm->tm_min >= 60
+ || tm->tm_sec >= 60) {
+ dev_err(dev->parent, "\n returning error due to time"
+ "%d/%d/%d %d:%d:%d", tm->tm_mon, tm->tm_mday,
+ tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static u8 dec2bcd(u8 dec)
+{
+ return ((dec/10)<<4)+(dec%10);
+}
+
+static u8 bcd2dec(u8 bcd)
+{
+ return (bcd >> 4)*10+(bcd & 0xf);
+}
+
+static void convert_bcd_to_decimal(u8 *buf, u8 len)
+{
+ int i = 0;
+ for (i = 0; i < len; i++)
+ buf[i] = bcd2dec(buf[i]);
+}
+
+static void convert_decimal_to_bcd(u8 *buf, u8 len)
+{
+ int i = 0;
+ for (i = 0; i < len; i++)
+ buf[i] = dec2bcd(buf[i]);
+}
+
+static void print_time(struct device *dev, struct rtc_time *tm)
+{
+ dev_info(dev, "rtc-time : %d/%d/%d %d:%d\n",
+ (tm->tm_mon + 1), tm->tm_mday, (tm->tm_year + os_ref_year),
+ tm->tm_hour, tm->tm_min);
+}
+
+static int ricoh619_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ u8 buff[7];
+ int err;
+ err = ricoh619_read_regs(dev, rtc_seconds_reg, sizeof(buff), buff);
+ if (err < 0) {
+ dev_err(dev, "\n %s :: failed to read time\n", __FILE__);
+ return err;
+ }
+ convert_bcd_to_decimal(buff, sizeof(buff));
+ tm->tm_sec = buff[0];
+ tm->tm_min = buff[1];
+ tm->tm_hour = buff[2];
+ tm->tm_wday = buff[3];
+ tm->tm_mday = buff[4];
+ tm->tm_mon = buff[5] - 1;
+ tm->tm_year = buff[6] + rtc_year_offset;
+// print_time(dev, tm);
+ return ricoh619_rtc_valid_tm(dev, tm);
+}
+
+static int ricoh619_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ u8 buff[7];
+ int err;
+
+// print_time(dev, tm);
+ buff[0] = tm->tm_sec;
+ buff[1] = tm->tm_min;
+ buff[2] = tm->tm_hour;
+ buff[3] = tm->tm_wday;
+ buff[4] = tm->tm_mday;
+ buff[5] = tm->tm_mon + 1;
+ buff[6] = tm->tm_year - rtc_year_offset;
+
+ convert_decimal_to_bcd(buff, sizeof(buff));
+ err = ricoh619_write_regs(dev, rtc_seconds_reg, sizeof(buff), buff);
+ if (err < 0) {
+ dev_err(dev->parent, "\n failed to program new time\n");
+ return err;
+ }
+
+ return 0;
+}
+static int ricoh619_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm);
+
+static int ricoh619_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct ricoh619_rtc *rtc = dev_get_drvdata(dev);
+ unsigned long seconds;
+ u8 buff[6];
+ int err;
+ struct rtc_time tm;
+
+ if (rtc->irq == -1)
+ return -EIO;
+
+ rtc_tm_to_time(&alrm->time, &seconds);
+ err = ricoh619_rtc_read_time(dev, &tm);
+ if (err) {
+ dev_err(dev, "\n failed to read time\n");
+ return err;
+ }
+ rtc_tm_to_time(&tm, &rtc->epoch_start);
+
+ dev_info(dev->parent, "\n setting alarm to requested time::\n");
+// print_time(dev->parent, &alrm->time);
+
+ if (WARN_ON(alrm->enabled && (seconds < rtc->epoch_start))) {
+ dev_err(dev->parent, "\n can't set alarm to requested time\n");
+ return -EINVAL;
+ }
+
+ if (alrm->enabled && !rtc->irq_en)
+ rtc->irq_en = true;
+ else if (!alrm->enabled && rtc->irq_en)
+ rtc->irq_en = false;
+
+ buff[0] = alrm->time.tm_sec;
+ buff[1] = alrm->time.tm_min;
+ buff[2] = alrm->time.tm_hour;
+ buff[3] = alrm->time.tm_mday;
+ buff[4] = alrm->time.tm_mon + 1;
+ buff[5] = alrm->time.tm_year - rtc_year_offset;
+ convert_decimal_to_bcd(buff, sizeof(buff));
+ buff[3] |= 0x80; /* set DAL_EXT */
+ err = ricoh619_write_regs(dev, rtc_alarm_y_sec, sizeof(buff), buff);
+ if (err) {
+ dev_err(dev->parent, "\n unable to set alarm\n");
+ return -EBUSY;
+ }
+
+ err = ricoh619_read_regs(dev, rtc_ctrl2, 1, buff);
+ if (err) {
+ dev_err(dev->parent, "unable to read rtc_ctrl2 reg\n");
+ return -EBUSY;
+ }
+
+ buff[1] = buff[0] & ~0x81; /* to clear alarm-D flag, and set adjustment parameter */
+ buff[0] = 0x60; /* to enable alarm_d and 24-hour format */
+ err = ricoh619_write_regs(dev, rtc_ctrl1, 2, buff);
+ if (err) {
+ dev_err(dev, "failed programming rtc ctrl regs\n");
+ return -EBUSY;
+ }
+return err;
+}
+
+static int ricoh619_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ u8 buff[6];
+ int err;
+
+ err = ricoh619_read_regs(dev, rtc_alarm_y_sec, sizeof(buff), buff);
+ if (err)
+ return err;
+ buff[3] &= ~0x80; /* clear DAL_EXT */
+ convert_bcd_to_decimal(buff, sizeof(buff));
+
+ alrm->time.tm_sec = buff[0];
+ alrm->time.tm_min = buff[1];
+ alrm->time.tm_hour = buff[2];
+ alrm->time.tm_mday = buff[3];
+ alrm->time.tm_mon = buff[4] - 1;
+ alrm->time.tm_year = buff[5] + rtc_year_offset;
+
+// dev_info(dev->parent, "\n getting alarm time::\n");
+// print_time(dev, &alrm->time);
+
+ return 0;
+}
+
+static const struct rtc_class_ops ricoh619_rtc_ops = {
+ .read_time = ricoh619_rtc_read_time,
+ .set_time = ricoh619_rtc_set_time,
+ .set_alarm = ricoh619_rtc_set_alarm,
+ .read_alarm = ricoh619_rtc_read_alarm,
+};
+
+static irqreturn_t ricoh619_rtc_irq(int irq, void *data)
+{
+ struct device *dev = data;
+ struct ricoh619_rtc *rtc = dev_get_drvdata(dev);
+ u8 reg;
+ int err;
+
+ /* clear alarm-D status bits.*/
+ err = ricoh619_read_regs(dev, rtc_ctrl2, 1, ®);
+ if (err) {
+ dev_err(dev->parent, "unable to read rtc_ctrl2 reg\n");
+ }
+ reg &= ~0x81; /* to clear alarm-D flag, and set adjustment parameter */
+ err = ricoh619_write_regs(dev, rtc_ctrl2, 1, ®);
+ if (err) {
+ dev_err(dev->parent, "unable to program rtc_status reg\n");
+ }
+
+ rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
+ return IRQ_HANDLED;
+}
+
+static int __devinit ricoh619_rtc_probe(struct platform_device *pdev)
+{
+ struct ricoh619_rtc_platform_data *pdata = pdev->dev.platform_data;
+ struct ricoh619_rtc *rtc;
+ struct rtc_time tm;
+ int err;
+ u8 reg;
+ rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
+// printk("%s,line=%d\n", __func__,__LINE__);
+
+ if (!rtc)
+ return -ENOMEM;
+
+ rtc->irq = -1;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform_data specified\n");
+ return -EINVAL;
+ }
+
+ if (pdata->irq < 0)
+ dev_err(&pdev->dev, "\n no irq specified, wakeup is disabled\n");
+
+ dev_set_drvdata(&pdev->dev, rtc);
+ device_init_wakeup(&pdev->dev, 1);
+ rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
+ &ricoh619_rtc_ops, THIS_MODULE);
+
+ if (IS_ERR(rtc->rtc)) {
+ err = PTR_ERR(rtc->rtc);
+ goto fail;
+ }
+
+ reg = 0x20; /* to clear power-on-reset flag */
+ err = ricoh619_write_regs(&pdev->dev, rtc_ctrl2, 1, ®);
+ if (err) {
+ dev_err(&pdev->dev, "failed rtc setup\n");
+ return -EBUSY;
+ }
+
+ reg = 0x60; /* to enable alarm_d and 24-hour format */
+ err = ricoh619_write_regs(&pdev->dev, rtc_ctrl1, 1, ®);
+ if (err) {
+ dev_err(&pdev->dev, "failed rtc setup\n");
+ return -EBUSY;
+ }
+
+ reg = 0; /* clearing RTC Adjust register */
+ err = ricoh619_write_regs(&pdev->dev, rtc_adjust, 1, ®);
+ if (err) {
+ dev_err(&pdev->dev, "unable to program rtc_adjust reg\n");
+ return -EBUSY;
+ }
+
+ err = ricoh619_rtc_read_time(&pdev->dev, &tm);
+ if (err) {
+ dev_err(&pdev->dev, "\n failed to read time\n");
+ return err;
+ }
+ if (ricoh619_rtc_valid_tm(&pdev->dev, &tm)) {
+ if (pdata->time.tm_year < 2000 || pdata->time.tm_year > 2100) {
+ memset(&pdata->time, 0, sizeof(pdata->time));
+ pdata->time.tm_year = rtc_year_offset;
+ pdata->time.tm_mday = 1;
+ } else
+ pdata->time.tm_year -= os_ref_year;
+ err = ricoh619_rtc_set_time(&pdev->dev, &pdata->time);
+ if (err) {
+ dev_err(&pdev->dev, "\n failed to set time\n");
+ return err;
+ }
+ }
+ if (pdata && (pdata->irq >= 0)) {
+ rtc->irq = pdata->irq + RICOH619_IRQ_DALE;
+ err = request_threaded_irq(rtc->irq, NULL, ricoh619_rtc_irq,
+ IRQF_ONESHOT, "rtc_ricoh619",
+ &pdev->dev);
+ if (err) {
+ dev_err(&pdev->dev, "request IRQ:%d fail\n", rtc->irq);
+ rtc->irq = -1;
+ } else {
+ device_init_wakeup(&pdev->dev, 1);
+ enable_irq_wake(rtc->irq);
+ }
+ }
+ return 0;
+
+fail:
+ if (!IS_ERR_OR_NULL(rtc->rtc))
+ rtc_device_unregister(rtc->rtc);
+ kfree(rtc);
+ return err;
+}
+
+static int __devexit ricoh619_rtc_remove(struct platform_device *pdev)
+{
+ struct ricoh619_rtc *rtc = dev_get_drvdata(&pdev->dev);
+
+ if (rtc->irq != -1)
+ free_irq(rtc->irq, rtc);
+ rtc_device_unregister(rtc->rtc);
+ kfree(rtc);
+ return 0;
+}
+
+static struct platform_driver ricoh619_rtc_driver = {
+ .driver = {
+ .name = "rtc_ricoh619",
+ .owner = THIS_MODULE,
+ },
+ .probe = ricoh619_rtc_probe,
+ .remove = __devexit_p(ricoh619_rtc_remove),
+};
+
+static int __init ricoh619_rtc_init(void)
+{
+ return platform_driver_register(&ricoh619_rtc_driver);
+}
+subsys_initcall_sync(ricoh619_rtc_init);
+
+static void __exit ricoh619_rtc_exit(void)
+{
+ platform_driver_unregister(&ricoh619_rtc_driver);
+}
+module_exit(ricoh619_rtc_exit);
+
+MODULE_DESCRIPTION("RICOH RICOH619 RTC driver");
+MODULE_ALIAS("platform:rtc_ricoh619");
+MODULE_AUTHOR("zhangqing <zhangqing@rock-chips.com>");
+MODULE_LICENSE("GPL");
+
--- /dev/null
+/*
+ * include/linux/mfd/ricoh619.h
+ *
+ * Core driver interface to access RICOH RC5T619 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __LINUX_MFD_RICOH619_H
+#define __LINUX_MFD_RICOH619_H
+
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+
+/* Maximum number of main interrupts */
+#define MAX_INTERRUPT_MASKS 13
+#define MAX_MAIN_INTERRUPT 7
+#define MAX_GPEDGE_REG 2
+
+/* Power control register */
+#define RICOH619_PWR_WD 0x0B
+#define RICOH619_PWR_WD_COUNT 0x0C
+#define RICOH619_PWR_FUNC 0x0D
+#define RICOH619_PWR_SLP_CNT 0x0E
+#define RICOH619_PWR_REP_CNT 0x0F
+#define RICOH619_PWR_ON_TIMSET 0x10
+#define RICOH619_PWR_NOE_TIMSET 0x11
+#define RICOH619_PWR_IRSEL 0x15
+
+/* Interrupt enable register */
+#define RICOH619_INT_EN_SYS 0x12
+#define RICOH619_INT_EN_DCDC 0x40
+#define RICOH619_INT_EN_RTC 0xAE
+#define RICOH619_INT_EN_ADC1 0x88
+#define RICOH619_INT_EN_ADC2 0x89
+#define RICOH619_INT_EN_ADC3 0x8A
+#define RICOH619_INT_EN_GPIO 0x94
+#define RICOH619_INT_EN_GPIO2 0x94 // dummy
+#define RICOH619_INT_MSK_CHGCTR 0xBE
+#define RICOH619_INT_MSK_CHGSTS1 0xBF
+#define RICOH619_INT_MSK_CHGSTS2 0xC0
+#define RICOH619_INT_MSK_CHGERR 0xC1
+#define RICOH619_INT_MSK_CHGEXTIF 0xD1
+
+/* Interrupt select register */
+#define RICOH619_PWR_IRSEL 0x15
+#define RICOH619_CHG_CTRL_DETMOD1 0xCA
+#define RICOH619_CHG_CTRL_DETMOD2 0xCB
+#define RICOH619_CHG_STAT_DETMOD1 0xCC
+#define RICOH619_CHG_STAT_DETMOD2 0xCD
+#define RICOH619_CHG_STAT_DETMOD3 0xCE
+
+
+/* interrupt status registers (monitor regs)*/
+#define RICOH619_INTC_INTPOL 0x9C
+#define RICOH619_INTC_INTEN 0x9D
+#define RICOH619_INTC_INTMON 0x9E
+
+#define RICOH619_INT_MON_SYS 0x14
+#define RICOH619_INT_MON_DCDC 0x42
+#define RICOH619_INT_MON_RTC 0xAF
+
+#define RICOH619_INT_MON_CHGCTR 0xC6
+#define RICOH619_INT_MON_CHGSTS1 0xC7
+#define RICOH619_INT_MON_CHGSTS2 0xC8
+#define RICOH619_INT_MON_CHGERR 0xC9
+#define RICOH619_INT_MON_CHGEXTIF 0xD3
+
+/* interrupt clearing registers */
+#define RICOH619_INT_IR_SYS 0x13
+#define RICOH619_INT_IR_DCDC 0x41
+#define RICOH619_INT_IR_RTC 0xAF
+#define RICOH619_INT_IR_ADCL 0x8C
+#define RICOH619_INT_IR_ADCH 0x8D
+#define RICOH619_INT_IR_ADCEND 0x8E
+#define RICOH619_INT_IR_GPIOR 0x95
+#define RICOH619_INT_IR_GPIOF 0x96
+#define RICOH619_INT_IR_CHGCTR 0xC2
+#define RICOH619_INT_IR_CHGSTS1 0xC3
+#define RICOH619_INT_IR_CHGSTS2 0xC4
+#define RICOH619_INT_IR_CHGERR 0xC5
+#define RICOH619_INT_IR_CHGEXTIF 0xD2
+
+/* GPIO register base address */
+#define RICOH619_GPIO_IOSEL 0x90
+#define RICOH619_GPIO_IOOUT 0x91
+#define RICOH619_GPIO_GPEDGE1 0x92
+#define RICOH619_GPIO_GPEDGE2 0x93
+//#define RICOH619_GPIO_EN_GPIR 0x94
+//#define RICOH619_GPIO_IR_GPR 0x95
+//#define RICOH619_GPIO_IR_GPF 0x96
+#define RICOH619_GPIO_MON_IOIN 0x97
+#define RICOH619_GPIO_LED_FUNC 0x98
+
+#define RICOH619_REG_BANKSEL 0xFF
+
+/* Charger Control register */
+#define RICOH619_CHG_CTL1 0xB3
+
+/* ADC Control register */
+#define RICOH619_ADC_CNT1 0x64
+#define RICOH619_ADC_CNT2 0x65
+#define RICOH619_ADC_CNT3 0x66
+#define RICOH619_ADC_VADP_THL 0x7C
+#define RICOH619_ADC_VSYS_THL 0x80
+
+#define RICOH619_FG_CTRL 0xE0
+#define RICOH619_PSWR 0x07
+
+/* RICOH619 IRQ definitions */
+enum {
+ RICOH619_IRQ_POWER_ON,
+ RICOH619_IRQ_EXTIN,
+ RICOH619_IRQ_PRE_VINDT,
+ RICOH619_IRQ_PREOT,
+ RICOH619_IRQ_POWER_OFF,
+ RICOH619_IRQ_NOE_OFF,
+ RICOH619_IRQ_WD,
+ RICOH619_IRQ_CLK_STP,
+
+ RICOH619_IRQ_DC1LIM,
+ RICOH619_IRQ_DC2LIM,
+ RICOH619_IRQ_DC3LIM,
+ RICOH619_IRQ_DC4LIM,
+ RICOH619_IRQ_DC5LIM,
+
+ RICOH619_IRQ_ILIMLIR,
+ RICOH619_IRQ_VBATLIR,
+ RICOH619_IRQ_VADPLIR,
+ RICOH619_IRQ_VUSBLIR,
+ RICOH619_IRQ_VSYSLIR,
+ RICOH619_IRQ_VTHMLIR,
+ RICOH619_IRQ_AIN1LIR,
+ RICOH619_IRQ_AIN0LIR,
+
+ RICOH619_IRQ_ILIMHIR,
+ RICOH619_IRQ_VBATHIR,
+ RICOH619_IRQ_VADPHIR,
+ RICOH619_IRQ_VUSBHIR,
+ RICOH619_IRQ_VSYSHIR,
+ RICOH619_IRQ_VTHMHIR,
+ RICOH619_IRQ_AIN1HIR,
+ RICOH619_IRQ_AIN0HIR,
+
+ RICOH619_IRQ_ADC_ENDIR,
+
+ RICOH619_IRQ_GPIO0,
+ RICOH619_IRQ_GPIO1,
+ RICOH619_IRQ_GPIO2,
+ RICOH619_IRQ_GPIO3,
+ RICOH619_IRQ_GPIO4,
+
+ RICOH619_IRQ_CTC,
+ RICOH619_IRQ_DALE,
+
+ RICOH619_IRQ_FVADPDETSINT,
+ RICOH619_IRQ_FVUSBDETSINT,
+ RICOH619_IRQ_FVADPLVSINT,
+ RICOH619_IRQ_FVUSBLVSINT,
+ RICOH619_IRQ_FWVADPSINT,
+ RICOH619_IRQ_FWVUSBSINT,
+
+ RICOH619_IRQ_FONCHGINT,
+ RICOH619_IRQ_FCHGCMPINT,
+ RICOH619_IRQ_FBATOPENINT,
+ RICOH619_IRQ_FSLPMODEINT,
+ RICOH619_IRQ_FBTEMPJTA1INT,
+ RICOH619_IRQ_FBTEMPJTA2INT,
+ RICOH619_IRQ_FBTEMPJTA3INT,
+ RICOH619_IRQ_FBTEMPJTA4INT,
+
+ RICOH619_IRQ_FCURTERMINT,
+ RICOH619_IRQ_FVOLTERMINT,
+ RICOH619_IRQ_FICRVSINT,
+ RICOH619_IRQ_FPOOR_CHGCURINT,
+ RICOH619_IRQ_FOSCFDETINT1,
+ RICOH619_IRQ_FOSCFDETINT2,
+ RICOH619_IRQ_FOSCFDETINT3,
+ RICOH619_IRQ_FOSCMDETINT,
+
+ RICOH619_IRQ_FDIEOFFINT,
+ RICOH619_IRQ_FDIEERRINT,
+ RICOH619_IRQ_FBTEMPERRINT,
+ RICOH619_IRQ_FVBATOVINT,
+ RICOH619_IRQ_FTTIMOVINT,
+ RICOH619_IRQ_FRTIMOVINT,
+ RICOH619_IRQ_FVADPOVSINT,
+ RICOH619_IRQ_FVUSBOVSINT,
+
+ RICOH619_IRQ_FGCDET,
+ RICOH619_IRQ_FPCDET,
+ RICOH619_IRQ_FWARN_ADP,
+
+ /* Should be last entry */
+ RICOH619_NR_IRQS,
+};
+
+/* Ricoh619 gpio definitions */
+enum {
+ RICOH619_GPIO0,
+ RICOH619_GPIO1,
+ RICOH619_GPIO2,
+ RICOH619_GPIO3,
+ RICOH619_GPIO4,
+
+ RICOH619_NR_GPIO,
+};
+
+enum ricoh619_sleep_control_id {
+ RICOH619_DS_DC1,
+ RICOH619_DS_DC2,
+ RICOH619_DS_DC3,
+ RICOH619_DS_DC4,
+ RICOH619_DS_DC5,
+ RICOH619_DS_LDO1,
+ RICOH619_DS_LDO2,
+ RICOH619_DS_LDO3,
+ RICOH619_DS_LDO4,
+ RICOH619_DS_LDO5,
+ RICOH619_DS_LDO6,
+ RICOH619_DS_LDO7,
+ RICOH619_DS_LDO8,
+ RICOH619_DS_LDO9,
+ RICOH619_DS_LDO10,
+ RICOH619_DS_LDORTC1,
+ RICOH619_DS_LDORTC2,
+ RICOH619_DS_PSO0,
+ RICOH619_DS_PSO1,
+ RICOH619_DS_PSO2,
+ RICOH619_DS_PSO3,
+ RICOH619_DS_PSO4,
+};
+
+
+struct ricoh619_subdev_info {
+ int id;
+ const char *name;
+ void *platform_data;
+};
+
+/*
+struct ricoh619_rtc_platform_data {
+ int irq;
+ struct rtc_time time;
+};
+*/
+
+struct ricoh619_gpio_init_data {
+ unsigned output_mode_en:1; /* Enable output mode during init */
+ unsigned output_val:1; /* Output value if it is in output mode */
+ unsigned init_apply:1; /* Apply init data on configuring gpios*/
+ unsigned led_mode:1; /* Select LED mode during init */
+ unsigned led_func:1; /* Set LED function if LED mode is 1 */
+};
+
+struct ricoh619 {
+ struct device *dev;
+ struct i2c_client *client;
+ struct mutex io_lock;
+ int gpio_base;
+ struct gpio_chip gpio_chip;
+ int irq_base;
+// struct irq_chip irq_chip;
+ int chip_irq;
+ 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];
+
+ /* For gpio edge */
+ u8 gpedge_cache[MAX_GPEDGE_REG];
+ u8 gpedge_reg[MAX_GPEDGE_REG];
+
+ int bank_num;
+};
+
+struct ricoh619_platform_data {
+ int num_subdevs;
+ struct ricoh619_subdev_info *subdevs;
+ int (*init_port)(int irq_num); // Init GPIO for IRQ pin
+ int gpio_base;
+ int irq_base;
+ struct ricoh619_gpio_init_data *gpio_init_data;
+ int num_gpioinit_data;
+ bool enable_shutdown_pin;
+ int (*pre_init)(struct ricoh619 *ricoh619);
+ int (*post_init)(struct ricoh619 *ricoh619);
+};
+
+/* ==================================== */
+/* RICOH619 Power_Key device data */
+/* ==================================== */
+struct ricoh619_pwrkey_platform_data {
+ int irq;
+ unsigned long delay_ms;
+};
+extern int pwrkey_wakeup;
+extern struct ricoh619 *g_ricoh619;
+/* ==================================== */
+/* RICOH619 battery device data */
+/* ==================================== */
+extern int g_soc;
+extern int g_fg_on_mode;
+
+extern int ricoh619_read(struct device *dev, uint8_t reg, uint8_t *val);
+extern int ricoh619_read_bank1(struct device *dev, uint8_t reg, uint8_t *val);
+extern int ricoh619_bulk_reads(struct device *dev, u8 reg, u8 count,
+ uint8_t *val);
+extern int ricoh619_bulk_reads_bank1(struct device *dev, u8 reg, u8 count,
+ uint8_t *val);
+extern int ricoh619_write(struct device *dev, u8 reg, uint8_t val);
+extern int ricoh619_write_bank1(struct device *dev, u8 reg, uint8_t val);
+extern int ricoh619_bulk_writes(struct device *dev, u8 reg, u8 count,
+ uint8_t *val);
+extern int ricoh619_bulk_writes_bank1(struct device *dev, u8 reg, u8 count,
+ uint8_t *val);
+extern int ricoh619_set_bits(struct device *dev, u8 reg, uint8_t bit_mask);
+extern int ricoh619_clr_bits(struct device *dev, u8 reg, uint8_t bit_mask);
+extern int ricoh619_update(struct device *dev, u8 reg, uint8_t val,
+ uint8_t mask);
+extern int ricoh619_update_bank1(struct device *dev, u8 reg, uint8_t val,
+ uint8_t mask);
+extern int ricoh619_power_off(void);
+extern int ricoh619_irq_init(struct ricoh619 *ricoh619, int irq, int irq_base);
+extern int ricoh619_irq_exit(struct ricoh619 *ricoh619);
+extern int ricoh619_power_off(void);
+
+#endif
--- /dev/null
+/*
+ * include/linux/power/ricoh619-battery.c
+ *
+ * RICOH RC5T619 Charger Driver
+ *
+ * Copyright (C) 2012-2013 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef __LINUX_POWER_RICOH619_H_
+#define __LINUX_POWER_RICOH619_H_
+
+/* #include <linux/power_supply.h> */
+/* #include <linux/types.h> */
+
+#if 0
+#define RICOH_FG_DBG(fmt, args...) printk(KERN_DEBUG "RICOH_FG_DBG:\t"fmt, ##args)
+#else
+#define RICOH_FG_DBG(fmt, args...) {while(0);}
+#endif
+
+/* Defined buttery information */
+#define ADC_VDD_MV 2800
+#define MIN_VOLTAGE 3100
+#define MAX_VOLTAGE 4200
+
+/* 619 Register information */
+/* bank 0 */
+#define PSWR_REG 0x07
+/* for ADC */
+#define INTEN_REG 0x9D
+#define EN_ADCIR3_REG 0x8A
+#define ADCCNT3_REG 0x66
+#define VBATDATAH_REG 0x6A
+#define VBATDATAL_REG 0x6B
+
+#define CHGCTL1_REG 0xB3
+#define REGISET1_REG 0xB6
+#define REGISET2_REG 0xB7
+#define CHGISET_REG 0xB8
+#define BATSET2_REG 0xBB
+
+#define CHGSTATE_REG 0xBD
+
+#define FG_CTRL_REG 0xE0
+#define SOC_REG 0xE1
+#define RE_CAP_H_REG 0xE2
+#define RE_CAP_L_REG 0xE3
+#define FA_CAP_H_REG 0xE4
+#define FA_CAP_L_REG 0xE5
+#define TT_EMPTY_H_REG 0xE7
+#define TT_EMPTY_L_REG 0xE8
+#define TT_FULL_H_REG 0xE9
+#define TT_FULL_L_REG 0xEA
+#define VOLTAGE_1_REG 0xEB
+#define VOLTAGE_2_REG 0xEC
+#define TEMP_1_REG 0xED
+#define TEMP_2_REG 0xEE
+
+#define CC_CTRL_REG 0xEF
+#define CC_SUMREG3_REG 0xF3
+#define CC_SUMREG2_REG 0xF4
+#define CC_SUMREG1_REG 0xF5
+#define CC_SUMREG0_REG 0xF6
+#define CC_AVERAGE1_REG 0xFB
+#define CC_AVERAGE0_REG 0xFC
+
+/* bank 1 */
+/* Top address for battery initial setting */
+#define BAT_INIT_TOP_REG 0xBC
+#define BAT_REL_SEL_REG 0xDA
+/**************************/
+
+/* detailed status in CHGSTATE (0xBD) */
+enum ChargeState {
+ CHG_STATE_CHG_OFF = 0,
+ CHG_STATE_CHG_READY_VADP,
+ CHG_STATE_CHG_TRICKLE,
+ CHG_STATE_CHG_RAPID,
+ CHG_STATE_CHG_COMPLETE,
+ CHG_STATE_SUSPEND,
+ CHG_STATE_VCHG_OVER_VOL,
+ CHG_STATE_BAT_ERROR,
+ CHG_STATE_NO_BAT,
+ CHG_STATE_BAT_OVER_VOL,
+ CHG_STATE_BAT_TEMP_ERR,
+ CHG_STATE_DIE_ERR,
+ CHG_STATE_DIE_SHUTDOWN,
+ CHG_STATE_NO_BAT2,
+ CHG_STATE_CHG_READY_VUSB,
+};
+
+enum SupplyState {
+ SUPPLY_STATE_BAT = 0,
+ SUPPLY_STATE_ADP,
+ SUPPLY_STATE_USB,
+} ;
+
+struct ricoh619_battery_platform_data {
+ int irq;
+ int alarm_vol_mv;
+ int multiple;
+ unsigned long monitor_time;
+};
+
+extern struct ricoh619 *g_ricoh619;
+
+
+#endif
--- /dev/null
+/*
+ * include/linux/power/ricoh61x_battery_init.h
+ *
+ * Battery initial parameter for RICOH RN5T618/619 power management chip.
+ *
+ * Copyright (C) 2012-2013 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.
+ *
+ */
+#ifndef __LINUX_POWER_RICOH61X_BATTERY_INIT_H
+#define __LINUX_POWER_RICOH61X_BATTERY_INIT_H
+
+
+uint8_t battery_init_para[32] = {
+ 0x0B, 0x3F, 0x0B, 0xCB, 0x0B, 0xEE, 0x0C, 0x08, 0x0C, 0x1E, 0x0C, 0x38, 0x0C, 0x5B, 0x0C, 0x94,
+ 0x0C, 0xC8, 0x0D, 0x08, 0x0D, 0x55, 0x0E, 0x14, 0x00, 0x39, 0x0F, 0xC8, 0x05, 0x2C, 0x22, 0x56
+// 0x0C, 0xC8, 0x0D, 0x08, 0x0D, 0x55, 0x0E, 0x14, 0x00, 0x3E, 0x0F, 0xC8, 0x05, 0x2C, 0x22, 0x56 //150ohme
+// 0x0C, 0xC8, 0x0D, 0x08, 0x0D, 0x55, 0x0E, 0x14, 0x00, 0x32, 0x0F, 0xC8, 0x05, 0x2C, 0x22, 0x56 //120ohme
+ //0x08, 0xa3, 0x0a, 0xf9, 0x0b, 0x4b, 0x0b, 0x74,
+ //0x0b, 0x94, 0x0b, 0xb5, 0x0b, 0xe6, 0x0c, 0x30,
+ //0x0c, 0x92, 0x0c, 0xf4, 0x0d, 0x6f, 0x08, 0xca,
+ //0x00, 0x36, 0x0f, 0xc8, 0x05, 0x2c, 0x22, 0x56
+};
+
+#endif
+
+/*
+<Other Parameter>
+nominal_capacity=3800
+cut-off_v=3400
+thermistor_b=3435
+board_impe=0
+bat_impe=0.1363
+load_c=768
+available_c=3604
+battery_v=3515
+MakingMode=Normal
+ChargeV=4.20V
+LoadMode=Resistor
+ */
+
--- /dev/null
+/*
+ * linux/regulator/ricoh619-regulator.h
+ *
+ * Regulator driver for RICOH619 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __LINUX_REGULATOR_RICOH619_H
+#define __LINUX_REGULATOR_RICOH619_H
+
+#include <linux/regulator/machine.h>
+#include <linux/regulator/driver.h>
+
+#define ricoh619_rails(_name) "RICOH619_"#_name
+
+/* RICHOH Regulator IDs */
+enum regulator_id {
+ RICOH619_ID_DC1,
+ RICOH619_ID_DC2,
+ RICOH619_ID_DC3,
+ RICOH619_ID_DC4,
+ RICOH619_ID_DC5,
+ RICOH619_ID_LDO1,
+ RICOH619_ID_LDO2,
+ RICOH619_ID_LDO3,
+ RICOH619_ID_LDO4,
+ RICOH619_ID_LDO5,
+ RICOH619_ID_LDO6,
+ RICOH619_ID_LDO7,
+ RICOH619_ID_LDO8,
+ RICOH619_ID_LDO9,
+ RICOH619_ID_LDO10,
+ RICOH619_ID_LDORTC1,
+ RICOH619_ID_LDORTC2,
+};
+
+struct ricoh619_regulator_platform_data {
+ struct regulator_init_data regulator;
+ int init_uV;
+ unsigned init_enable:1;
+ unsigned init_apply:1;
+ int sleep_uV;
+ int sleep_slots;
+ unsigned long ext_pwr_req;
+ unsigned long flags;
+};
+
+extern int ricoh619_regulator_enable_eco_mode(struct regulator_dev *rdev);
+extern int ricoh619_regulator_disable_eco_mode(struct regulator_dev *rdev);
+extern int ricoh619_regulator_enable_eco_slp_mode(struct regulator_dev *rdev);
+extern int ricoh619_regulator_disable_eco_slp_mode(struct regulator_dev *rdev);
+
+
+#endif
--- /dev/null
+/*
+ * include/linux/rtc/rtc-ricoh619.h
+ *
+ * Real time clock driver for RICOH RC5T619 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef __LINUX_RTC_RICOH619_H_
+#define __LINUX_RTC_RICOH619_H_
+
+#include <linux/rtc.h>
+
+#define rtc_ctrl1 0xAE
+#define rtc_ctrl2 0xAF
+#define rtc_seconds_reg 0xA0
+#define rtc_alarm_y_sec 0xA8
+#define rtc_adjust 0xA7
+
+
+/*
+linux rtc driver refers 1900 as base year in many calculations.
+(e.g. refer drivers/rtc/rtc-lib.c)
+*/
+#define os_ref_year 1900
+
+/*
+ pmu rtc have only 2 nibbles to store year information, so using an
+ offset of 100 to set the base year as 2000 for our driver.
+*/
+#define rtc_year_offset 100
+
+
+
+struct ricoh619_rtc_platform_data {
+ int irq;
+ struct rtc_time time;
+};
+
+
+#endif