| /* |
| * driver/mfd/tps80031.c |
| * |
| * Core driver for TI TPS80031 |
| * |
| * 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. |
| * |
| */ |
| |
| #include <linux/interrupt.h> |
| #include <linux/irq.h> |
| #include <linux/kernel.h> |
| #include <linux/module.h> |
| #include <linux/mutex.h> |
| #include <linux/slab.h> |
| #include <linux/gpio.h> |
| #include <linux/i2c.h> |
| #include <linux/pm.h> |
| |
| #include <linux/mfd/core.h> |
| #include <linux/mfd/tps80031.h> |
| |
| /* interrupt related registers */ |
| #define TPS80031_INT_STS_A 0xD0 |
| #define TPS80031_INT_STS_B 0xD1 |
| #define TPS80031_INT_STS_C 0xD2 |
| #define TPS80031_INT_MSK_LINE_A 0xD3 |
| #define TPS80031_INT_MSK_LINE_B 0xD4 |
| #define TPS80031_INT_MSK_LINE_C 0xD5 |
| #define TPS80031_INT_MSK_STS_A 0xD6 |
| #define TPS80031_INT_MSK_STS_B 0xD7 |
| #define TPS80031_INT_MSK_STS_C 0xD8 |
| |
| #define TPS80031_CONTROLLER_STAT1 0xE3 |
| #define CONTROLLER_STAT1_BAT_TEMP 0 |
| #define CONTROLLER_STAT1_BAT_REMOVED 1 |
| #define CONTROLLER_STAT1_VBUS_DET 2 |
| #define CONTROLLER_STAT1_VAC_DET 3 |
| #define CONTROLLER_STAT1_FAULT_WDG 4 |
| #define CONTROLLER_STAT1_LINCH_GATED 6 |
| |
| #define TPS80031_CONTROLLER_INT_MASK 0xE0 |
| #define CONTROLLER_INT_MASK_MVAC_DET 0 |
| #define CONTROLLER_INT_MASK_MVBUS_DET 1 |
| #define CONTROLLER_INT_MASK_MBAT_TEMP 2 |
| #define CONTROLLER_INT_MASK_MFAULT_WDG 3 |
| #define CONTROLLER_INT_MASK_MBAT_REMOVED 4 |
| #define CONTROLLER_INT_MASK_MLINCH_GATED 5 |
| |
| #define CHARGE_CONTROL_SUB_INT_MASK 0x3F |
| |
| /* Version number related register */ |
| #define TPS80031_JTAGVERNUM 0x87 |
| /* Epprom version */ |
| #define TPS80031_EPROM_REV 0xDF |
| |
| /* External control register */ |
| #define REGEN1_BASE_ADD 0xAE |
| #define REGEN2_BASE_ADD 0xB1 |
| #define SYSEN_BASE_ADD 0xB4 |
| |
| /* device control registers */ |
| #define TPS80031_PHOENIX_DEV_ON 0x25 |
| #define DEVOFF 1 |
| |
| #define CLK32KAO_BASE_ADD 0xBA |
| #define CLK32KG_BASE_ADD 0xBD |
| #define CLK32KAUDIO_BASE_ADD 0xC0 |
| |
| #define EXT_CONTROL_CFG_TRANS 0 |
| #define EXT_CONTROL_CFG_STATE 1 |
| |
| #define STATE_OFF 0x00 |
| #define STATE_ON 0x01 |
| #define STATE_MASK 0x03 |
| |
| #define TRANS_SLEEP_OFF 0x00 |
| #define TRANS_SLEEP_ON 0x04 |
| #define TRANS_SLEEP_MASK 0x0C |
| |
| #define TPS_NUM_SLAVES 4 |
| #define EXT_PWR_REQ (PWR_REQ_INPUT_PREQ1 | PWR_REQ_INPUT_PREQ2 | \ |
| PWR_REQ_INPUT_PREQ3) |
| #define TPS80031_PREQ1_RES_ASS_A 0xD7 |
| #define TPS80031_PREQ2_RES_ASS_A 0xDA |
| #define TPS80031_PREQ3_RES_ASS_A 0xDD |
| #define TPS80031_PHOENIX_MSK_TRANSITION 0x20 |
| |
| #define TPS80031_CFG_INPUT_PUPD1 0xF0 |
| #define TPS80031_CFG_INPUT_PUPD2 0xF1 |
| #define TPS80031_CFG_INPUT_PUPD3 0xF2 |
| #define TPS80031_CFG_INPUT_PUPD4 0xF3 |
| |
| struct tps80031_pupd_data { |
| u8 reg; |
| u8 pullup_bit; |
| u8 pulldown_bit; |
| }; |
| |
| static u8 pmc_ext_control_base[] = { |
| REGEN1_BASE_ADD, |
| REGEN2_BASE_ADD, |
| SYSEN_BASE_ADD, |
| }; |
| |
| static u8 pmc_clk32k_control_base[] = { |
| CLK32KAO_BASE_ADD, |
| CLK32KG_BASE_ADD, |
| CLK32KAUDIO_BASE_ADD, |
| }; |
| struct tps80031_irq_data { |
| u8 mask_reg; |
| u8 mask_mask; |
| u8 is_sec_int; |
| u8 parent_int; |
| u8 mask_sec_int_reg; |
| u8 int_mask_bit; |
| u8 int_sec_sts_reg; |
| u8 int_sts_bit; |
| }; |
| |
| #define TPS80031_IRQ(_reg, _mask) \ |
| { \ |
| .mask_reg = (TPS80031_INT_MSK_LINE_##_reg) - \ |
| TPS80031_INT_MSK_LINE_A, \ |
| .mask_mask = (_mask), \ |
| } |
| |
| #define TPS80031_IRQ_SEC(_reg, _mask, _pint, _sint_mask_bit, _sint_sts_bit) \ |
| { \ |
| .mask_reg = (TPS80031_INT_MSK_LINE_##_reg) - \ |
| TPS80031_INT_MSK_LINE_A, \ |
| .mask_mask = (_mask), \ |
| .is_sec_int = true, \ |
| .parent_int = TPS80031_INT_##_pint, \ |
| .mask_sec_int_reg = TPS80031_CONTROLLER_INT_MASK, \ |
| .int_mask_bit = CONTROLLER_INT_MASK_##_sint_mask_bit, \ |
| .int_sec_sts_reg = TPS80031_CONTROLLER_STAT1, \ |
| .int_sts_bit = CONTROLLER_STAT1_##_sint_sts_bit \ |
| } |
| |
| static const struct tps80031_irq_data tps80031_irqs[] = { |
| |
| [TPS80031_INT_PWRON] = TPS80031_IRQ(A, 0), |
| [TPS80031_INT_RPWRON] = TPS80031_IRQ(A, 1), |
| [TPS80031_INT_SYS_VLOW] = TPS80031_IRQ(A, 2), |
| [TPS80031_INT_RTC_ALARM] = TPS80031_IRQ(A, 3), |
| [TPS80031_INT_RTC_PERIOD] = TPS80031_IRQ(A, 4), |
| [TPS80031_INT_HOT_DIE] = TPS80031_IRQ(A, 5), |
| [TPS80031_INT_VXX_SHORT] = TPS80031_IRQ(A, 6), |
| [TPS80031_INT_SPDURATION] = TPS80031_IRQ(A, 7), |
| [TPS80031_INT_WATCHDOG] = TPS80031_IRQ(B, 0), |
| [TPS80031_INT_BAT] = TPS80031_IRQ(B, 1), |
| [TPS80031_INT_SIM] = TPS80031_IRQ(B, 2), |
| [TPS80031_INT_MMC] = TPS80031_IRQ(B, 3), |
| [TPS80031_INT_RES] = TPS80031_IRQ(B, 4), |
| [TPS80031_INT_GPADC_RT] = TPS80031_IRQ(B, 5), |
| [TPS80031_INT_GPADC_SW2_EOC] = TPS80031_IRQ(B, 6), |
| [TPS80031_INT_CC_AUTOCAL] = TPS80031_IRQ(B, 7), |
| [TPS80031_INT_ID_WKUP] = TPS80031_IRQ(C, 0), |
| [TPS80031_INT_VBUSS_WKUP] = TPS80031_IRQ(C, 1), |
| [TPS80031_INT_ID] = TPS80031_IRQ(C, 2), |
| [TPS80031_INT_VBUS] = TPS80031_IRQ(C, 3), |
| [TPS80031_INT_CHRG_CTRL] = TPS80031_IRQ(C, 4), |
| [TPS80031_INT_EXT_CHRG] = TPS80031_IRQ(C, 5), |
| [TPS80031_INT_INT_CHRG] = TPS80031_IRQ(C, 6), |
| [TPS80031_INT_RES2] = TPS80031_IRQ(C, 7), |
| [TPS80031_INT_BAT_TEMP_OVRANGE] = TPS80031_IRQ_SEC(C, 4, CHRG_CTRL, |
| MBAT_TEMP, BAT_TEMP), |
| [TPS80031_INT_BAT_REMOVED] = TPS80031_IRQ_SEC(C, 4, CHRG_CTRL, |
| MBAT_REMOVED, BAT_REMOVED), |
| [TPS80031_INT_VBUS_DET] = TPS80031_IRQ_SEC(C, 4, CHRG_CTRL, |
| MVBUS_DET, VBUS_DET), |
| [TPS80031_INT_VAC_DET] = TPS80031_IRQ_SEC(C, 4, CHRG_CTRL, |
| MVAC_DET, VAC_DET), |
| [TPS80031_INT_FAULT_WDG] = TPS80031_IRQ_SEC(C, 4, CHRG_CTRL, |
| MFAULT_WDG, FAULT_WDG), |
| [TPS80031_INT_LINCH_GATED] = TPS80031_IRQ_SEC(C, 4, CHRG_CTRL, |
| MLINCH_GATED, LINCH_GATED), |
| }; |
| |
| #define PUPD_DATA(_reg, _pulldown_bit, _pullup_bit) \ |
| { \ |
| .reg = TPS80031_CFG_INPUT_PUPD##_reg, \ |
| .pulldown_bit = _pulldown_bit, \ |
| .pullup_bit = _pullup_bit, \ |
| } |
| |
| static const struct tps80031_pupd_data tps80031_pupds[] = { |
| [TPS80031_PREQ1] = PUPD_DATA(1, 1 << 0, 1 << 1 ), |
| [TPS80031_PREQ2A] = PUPD_DATA(1, 1 << 2, 1 << 3 ), |
| [TPS80031_PREQ2B] = PUPD_DATA(1, 1 << 4, 1 << 5 ), |
| [TPS80031_PREQ2C] = PUPD_DATA(1, 1 << 6, 1 << 7 ), |
| [TPS80031_PREQ3] = PUPD_DATA(2, 1 << 0, 1 << 1 ), |
| [TPS80031_NRES_WARM] = PUPD_DATA(2, 0, 1 << 2 ), |
| [TPS80031_PWM_FORCE] = PUPD_DATA(2, 1 << 5, 0 ), |
| [TPS80031_CHRG_EXT_CHRG_STATZ] = PUPD_DATA(2, 0, 1 << 6 ), |
| [TPS80031_SIM] = PUPD_DATA(3, 1 << 0, 1 << 1 ), |
| [TPS80031_MMC] = PUPD_DATA(3, 1 << 2, 1 << 3 ), |
| [TPS80031_GPADC_START] = PUPD_DATA(3, 1 << 4, 0 ), |
| [TPS80031_DVSI2C_SCL] = PUPD_DATA(4, 0, 1 << 0 ), |
| [TPS80031_DVSI2C_SDA] = PUPD_DATA(4, 0, 1 << 1 ), |
| [TPS80031_CTLI2C_SCL] = PUPD_DATA(4, 0, 1 << 2 ), |
| [TPS80031_CTLI2C_SDA] = PUPD_DATA(4, 0, 1 << 3 ), |
| }; |
| |
| static const int controller_stat1_irq_nr[] = { |
| TPS80031_INT_BAT_TEMP_OVRANGE, |
| TPS80031_INT_BAT_REMOVED, |
| TPS80031_INT_VBUS_DET, |
| TPS80031_INT_VAC_DET, |
| TPS80031_INT_FAULT_WDG, |
| 0, |
| TPS80031_INT_LINCH_GATED, |
| 0 |
| }; |
| |
| /* Structure for TPS80031 Slaves */ |
| struct tps80031_client { |
| struct i2c_client *client; |
| struct mutex lock; |
| u8 addr; |
| }; |
| |
| struct tps80031 { |
| struct device *dev; |
| unsigned long chip_info; |
| int es_version; |
| |
| struct gpio_chip gpio; |
| struct irq_chip irq_chip; |
| struct mutex irq_lock; |
| int irq_base; |
| u32 irq_en; |
| u8 mask_cache[3]; |
| u8 mask_reg[3]; |
| u8 cont_int_mask_reg; |
| u8 cont_int_mask_cache; |
| u8 cont_int_en; |
| u8 prev_cont_stat1; |
| struct tps80031_client tps_clients[TPS_NUM_SLAVES]; |
| }; |
| |
| static inline int __tps80031_read(struct i2c_client *client, |
| int reg, uint8_t *val) |
| { |
| int ret; |
| |
| ret = i2c_smbus_read_byte_data(client, reg); |
| if (ret < 0) { |
| dev_err(&client->dev, |
| "failed reading from addr 0x%02x, reg 0x%02x\n", |
| client->addr, reg); |
| return ret; |
| } |
| |
| *val = (uint8_t)ret; |
| |
| return 0; |
| } |
| |
| static inline int __tps80031_reads(struct i2c_client *client, int reg, |
| int len, uint8_t *val) |
| { |
| int ret; |
| |
| ret = i2c_smbus_read_i2c_block_data(client, reg, len, val); |
| if (ret < 0) { |
| dev_err(&client->dev, |
| "failed reading from addr 0x%02x, reg 0x%02x\n", |
| client->addr, reg); |
| return ret; |
| } |
| |
| return 0; |
| } |
| |
| static inline int __tps80031_write(struct i2c_client *client, |
| int reg, uint8_t val) |
| { |
| int ret; |
| 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 __tps80031_writes(struct i2c_client *client, int reg, |
| int len, uint8_t *val) |
| { |
| int ret; |
| |
| ret = i2c_smbus_write_i2c_block_data(client, reg, len, val); |
| if (ret < 0) { |
| dev_err(&client->dev, "failed writings to 0x%02x\n", reg); |
| return ret; |
| } |
| |
| return 0; |
| } |
| |
| int tps80031_write(struct device *dev, int sid, int reg, uint8_t val) |
| { |
| struct tps80031 *tps80031 = dev_get_drvdata(dev); |
| struct tps80031_client *tps = &tps80031->tps_clients[sid]; |
| int ret; |
| |
| mutex_lock(&tps->lock); |
| ret = __tps80031_write(tps->client, reg, val); |
| mutex_unlock(&tps->lock); |
| |
| return ret; |
| } |
| EXPORT_SYMBOL_GPL(tps80031_write); |
| |
| int tps80031_writes(struct device *dev, int sid, int reg, int len, uint8_t *val) |
| { |
| struct tps80031 *tps80031 = dev_get_drvdata(dev); |
| struct tps80031_client *tps = &tps80031->tps_clients[sid]; |
| int ret; |
| |
| mutex_lock(&tps->lock); |
| ret = __tps80031_writes(tps->client, reg, len, val); |
| mutex_unlock(&tps->lock); |
| |
| return ret; |
| } |
| EXPORT_SYMBOL_GPL(tps80031_writes); |
| |
| int tps80031_read(struct device *dev, int sid, int reg, uint8_t *val) |
| { |
| struct tps80031 *tps80031 = dev_get_drvdata(dev); |
| struct tps80031_client *tps = &tps80031->tps_clients[sid]; |
| |
| return __tps80031_read(tps->client, reg, val); |
| } |
| EXPORT_SYMBOL_GPL(tps80031_read); |
| |
| int tps80031_reads(struct device *dev, int sid, int reg, int len, uint8_t *val) |
| { |
| struct tps80031 *tps80031 = dev_get_drvdata(dev); |
| struct tps80031_client *tps = &tps80031->tps_clients[sid]; |
| |
| return __tps80031_reads(tps->client, reg, len, val); |
| } |
| EXPORT_SYMBOL_GPL(tps80031_reads); |
| |
| int tps80031_set_bits(struct device *dev, int sid, int reg, uint8_t bit_mask) |
| { |
| struct tps80031 *tps80031 = dev_get_drvdata(dev); |
| struct tps80031_client *tps = &tps80031->tps_clients[sid]; |
| uint8_t reg_val; |
| int ret = 0; |
| |
| mutex_lock(&tps->lock); |
| |
| ret = __tps80031_read(tps->client, reg, ®_val); |
| if (ret) |
| goto out; |
| |
| if ((reg_val & bit_mask) != bit_mask) { |
| reg_val |= bit_mask; |
| ret = __tps80031_write(tps->client, reg, reg_val); |
| } |
| out: |
| mutex_unlock(&tps->lock); |
| return ret; |
| } |
| EXPORT_SYMBOL_GPL(tps80031_set_bits); |
| |
| int tps80031_clr_bits(struct device *dev, int sid, int reg, uint8_t bit_mask) |
| { |
| struct tps80031 *tps80031 = dev_get_drvdata(dev); |
| struct tps80031_client *tps = &tps80031->tps_clients[sid]; |
| uint8_t reg_val; |
| int ret = 0; |
| |
| mutex_lock(&tps->lock); |
| |
| ret = __tps80031_read(tps->client, reg, ®_val); |
| if (ret) |
| goto out; |
| |
| if (reg_val & bit_mask) { |
| reg_val &= ~bit_mask; |
| ret = __tps80031_write(tps->client, reg, reg_val); |
| } |
| out: |
| mutex_unlock(&tps->lock); |
| return ret; |
| } |
| EXPORT_SYMBOL_GPL(tps80031_clr_bits); |
| |
| int tps80031_update(struct device *dev, int sid, int reg, uint8_t val, |
| uint8_t mask) |
| { |
| struct tps80031 *tps80031 = dev_get_drvdata(dev); |
| struct tps80031_client *tps = &tps80031->tps_clients[sid]; |
| uint8_t reg_val; |
| int ret = 0; |
| |
| mutex_lock(&tps->lock); |
| |
| ret = __tps80031_read(tps->client, reg, ®_val); |
| if (ret) |
| goto out; |
| |
| if ((reg_val & mask) != val) { |
| reg_val = (reg_val & ~mask) | (val & mask); |
| ret = __tps80031_write(tps->client, reg, reg_val); |
| } |
| out: |
| mutex_unlock(&tps->lock); |
| return ret; |
| } |
| EXPORT_SYMBOL_GPL(tps80031_update); |
| |
| int tps80031_force_update(struct device *dev, int sid, int reg, uint8_t val, |
| uint8_t mask) |
| { |
| struct tps80031 *tps80031 = dev_get_drvdata(dev); |
| struct tps80031_client *tps = &tps80031->tps_clients[sid]; |
| uint8_t reg_val; |
| int ret = 0; |
| |
| mutex_lock(&tps->lock); |
| |
| ret = __tps80031_read(tps->client, reg, ®_val); |
| if (ret) |
| goto out; |
| |
| reg_val = (reg_val & ~mask) | (val & mask); |
| ret = __tps80031_write(tps->client, reg, reg_val); |
| |
| out: |
| mutex_unlock(&tps->lock); |
| return ret; |
| } |
| EXPORT_SYMBOL_GPL(tps80031_force_update); |
| |
| int tps80031_ext_power_req_config(struct device *dev, |
| unsigned long ext_ctrl_flag, int preq_bit, |
| int state_reg_add, int trans_reg_add) |
| { |
| u8 res_ass_reg = 0; |
| int preq_mask_bit = 0; |
| int ret; |
| |
| if (!(ext_ctrl_flag & EXT_PWR_REQ)) |
| return 0; |
| |
| if (ext_ctrl_flag & PWR_REQ_INPUT_PREQ1) { |
| res_ass_reg = TPS80031_PREQ1_RES_ASS_A + (preq_bit >> 3); |
| preq_mask_bit = 5; |
| } else if (ext_ctrl_flag & PWR_REQ_INPUT_PREQ2) { |
| res_ass_reg = TPS80031_PREQ2_RES_ASS_A + (preq_bit >> 3); |
| preq_mask_bit = 6; |
| } else if (ext_ctrl_flag & PWR_REQ_INPUT_PREQ3) { |
| res_ass_reg = TPS80031_PREQ3_RES_ASS_A + (preq_bit >> 3); |
| preq_mask_bit = 7; |
| } |
| |
| /* Configure REQ_ASS registers */ |
| ret = tps80031_set_bits(dev, SLAVE_ID1, res_ass_reg, |
| BIT(preq_bit & 0x7)); |
| if (ret < 0) { |
| dev_err(dev, "%s() Not able to set bit %d of " |
| "reg %d error %d\n", |
| __func__, preq_bit, res_ass_reg, ret); |
| return ret; |
| } |
| |
| /* Unmask the PREQ */ |
| ret = tps80031_clr_bits(dev, SLAVE_ID1, |
| TPS80031_PHOENIX_MSK_TRANSITION, BIT(preq_mask_bit)); |
| if (ret < 0) { |
| dev_err(dev, "%s() Not able to clear bit %d of " |
| "reg %d error %d\n", |
| __func__, preq_mask_bit, |
| TPS80031_PHOENIX_MSK_TRANSITION, ret); |
| return ret; |
| } |
| |
| /* Switch regulator control to resource now */ |
| if (ext_ctrl_flag & (PWR_REQ_INPUT_PREQ2 | PWR_REQ_INPUT_PREQ3)) { |
| ret = tps80031_update(dev, SLAVE_ID1, state_reg_add, 0x0, |
| STATE_MASK); |
| if (ret < 0) |
| dev_err(dev, "%s() Error in writing the STATE " |
| "register %d error %d\n", __func__, |
| state_reg_add, ret); |
| } else { |
| ret = tps80031_update(dev, SLAVE_ID1, trans_reg_add, |
| TRANS_SLEEP_OFF, TRANS_SLEEP_MASK); |
| if (ret < 0) |
| dev_err(dev, "%s() Error in writing the TRANS " |
| "register %d error %d\n", __func__, |
| trans_reg_add, ret); |
| } |
| return ret; |
| } |
| EXPORT_SYMBOL_GPL(tps80031_ext_power_req_config); |
| |
| unsigned long tps80031_get_chip_info(struct device *dev) |
| { |
| struct tps80031 *tps80031 = dev_get_drvdata(dev); |
| return tps80031->chip_info; |
| } |
| EXPORT_SYMBOL_GPL(tps80031_get_chip_info); |
| |
| int tps80031_get_pmu_version(struct device *dev) |
| { |
| struct tps80031 *tps80031 = dev_get_drvdata(dev); |
| return tps80031->es_version; |
| } |
| EXPORT_SYMBOL_GPL(tps80031_get_pmu_version); |
| |
| static struct tps80031 *tps80031_dev; |
| static void tps80031_power_off(void) |
| { |
| struct tps80031_client *tps = &tps80031_dev->tps_clients[SLAVE_ID1]; |
| |
| if (!tps->client) |
| return; |
| dev_info(&tps->client->dev, "switching off PMU\n"); |
| __tps80031_write(tps->client, TPS80031_PHOENIX_DEV_ON, DEVOFF); |
| } |
| |
| static void tps80031_pupd_init(struct tps80031 *tps80031, |
| struct tps80031_platform_data *pdata) |
| { |
| struct tps80031_pupd_init_data *pupd_init_data = pdata->pupd_init_data; |
| int data_size = pdata->pupd_init_data_size; |
| int i; |
| |
| for (i = 0; i < data_size; ++i) { |
| struct tps80031_pupd_init_data *pupd_init = &pupd_init_data[i]; |
| const struct tps80031_pupd_data *pupd = |
| &tps80031_pupds[pupd_init->input_pin]; |
| u8 update_value = 0; |
| u8 update_mask = pupd->pulldown_bit | pupd->pullup_bit; |
| |
| if (pupd_init->setting == TPS80031_PUPD_PULLDOWN) |
| update_value = pupd->pulldown_bit; |
| else if (pupd_init->setting == TPS80031_PUPD_PULLUP) |
| update_value = pupd->pullup_bit; |
| |
| tps80031_update(tps80031->dev, SLAVE_ID1, pupd->reg, |
| update_value, update_mask); |
| } |
| } |
| |
| static void tps80031_init_ext_control(struct tps80031 *tps80031, |
| struct tps80031_platform_data *pdata) { |
| int ret; |
| int i; |
| |
| /* Clear all external control for this rail */ |
| for (i = 0; i < 9; ++i) { |
| ret = tps80031_write(tps80031->dev, SLAVE_ID1, |
| TPS80031_PREQ1_RES_ASS_A + i, 0); |
| if (ret < 0) |
| dev_err(tps80031->dev, "%s() Error in clearing " |
| "register %02x\n", __func__, |
| TPS80031_PREQ1_RES_ASS_A + i); |
| } |
| |
| /* Mask the PREQ */ |
| ret = tps80031_set_bits(tps80031->dev, SLAVE_ID1, |
| TPS80031_PHOENIX_MSK_TRANSITION, 0x7 << 5); |
| if (ret < 0) |
| dev_err(tps80031->dev, "%s() Not able to mask register " |
| "0x%02x\n", __func__, TPS80031_PHOENIX_MSK_TRANSITION); |
| } |
| |
| static int tps80031_gpio_get(struct gpio_chip *gc, unsigned offset) |
| { |
| struct tps80031 *tps80031 = container_of(gc, struct tps80031, gpio); |
| struct tps80031_client *tps = &tps80031->tps_clients[SLAVE_ID1]; |
| uint8_t state; |
| uint8_t trans; |
| int ret; |
| |
| ret = __tps80031_read(tps->client, |
| pmc_ext_control_base[offset] + |
| EXT_CONTROL_CFG_STATE, &state); |
| if (ret) |
| return ret; |
| |
| if (state != 0) { |
| ret = __tps80031_read(tps->client, |
| pmc_ext_control_base[offset] + |
| EXT_CONTROL_CFG_TRANS, &trans); |
| if (ret) |
| return ret; |
| return trans & 0x1; |
| } |
| return 0; |
| } |
| |
| static void tps80031_gpio_set(struct gpio_chip *gc, unsigned offset, |
| int value) |
| { |
| struct tps80031 *tps80031 = container_of(gc, struct tps80031, gpio); |
| |
| tps80031_update(tps80031->dev, SLAVE_ID1, |
| pmc_ext_control_base[offset] + EXT_CONTROL_CFG_TRANS, |
| value, 0x1); |
| } |
| |
| static int tps80031_gpio_input(struct gpio_chip *gc, unsigned offset) |
| { |
| return -EIO; |
| } |
| |
| static int tps80031_gpio_output(struct gpio_chip *gc, unsigned offset, |
| int value) |
| { |
| tps80031_gpio_set(gc, offset, value); |
| return 0; |
| } |
| |
| static int tps80031_gpio_enable(struct gpio_chip *gc, unsigned offset) |
| { |
| struct tps80031 *tps80031 = container_of(gc, struct tps80031, gpio); |
| int ret; |
| |
| ret = tps80031_update(tps80031->dev, SLAVE_ID1, |
| pmc_ext_control_base[offset] + EXT_CONTROL_CFG_STATE, |
| STATE_ON, STATE_MASK); |
| if (ret) |
| return ret; |
| |
| return tps80031_write(tps80031->dev, SLAVE_ID1, |
| pmc_ext_control_base[offset] + EXT_CONTROL_CFG_TRANS, 0x0); |
| } |
| |
| static void tps80031_gpio_disable(struct gpio_chip *gc, unsigned offset) |
| { |
| struct tps80031 *tps80031 = container_of(gc, struct tps80031, gpio); |
| tps80031_update(tps80031->dev, SLAVE_ID1, |
| pmc_ext_control_base[offset] + EXT_CONTROL_CFG_STATE, |
| STATE_OFF, STATE_MASK); |
| } |
| |
| static void tps80031_gpio_init(struct tps80031 *tps80031, |
| struct tps80031_platform_data *pdata) |
| { |
| int ret; |
| int gpio_base = pdata->gpio_base; |
| struct tps80031_client *tps = &tps80031->tps_clients[SLAVE_ID1]; |
| struct tps80031_gpio_init_data *gpio_init_data = pdata->gpio_init_data; |
| int data_size = pdata->gpio_init_data_size; |
| static int preq_bit_pos[TPS80031_GPIO_NR] = {16, 17, 18}; |
| int base_add; |
| int i; |
| |
| if (gpio_base <= 0) |
| return; |
| |
| /* Configure the external request mode */ |
| for (i = 0; i < data_size; ++i) { |
| struct tps80031_gpio_init_data *gpio_pd = &gpio_init_data[i]; |
| base_add = pmc_ext_control_base[gpio_pd->gpio_nr]; |
| |
| if (gpio_pd->ext_ctrl_flag & EXT_PWR_REQ) { |
| ret = tps80031_ext_power_req_config(tps80031->dev, |
| gpio_pd->ext_ctrl_flag, |
| preq_bit_pos[gpio_pd->gpio_nr], |
| base_add + EXT_CONTROL_CFG_STATE, |
| base_add + EXT_CONTROL_CFG_TRANS); |
| if (ret < 0) |
| dev_warn(tps80031->dev, "Ext pwrreq GPIO " |
| "sleep control fails\n"); |
| } |
| |
| if (gpio_pd->ext_ctrl_flag & PWR_OFF_ON_SLEEP) { |
| ret = tps80031_update(tps80031->dev, SLAVE_ID1, |
| base_add + EXT_CONTROL_CFG_TRANS, 0x0, 0xC); |
| if (ret < 0) |
| dev_warn(tps80031->dev, "GPIO OFF on sleep " |
| "control fails\n"); |
| } |
| |
| if (gpio_pd->ext_ctrl_flag & PWR_ON_ON_SLEEP) { |
| ret = tps80031_update(tps80031->dev, SLAVE_ID1, |
| base_add + EXT_CONTROL_CFG_TRANS, 0x4, 0xC); |
| if (ret < 0) |
| dev_warn(tps80031->dev, "GPIO ON on sleep " |
| "control fails\n"); |
| } |
| } |
| |
| tps80031->gpio.owner = THIS_MODULE; |
| tps80031->gpio.label = tps->client->name; |
| tps80031->gpio.dev = tps80031->dev; |
| tps80031->gpio.base = gpio_base; |
| tps80031->gpio.ngpio = TPS80031_GPIO_NR; |
| tps80031->gpio.can_sleep = 1; |
| |
| tps80031->gpio.request = tps80031_gpio_enable; |
| tps80031->gpio.free = tps80031_gpio_disable; |
| tps80031->gpio.direction_input = tps80031_gpio_input; |
| tps80031->gpio.direction_output = tps80031_gpio_output; |
| tps80031->gpio.set = tps80031_gpio_set; |
| tps80031->gpio.get = tps80031_gpio_get; |
| |
| ret = gpiochip_add(&tps80031->gpio); |
| if (ret) |
| dev_warn(tps80031->dev, "GPIO registration failed: %d\n", ret); |
| } |
| |
| static int __remove_subdev(struct device *dev, void *unused) |
| { |
| platform_device_unregister(to_platform_device(dev)); |
| return 0; |
| } |
| |
| static int tps80031_remove_subdevs(struct tps80031 *tps80031) |
| { |
| return device_for_each_child(tps80031->dev, NULL, __remove_subdev); |
| } |
| |
| static void tps80031_irq_lock(struct irq_data *data) |
| { |
| struct tps80031 *tps80031 = irq_data_get_irq_chip_data(data); |
| |
| mutex_lock(&tps80031->irq_lock); |
| } |
| |
| static void tps80031_irq_enable(struct irq_data *data) |
| { |
| struct tps80031 *tps80031 = irq_data_get_irq_chip_data(data); |
| unsigned int __irq = data->irq - tps80031->irq_base; |
| const struct tps80031_irq_data *irq_data = &tps80031_irqs[__irq]; |
| |
| if (irq_data->is_sec_int) { |
| tps80031->cont_int_mask_reg &= ~(1 << irq_data->int_mask_bit); |
| tps80031->cont_int_en |= (1 << irq_data->int_mask_bit); |
| tps80031->mask_reg[irq_data->mask_reg] &= ~(1 << irq_data->mask_mask); |
| tps80031->irq_en |= (1 << irq_data->parent_int); |
| } else |
| tps80031->mask_reg[irq_data->mask_reg] &= ~(1 << irq_data->mask_mask); |
| |
| tps80031->irq_en |= (1 << __irq); |
| } |
| |
| static void tps80031_irq_disable(struct irq_data *data) |
| { |
| struct tps80031 *tps80031 = irq_data_get_irq_chip_data(data); |
| |
| unsigned int __irq = data->irq - tps80031->irq_base; |
| const struct tps80031_irq_data *irq_data = &tps80031_irqs[__irq]; |
| |
| if (irq_data->is_sec_int) { |
| tps80031->cont_int_mask_reg |= (1 << irq_data->int_mask_bit); |
| tps80031->cont_int_en &= ~(1 << irq_data->int_mask_bit); |
| if (!tps80031->cont_int_en) { |
| tps80031->mask_reg[irq_data->mask_reg] |= |
| (1 << irq_data->mask_mask); |
| tps80031->irq_en &= ~(1 << irq_data->parent_int); |
| } |
| tps80031->irq_en &= ~(1 << __irq); |
| } else |
| tps80031->mask_reg[irq_data->mask_reg] |= (1 << irq_data->mask_mask); |
| |
| tps80031->irq_en &= ~(1 << __irq); |
| } |
| |
| static void tps80031_irq_sync_unlock(struct irq_data *data) |
| { |
| struct tps80031 *tps80031 = irq_data_get_irq_chip_data(data); |
| int i; |
| |
| for (i = 0; i < ARRAY_SIZE(tps80031->mask_reg); i++) { |
| if (tps80031->mask_reg[i] != tps80031->mask_cache[i]) { |
| if (!WARN_ON(tps80031_write(tps80031->dev, SLAVE_ID2, |
| TPS80031_INT_MSK_LINE_A + i, |
| tps80031->mask_reg[i]))) |
| if (!WARN_ON(tps80031_write(tps80031->dev, |
| SLAVE_ID2, |
| TPS80031_INT_MSK_STS_A + i, |
| tps80031->mask_reg[i]))) |
| tps80031->mask_cache[i] = |
| tps80031->mask_reg[i]; |
| } |
| } |
| |
| if (tps80031->cont_int_mask_reg != tps80031->cont_int_mask_cache) { |
| if (!WARN_ON(tps80031_write(tps80031->dev, SLAVE_ID2, |
| TPS80031_CONTROLLER_INT_MASK, |
| tps80031->cont_int_mask_reg))) |
| tps80031->cont_int_mask_cache = |
| tps80031->cont_int_mask_reg; |
| } |
| |
| mutex_unlock(&tps80031->irq_lock); |
| } |
| |
| static irqreturn_t tps80031_charge_control_irq(int irq, void *data) |
| { |
| struct tps80031 *tps80031 = data; |
| int ret = 0; |
| int i; |
| u8 cont_sts; |
| u8 org_sts; |
| if (irq != (tps80031->irq_base + TPS80031_INT_CHRG_CTRL)) { |
| dev_err(tps80031->dev, "%s() Got the illegal interrupt %d\n", |
| __func__, irq); |
| return IRQ_NONE; |
| } |
| |
| ret = tps80031_read(tps80031->dev, SLAVE_ID2, |
| TPS80031_CONTROLLER_STAT1, &org_sts); |
| if (ret < 0) { |
| dev_err(tps80031->dev, "%s(): failed to read controller state1 " |
| "status %d\n", __func__, ret); |
| return IRQ_NONE; |
| } |
| |
| /* Get change from last interrupt and mask for interested interrupt |
| * for charge control interrupt */ |
| cont_sts = org_sts ^ tps80031->prev_cont_stat1; |
| tps80031->prev_cont_stat1 = org_sts; |
| /* Clear watchdog timer state */ |
| tps80031->prev_cont_stat1 &= ~(1 << 4); |
| cont_sts &= 0x5F; |
| |
| for (i = 0; i < 8; ++i) { |
| if (!controller_stat1_irq_nr[i]) |
| continue; |
| |
| if ((cont_sts & BIT(i)) && |
| (tps80031->irq_en & BIT(controller_stat1_irq_nr[i]))) |
| handle_nested_irq(tps80031->irq_base + |
| controller_stat1_irq_nr[i]); |
| cont_sts &= ~BIT(i); |
| } |
| return IRQ_HANDLED; |
| } |
| |
| static irqreturn_t tps80031_irq(int irq, void *data) |
| { |
| struct tps80031 *tps80031 = data; |
| int ret = 0; |
| u32 acks; |
| int i; |
| uint8_t tmp[3]; |
| |
| ret = tps80031_reads(tps80031->dev, SLAVE_ID2, |
| TPS80031_INT_STS_A, 3, tmp); |
| if (ret < 0) { |
| dev_err(tps80031->dev, "failed to read interrupt status\n"); |
| return IRQ_NONE; |
| } |
| acks = (tmp[2] << 16) | (tmp[1] << 8) | tmp[0]; |
| |
| if (acks) { |
| ret = tps80031_writes(tps80031->dev, SLAVE_ID2, |
| TPS80031_INT_STS_A, 3, tmp); |
| if (ret < 0) { |
| dev_err(tps80031->dev, "failed to write " |
| "interrupt status\n"); |
| return IRQ_NONE; |
| } |
| |
| while (acks) { |
| i = __ffs(acks); |
| if (tps80031->irq_en & (1 << i)) |
| handle_nested_irq(tps80031->irq_base + i); |
| acks &= ~(1 << i); |
| } |
| } |
| |
| return IRQ_HANDLED; |
| } |
| |
| static int __devinit tps80031_irq_init(struct tps80031 *tps80031, int irq, |
| int irq_base) |
| { |
| int i, ret; |
| |
| if (!irq_base) { |
| dev_warn(tps80031->dev, "No interrupt support on IRQ base\n"); |
| return -EINVAL; |
| } |
| |
| mutex_init(&tps80031->irq_lock); |
| |
| for (i = 0; i < 3; i++) { |
| tps80031->mask_reg[i] = 0xFF; |
| tps80031->mask_cache[i] = tps80031->mask_reg[i]; |
| tps80031_write(tps80031->dev, SLAVE_ID2, |
| TPS80031_INT_MSK_LINE_A + i, |
| tps80031->mask_cache[i]); |
| tps80031_write(tps80031->dev, SLAVE_ID2, |
| TPS80031_INT_MSK_STS_A + i, 0xFF); |
| tps80031_write(tps80031->dev, SLAVE_ID2, |
| TPS80031_INT_STS_A + i, 0xFF); |
| } |
| |
| ret = tps80031_read(tps80031->dev, SLAVE_ID2, |
| TPS80031_CONTROLLER_INT_MASK, |
| &tps80031->cont_int_mask_reg); |
| if (ret < 0) { |
| dev_err(tps80031->dev, "Error in reading the controller_mask " |
| "register %d\n", ret); |
| return ret; |
| } |
| |
| tps80031->cont_int_mask_reg |= CHARGE_CONTROL_SUB_INT_MASK; |
| tps80031->cont_int_mask_cache = tps80031->cont_int_mask_reg; |
| tps80031->cont_int_en = 0; |
| ret = tps80031_write(tps80031->dev, SLAVE_ID2, |
| TPS80031_CONTROLLER_INT_MASK, |
| tps80031->cont_int_mask_reg); |
| if (ret < 0) { |
| dev_err(tps80031->dev, "Error in writing the controller_mask " |
| "register %d\n", ret); |
| return ret; |
| } |
| |
| ret = tps80031_read(tps80031->dev, SLAVE_ID2, |
| TPS80031_CONTROLLER_STAT1, &tps80031->prev_cont_stat1); |
| if (ret < 0) { |
| dev_err(tps80031->dev, "%s(): failed to read controller state1 " |
| "status %d\n", __func__, ret); |
| return ret; |
| } |
| |
| /* Clear watch dog interrupt status in status */ |
| tps80031->prev_cont_stat1 &= ~(1 << 4); |
| |
| tps80031->irq_base = irq_base; |
| |
| tps80031->irq_chip.name = "tps80031"; |
| tps80031->irq_chip.irq_enable = tps80031_irq_enable; |
| tps80031->irq_chip.irq_disable = tps80031_irq_disable; |
| tps80031->irq_chip.irq_bus_lock = tps80031_irq_lock; |
| tps80031->irq_chip.irq_bus_sync_unlock = tps80031_irq_sync_unlock; |
| |
| for (i = 0; i < TPS80031_INT_NR; i++) { |
| int __irq = i + tps80031->irq_base; |
| irq_set_chip_data(__irq, tps80031); |
| irq_set_chip_and_handler(__irq, &tps80031->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, tps80031_irq, IRQF_ONESHOT, |
| "tps80031", tps80031); |
| /* register the isr for the secondary interrupt */ |
| if (!ret) |
| ret = request_threaded_irq(irq_base + TPS80031_INT_CHRG_CTRL, |
| NULL, tps80031_charge_control_irq, |
| IRQF_ONESHOT, "80031_chg_ctl", tps80031); |
| if (!ret) { |
| |
| device_init_wakeup(tps80031->dev, 1); |
| enable_irq_wake(irq); |
| } |
| |
| return ret; |
| } |
| |
| static void tps80031_clk32k_enable(struct tps80031 *tps80031, int base_add) |
| { |
| int ret; |
| ret = tps80031_update(tps80031->dev, SLAVE_ID1, |
| base_add + EXT_CONTROL_CFG_STATE, STATE_ON, STATE_MASK); |
| if (!ret) |
| ret = tps80031_update(tps80031->dev, SLAVE_ID1, |
| base_add + EXT_CONTROL_CFG_TRANS, |
| STATE_ON, STATE_MASK); |
| if (ret < 0) |
| dev_err(tps80031->dev, "Error in updating clock register\n"); |
| } |
| |
| static void tps80031_clk32k_init(struct tps80031 *tps80031, |
| struct tps80031_platform_data *pdata) |
| { |
| int ret; |
| struct tps80031_clk32k_init_data *clk32_idata = pdata->clk32k_init_data; |
| int data_size = pdata->clk32k_init_data_size; |
| static int clk32k_preq_bit_pos[TPS80031_CLOCK32K_NR] = {-1, 20, 19}; |
| int base_add; |
| int i; |
| |
| if (!clk32_idata || !data_size) |
| return; |
| |
| /* Configure the external request mode */ |
| for (i = 0; i < data_size; ++i) { |
| struct tps80031_clk32k_init_data *clk32_pd = &clk32_idata[i]; |
| base_add = pmc_clk32k_control_base[clk32_pd->clk32k_nr]; |
| if (clk32_pd->enable) |
| tps80031_clk32k_enable(tps80031, base_add); |
| |
| if ((clk32_pd->ext_ctrl_flag & EXT_PWR_REQ) && |
| (clk32k_preq_bit_pos[clk32_pd->clk32k_nr] != -1)) { |
| ret = tps80031_ext_power_req_config(tps80031->dev, |
| clk32_pd->ext_ctrl_flag, |
| clk32k_preq_bit_pos[clk32_pd->clk32k_nr], |
| base_add + EXT_CONTROL_CFG_STATE, |
| base_add + EXT_CONTROL_CFG_TRANS); |
| if (ret < 0) |
| dev_warn(tps80031->dev, "Clk32 ext control " |
| "fails\n"); |
| } |
| |
| if (clk32_pd->ext_ctrl_flag & PWR_OFF_ON_SLEEP) { |
| ret = tps80031_update(tps80031->dev, SLAVE_ID1, |
| base_add + EXT_CONTROL_CFG_TRANS, 0x0, 0xC); |
| if (ret < 0) |
| dev_warn(tps80031->dev, "clk OFF on sleep " |
| "control fails\n"); |
| } |
| |
| if (clk32_pd->ext_ctrl_flag & PWR_ON_ON_SLEEP) { |
| ret = tps80031_update(tps80031->dev, SLAVE_ID1, |
| base_add + EXT_CONTROL_CFG_TRANS, 0x4, 0xC); |
| if (ret < 0) |
| dev_warn(tps80031->dev, "clk ON sleep " |
| "control fails\n"); |
| } |
| } |
| } |
| |
| static int __devinit tps80031_add_subdevs(struct tps80031 *tps80031, |
| struct tps80031_platform_data *pdata) |
| { |
| struct tps80031_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 = tps80031->dev; |
| pdev->dev.platform_data = subdev->platform_data; |
| |
| ret = platform_device_add(pdev); |
| if (ret) |
| goto failed; |
| } |
| return 0; |
| |
| failed: |
| tps80031_remove_subdevs(tps80031); |
| 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, |
| int sid, int start_offset, int end_offset) |
| { |
| struct tps80031 *tps80031 = s->private; |
| struct tps80031_client *tps = &tps80031->tps_clients[sid]; |
| uint8_t reg_val; |
| int i; |
| int ret; |
| |
| seq_printf(s, "%s\n", header); |
| for (i = start_offset; i <= end_offset; ++i) { |
| ret = __tps80031_read(tps->client, i, ®_val); |
| if (ret >= 0) |
| seq_printf(s, "Addr = 0x%02x Reg 0x%02x Value 0x%02x\n", |
| tps->client->addr, i, reg_val); |
| } |
| seq_printf(s, "------------------\n"); |
| } |
| |
| static int dbg_tps_show(struct seq_file *s, void *unused) |
| { |
| seq_printf(s, "TPS80031 Registers\n"); |
| seq_printf(s, "------------------\n"); |
| print_regs("VIO Regs", s, SLAVE_ID1, 0x47, 0x49); |
| print_regs("VIO Regs", s, SLAVE_ID0, 0x49, 0x4A); |
| print_regs("SMPS1 Regs", s, SLAVE_ID1, 0x53, 0x54); |
| print_regs("SMPS1 Regs", s, SLAVE_ID0, 0x55, 0x56); |
| print_regs("SMPS1 Regs", s, SLAVE_ID1, 0x57, 0x57); |
| print_regs("SMPS2 Regs", s, SLAVE_ID1, 0x59, 0x5B); |
| print_regs("SMPS2 Regs", s, SLAVE_ID0, 0x5B, 0x5C); |
| print_regs("SMPS2 Regs", s, SLAVE_ID1, 0x5C, 0x5D); |
| print_regs("SMPS3 Regs", s, SLAVE_ID1, 0x65, 0x68); |
| print_regs("SMPS4 Regs", s, SLAVE_ID1, 0x41, 0x44); |
| print_regs("VANA Regs", s, SLAVE_ID1, 0x81, 0x83); |
| print_regs("VRTC Regs", s, SLAVE_ID1, 0xC3, 0xC4); |
| print_regs("LDO1 Regs", s, SLAVE_ID1, 0x9D, 0x9F); |
| print_regs("LDO2 Regs", s, SLAVE_ID1, 0x85, 0x87); |
| print_regs("LDO3 Regs", s, SLAVE_ID1, 0x8D, 0x8F); |
| print_regs("LDO4 Regs", s, SLAVE_ID1, 0x89, 0x8B); |
| print_regs("LDO5 Regs", s, SLAVE_ID1, 0x99, 0x9B); |
| print_regs("LDO6 Regs", s, SLAVE_ID1, 0x91, 0x93); |
| print_regs("LDO7 Regs", s, SLAVE_ID1, 0xA5, 0xA7); |
| print_regs("LDOUSB Regs", s, SLAVE_ID1, 0xA1, 0xA3); |
| print_regs("LDOLN Regs", s, SLAVE_ID1, 0x95, 0x97); |
| print_regs("REGEN1 Regs", s, SLAVE_ID1, 0xAE, 0xAF); |
| print_regs("REGEN2 Regs", s, SLAVE_ID1, 0xB1, 0xB2); |
| print_regs("SYSEN Regs", s, SLAVE_ID1, 0xB4, 0xB5); |
| print_regs("CLK32KAO Regs", s, SLAVE_ID1, 0xBA, 0xBB); |
| print_regs("CLK32KG Regs", s, SLAVE_ID1, 0xBD, 0xBE); |
| print_regs("CLK32KAUD Regs", s, SLAVE_ID1, 0xC0, 0xC1); |
| print_regs("INT Regs", s, SLAVE_ID2, 0xD0, 0xD8); |
| print_regs("PREQ Regs", s, SLAVE_ID1, 0xD7, 0xDF); |
| print_regs("MASK_PH Regs", s, SLAVE_ID1, 0x20, 0x21); |
| print_regs("PMC MISC Regs", s, SLAVE_ID1, 0xE0, 0xEF); |
| print_regs("CONT_STATE", s, SLAVE_ID2, 0xE0, 0xE4); |
| print_regs("VERNUM Regs", s, SLAVE_ID3, 0x87, 0x87); |
| print_regs("EEPROM Regs", s, SLAVE_ID3, 0xDF, 0xDF); |
| print_regs("CHARGE Regs", s, SLAVE_ID2, 0xDA, 0xF5); |
| return 0; |
| } |
| |
| static int dbg_tps_open(struct inode *inode, struct file *file) |
| { |
| return single_open(file, dbg_tps_show, inode->i_private); |
| } |
| |
| static const struct file_operations debug_fops = { |
| .open = dbg_tps_open, |
| .read = seq_read, |
| .llseek = seq_lseek, |
| .release = single_release, |
| }; |
| |
| static void __init tps80031_debuginit(struct tps80031 *tps) |
| { |
| (void)debugfs_create_file("tps80031", S_IRUGO, NULL, |
| tps, &debug_fops); |
| } |
| #else |
| static void __init tps80031_debuginit(struct tps80031 *tpsi) |
| { |
| return; |
| } |
| #endif |
| |
| static int __devexit tps80031_i2c_remove(struct i2c_client *client) |
| { |
| struct tps80031 *tps80031 = i2c_get_clientdata(client); |
| int i; |
| |
| if (client->irq) |
| free_irq(client->irq, tps80031); |
| |
| if (tps80031->gpio.owner != NULL) |
| if (gpiochip_remove(&tps80031->gpio) < 0) |
| dev_err(&client->dev, "Error in removing the gpio driver\n"); |
| |
| for (i = 0; i < TPS_NUM_SLAVES; i++) { |
| struct tps80031_client *tps = &tps80031->tps_clients[i]; |
| if (tps->client && tps->client != client) |
| i2c_unregister_device(tps->client); |
| tps80031->tps_clients[i].client = NULL; |
| mutex_destroy(&tps->lock); |
| } |
| |
| kfree(tps80031); |
| return 0; |
| } |
| |
| static int __devinit tps80031_i2c_probe(struct i2c_client *client, |
| const struct i2c_device_id *id) |
| { |
| struct tps80031_platform_data *pdata = client->dev.platform_data; |
| struct tps80031 *tps80031; |
| struct tps80031_client *tps; |
| int ret; |
| int jtag_ver; |
| int ep_ver; |
| int i; |
| |
| if (!pdata) { |
| dev_err(&client->dev, "tps80031 requires platform data\n"); |
| return -ENOTSUPP; |
| } |
| |
| jtag_ver = i2c_smbus_read_byte_data(client, TPS80031_JTAGVERNUM); |
| if (jtag_ver < 0) { |
| dev_err(&client->dev, "Silicon version number read" |
| " failed: %d\n", jtag_ver); |
| return -EIO; |
| } |
| |
| ep_ver = i2c_smbus_read_byte_data(client, TPS80031_EPROM_REV); |
| if (ep_ver < 0) { |
| dev_err(&client->dev, "Silicon eeprom version read" |
| " failed: %d\n", ep_ver); |
| return -EIO; |
| } |
| |
| dev_info(&client->dev, "Jtag version 0x%02x and Eeprom version 0x%02x\n", |
| jtag_ver, ep_ver); |
| |
| tps80031 = kzalloc(sizeof(struct tps80031), GFP_KERNEL); |
| if (tps80031 == NULL) |
| return -ENOMEM; |
| |
| tps80031->es_version = jtag_ver; |
| tps80031->dev = &client->dev; |
| i2c_set_clientdata(client, tps80031); |
| tps80031->chip_info = id->driver_data; |
| |
| /* Set up slaves */ |
| tps80031->tps_clients[SLAVE_ID0].addr = I2C_ID0_ADDR; |
| tps80031->tps_clients[SLAVE_ID1].addr = I2C_ID1_ADDR; |
| tps80031->tps_clients[SLAVE_ID2].addr = I2C_ID2_ADDR; |
| tps80031->tps_clients[SLAVE_ID3].addr = I2C_ID3_ADDR; |
| for (i = 0; i < TPS_NUM_SLAVES; i++) { |
| tps = &tps80031->tps_clients[i]; |
| if (tps->addr == client->addr) |
| tps->client = client; |
| else |
| tps->client = i2c_new_dummy(client->adapter, |
| tps->addr); |
| if (!tps->client) { |
| dev_err(&client->dev, "can't attach client %d\n", i); |
| ret = -ENOMEM; |
| goto fail; |
| } |
| i2c_set_clientdata(tps->client, tps80031); |
| mutex_init(&tps->lock); |
| } |
| |
| if (client->irq) { |
| ret = tps80031_irq_init(tps80031, client->irq, |
| pdata->irq_base); |
| if (ret) { |
| dev_err(&client->dev, "IRQ init failed: %d\n", ret); |
| goto fail; |
| } |
| } |
| |
| tps80031_pupd_init(tps80031, pdata); |
| |
| tps80031_init_ext_control(tps80031, pdata); |
| |
| ret = tps80031_add_subdevs(tps80031, pdata); |
| if (ret) { |
| dev_err(&client->dev, "add devices failed: %d\n", ret); |
| goto fail; |
| } |
| |
| tps80031_gpio_init(tps80031, pdata); |
| |
| tps80031_clk32k_init(tps80031, pdata); |
| |
| tps80031_debuginit(tps80031); |
| |
| if (pdata->use_power_off && !pm_power_off) |
| pm_power_off = tps80031_power_off; |
| |
| tps80031_dev = tps80031; |
| |
| return 0; |
| |
| fail: |
| tps80031_i2c_remove(client); |
| return ret; |
| } |
| |
| #ifdef CONFIG_PM |
| static int tps80031_i2c_suspend(struct i2c_client *client, pm_message_t state) |
| { |
| if (client->irq) |
| disable_irq(client->irq); |
| return 0; |
| } |
| |
| static int tps80031_i2c_resume(struct i2c_client *client) |
| { |
| if (client->irq) |
| enable_irq(client->irq); |
| return 0; |
| } |
| #endif |
| |
| |
| static const struct i2c_device_id tps80031_id_table[] = { |
| { "tps80031", TPS80031 }, |
| { "tps80032", TPS80032 }, |
| }; |
| MODULE_DEVICE_TABLE(i2c, tps80031_id_table); |
| |
| static struct i2c_driver tps80031_driver = { |
| .driver = { |
| .name = "tps80031", |
| .owner = THIS_MODULE, |
| }, |
| .probe = tps80031_i2c_probe, |
| .remove = __devexit_p(tps80031_i2c_remove), |
| #ifdef CONFIG_PM |
| .suspend = tps80031_i2c_suspend, |
| .resume = tps80031_i2c_resume, |
| #endif |
| .id_table = tps80031_id_table, |
| }; |
| |
| static int __init tps80031_init(void) |
| { |
| return i2c_add_driver(&tps80031_driver); |
| } |
| subsys_initcall(tps80031_init); |
| |
| static void __exit tps80031_exit(void) |
| { |
| i2c_del_driver(&tps80031_driver); |
| } |
| module_exit(tps80031_exit); |
| |
| MODULE_DESCRIPTION("TPS80031 core driver"); |
| MODULE_LICENSE("GPL"); |