M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions
@@ -0,0 +1,189 @@
/*
* Copyright (c) 2011-2012, Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Linux Foundation, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __DEV_PM8921_H
#define __DEV_PM8921_H
#include <sys/types.h>
#include <dev/pm8921_leds.h>
enum {
lvs_start = 1,
lvs_1 = lvs_start,
lvs_2,
lvs_3,
lvs_4,
lvs_5,
lvs_6,
lvs_7,
lvs_end = lvs_7,
};
enum {
mpp_start = 1,
mpp_1 = mpp_start,
mpp_2,
mpp_3,
mpp_4,
mpp_5,
mpp_6,
mpp_7,
mpp_8,
mpp_9,
mpp_10,
mpp_11,
mpp_12,
mpp_end = mpp_12,
};
typedef enum {
BAT_VOL_2_8 = 0,
BAT_VOL_2_9,
BAT_VOL_3_0,
BAT_VOL_3_1,
BAT_VOL_3_2,
BAT_VOL_3_3,
BAT_VOL_3_4,
BAT_VOL_3_5,
BAT_VOL_3_6,
BAT_VOL_3_7,
BAT_VOL_3_8,
BAT_VOL_3_9,
BAT_VOL_4_0,
BAT_VOL_4_1,
BAT_VOL_4_2,
BAT_VOL_4_3,
} bat_vol_t;
#define PM_GPIO_DIR_OUT 0x01
#define PM_GPIO_DIR_IN 0x02
#define PM_GPIO_DIR_BOTH (PM_GPIO_DIR_OUT | PM_GPIO_DIR_IN)
/* output_buffer */
#define PM_GPIO_OUT_BUF_OPEN_DRAIN 1
#define PM_GPIO_OUT_BUF_CMOS 0
#define PM_GPIO_PULL_UP_30 0
#define PM_GPIO_PULL_UP_1_5 1
#define PM_GPIO_PULL_UP_31_5 2
/* 1.5uA + 30uA boost */
#define PM_GPIO_PULL_UP_1_5_30 3
#define PM_GPIO_PULL_DN 4
#define PM_GPIO_PULL_NO 5
#define PM_GPIO_STRENGTH_NO 0
#define PM_GPIO_STRENGTH_HIGH 1
#define PM_GPIO_STRENGTH_MED 2
#define PM_GPIO_STRENGTH_LOW 3
#define PM_GPIO_FUNC_NORMAL 0
#define PM_GPIO_FUNC_PAIRED 1
#define PM_GPIO_FUNC_1 2
#define PM_GPIO_FUNC_2 3
/* LDO define values */
#define LDO_P_MASK (1 << 7)
#define LDO_2 (2)
#define LDO_8 (8 | LDO_P_MASK)
#define LDO_11 (11 | LDO_P_MASK)
#define LDO_23 (23 | LDO_P_MASK)
enum
{
LDO_VOLTAGE_1_2V = 0,
LDO_VOLTAGE_1_8V = 1,
LDO_VOLTAGE_3_0V = 2,
LDO_VOLTAGE_ENTRIES
};
#define PM_GPIO(_x) ((_x) - 1)
#define PM_IRQ_BLOCK(_x) (_x)
#define PM_IRQ_BLOCK_GPIO_START PM_IRQ_BLOCK(24)
#define PM_GPIO_BLOCK_ID(gpio) (PM_IRQ_BLOCK_GPIO_START + (gpio)/8)
#define PM_GPIO_ID_TO_BIT_MASK(gpio) (1 << ((gpio)%8))
#define PM_PWRKEY_BLOCK_ID 6
#define PM_PWRKEY_PRESS_BIT (1 << 3)
typedef int (*pm8921_read_func)(uint8_t *data, uint32_t length, uint32_t addr);
typedef int (*pm8921_write_func)(uint8_t *data, uint32_t length, uint32_t addr);
typedef struct
{
uint32_t initialized;
pm8921_read_func read;
pm8921_write_func write;
} pm8921_dev_t;
struct pm8921_gpio {
int direction;
int output_buffer;
int output_value;
int pull;
int vin_sel;
int out_strength;
int function;
int inv_int_pol;
int disable_pin;
};
struct pm89xx_vreg {
const char *name;
uint8_t type;
uint16_t test_reg;
uint16_t ctrl_reg;
};
void pm8921_init(pm8921_dev_t *);
int pm8921_gpio_config(int gpio, struct pm8921_gpio *param);
void pm8921_boot_done(void);
int pm8921_ldo_set_voltage(uint32_t ldo_id, uint32_t voltage);
int pm8921_config_reset_pwr_off(unsigned reset);
int pm8921_gpio_get(uint8_t gpio, uint8_t *status);
int pm8921_pwrkey_status(uint8_t *status);
int pm8921_config_led_current(enum pm8921_leds led_num,
uint8_t current,
enum led_mode sink,
int enable);
int pm8921_config_drv_keypad(unsigned int drv_flash_sel,
unsigned int flash_logic,
unsigned int flash_ensel);
int pm8921_low_voltage_switch_enable(uint8_t lvs_id);
int pm8921_mpp_set_digital_output(uint8_t mpp_id);
int pm8921_rtc_alarm_disable(void);
int pm89xx_bat_alarm_set(bat_vol_t, bat_vol_t);
int pm89xx_bat_alarm_status(uint8_t *, uint8_t *);
int pm89xx_vbus_status(void);
int pm89xx_ldo_set_voltage(const char * , uint32_t);
#endif
@@ -0,0 +1,99 @@
/*
* * Copyright (c) 2011, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __PMIC_LED_H
#define __PMIC_LED_H
/* LED CNTL register */
#define LED_CNTL_BASE 0x131
#define PM8921_LED_CNTL_REG(n) (LED_CNTL_BASE + n)
#define LED_DRV0_CNTL PM8921_LED_CNTL_REG(0)
#define LED_DRV1_CNTL PM8921_LED_CNTL_REG(1)
#define LED_DRV2_CNTL PM8921_LED_CNTL_REG(2)
/* LED CNTL setting */
/* Current settings:
* [00000, 10100]: Iout = x * 2 mA
* [10101, 11111]: invalid settings
*/
#define LED_CURRENT_SET(x) ((x) << 3)
#define LED_SIGNAL_SELECT(x) ((x) << 0)
#define PM8921_DRV_KEYPAD_CNTL_REG 0x48
/* Keypad DRV CNTL Settings */
#define DRV_FLASH_SEL(x) ((x) << 4)
#define FLASH_LOGIC_SEL(x) ((x) << 2)
#define FLASH_ENSEL(x) ((x) << 0)
#define MAX_LC_LED_BRIGHTNESS 20
#define MAX_FLASH_BRIGHTNESS 15
#define MAX_KB_LED_BRIGHTNESS 15
/*
* led ids
* @PM8921_ID_LED_0 - First low current led
* @PM8921_ID_LED_1 - Second low current led
* @PM8921_ID_LED_2 - Third low current led
*/
enum pm8921_leds {
PM8921_ID_LED_0,
PM8921_ID_LED_1,
PM8921_ID_LED_2,
};
enum led_mode{
MANUAL,
PWM1,
PWM2,
PWM3,
DBUS1,
DBUS2,
DBUS3,
DBUS4,
};
enum kp_backlight_mode{
MANUAL_MODE,
DBUS1_MODE,
DBUS2_MODE,
LPG_MODE,
};
enum kp_backlight_flash_logic{
FLASH_ON_WITH_DTEST_HIGH,
FLASH_ON_WITH_DTEST_LOW,
};
#endif
@@ -0,0 +1,166 @@
/*
* * Copyright (c) 2011, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __PMIC_PWM_H
#define __PMIC_PWM_H
/* PMIC 8921 LPG defines */
#define PM8921_LPG_CTL_BASE (0x13C)
#define PM8921_LPG_CTL(n) (PM8921_LPG_CTL_BASE + (n))
#define PM8921_LPG_BANK_SEL (0x143)
#define PM8921_LPG_BANK_ENABLE (0x144)
#define USEC_PER_SEC 1000000L
#define NSEC_PER_SEC 1000000000L
#define NSEC_PER_USEC 1000
#define PWM_FREQ_HZ 300
#define PWM_LEVEL 15
#define NUM_CLOCKS 3
#define NUM_PRE_DIVIDE 4
#define NUM_LPG_CTL_REGS 7
#define PRE_DIVIDE_0 2
#define PRE_DIVIDE_1 3
#define PRE_DIVIDE_2 5
#define PRE_DIVIDE_3 6
#define PRE_DIVIDE_MIN PRE_DIVIDE_0
#define PRE_DIVIDE_MAX PRE_DIVIDE_3
#define PM_PWM_M_MIN 0
#define PM_PWM_M_MAX 7
#define NSEC_1000HZ (NSEC_PER_SEC / 1000)
#define NSEC_32768HZ (NSEC_PER_SEC / 32768)
#define NSEC_19P2MHZ (NSEC_PER_SEC / 19200000)
#define CLK_PERIOD_MIN NSEC_19P2MHZ
#define CLK_PERIOD_MAX NSEC_1000HZ
#define MIN_MPT ((PRE_DIVIDE_MIN * CLK_PERIOD_MIN) << PM_PWM_M_MIN)
#define MAX_MPT ((PRE_DIVIDE_MAX * CLK_PERIOD_MAX) << PM_PWM_M_MAX)
/* The MAX value is computation limit. Hardware limit is 393 seconds. */
#define PM_PWM_PERIOD_MAX (274 * USEC_PER_SEC)
/* The MIN value is hardware limit. */
#define PM_PWM_PERIOD_MIN 7 /* micro seconds */
#define PWM_PERIOD_USEC (USEC_PER_SEC / PWM_FREQ_HZ)
#define PWM_DUTY_LEVEL (PWM_PERIOD_USEC / PWM_LEVEL)
/* Control 0 */
#define PM_PWM_1KHZ_COUNT_MASK 0xF0
#define PM_PWM_1KHZ_COUNT_SHIFT 4
#define PM_PWM_1KHZ_COUNT_MAX 15
#define PM_PWM_OUTPUT_EN 0x08
#define PM_PWM_PWM_EN 0x04
#define PM_PWM_RAMP_GEN_EN 0x02
#define PM_PWM_RAMP_START 0x01
#define PM_PWM_PWM_START (PM_PWM_OUTPUT_EN | PM_PWM_PWM_EN)
#define PM_PWM_RAMP_GEN_START (PM_PWM_RAMP_GEN_EN | PM_PWM_RAMP_START)
/* Control 1 */
#define PM_PWM_REVERSE_EN 0x80
#define PM_PWM_BYPASS_LUT 0x40
#define PM_PWM_HIGH_INDEX_MASK 0x3F
/* Control 2 */
#define PM_PWM_LOOP_EN 0x80
#define PM_PWM_RAMP_UP 0x40
#define PM_PWM_LOW_INDEX_MASK 0x3F
/* Control 3 */
#define PM_PWM_VALUE_BIT7_0 0xFF
#define PM_PWM_VALUE_BIT5_0 0x3F
/* Control 4 */
#define PM_PWM_VALUE_BIT8 0x80
#define PM_PWM_CLK_SEL_MASK 0x60
#define PM_PWM_CLK_SEL_SHIFT 5
#define PM_PWM_CLK_SEL_NO 0
#define PM_PWM_CLK_SEL_1KHZ 1
#define PM_PWM_CLK_SEL_32KHZ 2
#define PM_PWM_CLK_SEL_19P2MHZ 3
#define PM_PWM_PREDIVIDE_MASK 0x18
#define PM_PWM_PREDIVIDE_SHIFT 3
#define PM_PWM_PREDIVIDE_2 0
#define PM_PWM_PREDIVIDE_3 1
#define PM_PWM_PREDIVIDE_5 2
#define PM_PWM_PREDIVIDE_6 3
#define PM_PWM_M_MASK 0x07
#define PM_PWM_M_MIN 0
#define PM_PWM_M_MAX 7
/* Control 5 */
#define PM_PWM_PAUSE_COUNT_HI_MASK 0xFC
#define PM_PWM_PAUSE_COUNT_HI_SHIFT 2
#define PM_PWM_PAUSE_ENABLE_HIGH 0x02
#define PM_PWM_SIZE_9_BIT 0x01
/* Control 6 */
#define PM_PWM_PAUSE_COUNT_LO_MASK 0xFC
#define PM_PWM_PAUSE_COUNT_LO_SHIFT 2
#define PM_PWM_PAUSE_ENABLE_LOW 0x02
#define PM_PWM_RESERVED 0x01
#define PM_PWM_PAUSE_COUNT_MAX 56 /* < 2^6 = 64*/
struct pm8921_pwm_config {
uint8_t pwm_size; /* round up to 6 or 9 for 6/9-bit PWM SIZE */
uint8_t clk;
uint8_t pre_div;
uint8_t pre_div_exp;
uint8_t pwm_value;
uint8_t bypass_lut;
uint8_t pwm_ctl[NUM_LPG_CTL_REGS];
};
/* External PWM functions */
int pm8921_pwm_enable(uint8_t pwm_id, pm8921_dev_t *dev);
int pm8921_pwm_config(uint8_t pwm_id,
uint32_t duty_us,
uint32_t period_us,
pm8921_dev_t *dev);
#endif
@@ -0,0 +1,749 @@
/*
* Copyright (c) 2011-2013, Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Linux Foundation, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <assert.h>
#include <string.h>
#include <sys/types.h>
#include <err.h>
#include <dev/pm8921.h>
#include <platform/timer.h>
#include "pm8921_hw.h"
static pm8921_dev_t *dev;
static uint8_t ldo_n_voltage_mult[LDO_VOLTAGE_ENTRIES] = {
18, /* 1.2V */
0,
0,
};
static uint8_t ldo_p_voltage_mult[LDO_VOLTAGE_ENTRIES] = {
0,
6, /* 1.8V */
30, /* 3.0V */
};
/* Intialize the pmic driver */
void pm8921_init(pm8921_dev_t *pmic)
{
ASSERT(pmic);
ASSERT(pmic->read);
ASSERT(pmic->write);
dev = pmic;
dev->initialized = 1;
}
static int pm8921_masked_write(uint16_t addr,
uint8_t mask, uint8_t val)
{
int rc;
uint8_t reg;
rc = dev->read(&reg, 1, addr);
if (rc)
{
return rc;
}
reg &= ~mask;
reg |= val & mask;
rc = dev->write(&reg, 1, addr);
return rc;
}
/* Set the BOOT_DONE flag */
void pm8921_boot_done(void)
{
uint8_t val;
ASSERT(dev);
ASSERT(dev->initialized);
dev->read(&val, 1, PBL_ACCESS_2);
val |= PBL_ACCESS_2_ENUM_TIMER_STOP;
/* TODO: Remove next line when h/w is rewired for battery simulation.*/
val |= (0x7 << 2);
dev->write(&val, 1, PBL_ACCESS_2);
dev->read(&val, 1, SYS_CONFIG_2);
val |= (SYS_CONFIG_2_BOOT_DONE | SYS_CONFIG_2_ADAPTIVE_BOOT_DISABLE);
dev->write(&val, 1, SYS_CONFIG_2);
}
/* Configure PMIC GPIO */
int pm8921_gpio_config(int gpio, struct pm8921_gpio *param)
{
int ret;
uint8_t bank[6];
uint8_t output_buf_config;
uint8_t output_value;
static uint8_t dir_map[] = {
PM_GPIO_MODE_OFF,
PM_GPIO_MODE_OUTPUT,
PM_GPIO_MODE_INPUT,
PM_GPIO_MODE_BOTH,
};
if (param == NULL) {
dprintf (CRITICAL, "pm8291_gpio struct not defined\n");
return -1;
}
/* Select banks and configure the gpio */
bank[0] = PM_GPIO_WRITE |
((param->vin_sel << PM_GPIO_VIN_SHIFT) &
PM_GPIO_VIN_MASK) |
PM_GPIO_MODE_ENABLE;
/* bank1 */
if ((param->direction & PM_GPIO_DIR_OUT) && param->output_buffer)
output_buf_config = PM_GPIO_OUT_BUFFER_OPEN_DRAIN;
else
output_buf_config = 0;
if ((param->direction & PM_GPIO_DIR_OUT) && param->output_value)
output_value = 1;
else
output_value = 0;
bank[1] = PM_GPIO_WRITE |
((1 << PM_GPIO_BANK_SHIFT) & PM_GPIO_BANK_MASK) |
((dir_map[param->direction] << PM_GPIO_MODE_SHIFT)
& PM_GPIO_MODE_MASK) |
output_buf_config |
output_value;
bank[2] = PM_GPIO_WRITE |
((2 << PM_GPIO_BANK_SHIFT) & PM_GPIO_BANK_MASK) |
((param->pull << PM_GPIO_PULL_SHIFT) &
PM_GPIO_PULL_MASK);
bank[3] = PM_GPIO_WRITE |
((3 << PM_GPIO_BANK_SHIFT) & PM_GPIO_BANK_MASK) |
((param->out_strength << PM_GPIO_OUT_STRENGTH_SHIFT) &
PM_GPIO_OUT_STRENGTH_MASK) |
(param->disable_pin ? PM_GPIO_PIN_DISABLE : PM_GPIO_PIN_ENABLE);
bank[4] = PM_GPIO_WRITE |
((4 << PM_GPIO_BANK_SHIFT) & PM_GPIO_BANK_MASK) |
((param->function << PM_GPIO_FUNC_SHIFT) &
PM_GPIO_FUNC_MASK);
bank[5] = PM_GPIO_WRITE |
((5 << PM_GPIO_BANK_SHIFT) & PM_GPIO_BANK_MASK) |
(param->inv_int_pol ? 0 : PM_GPIO_NON_INT_POL_INV);
ret = dev->write(bank, 6, GPIO_CNTL(gpio));
if (ret) {
dprintf(CRITICAL, "Failed to write to PM8921 ret=%d.\n", ret);
return -1;
}
return 0;
}
/* Reads the value of the irq status for the requested block */
int pm8921_irq_get_block_status(uint8_t block, uint8_t *status)
{
int ret = 0;
/* Select the irq block to be read */
ret = dev->write(&block, 1, IRQ_BLOCK_SEL_USR_ADDR);
if(!ret)
{
/* Read the real time irq status value for the block */
ret = dev->read(status, 1, IRQ_STATUS_RT_USR_ADDR);
}
return ret;
}
/* Reads the status of requested gpio */
int pm8921_gpio_get(uint8_t gpio, uint8_t *status)
{
int ret = 0;
uint8_t block_status;
ret = pm8921_irq_get_block_status(PM_GPIO_BLOCK_ID(gpio), &block_status);
if(!ret)
{
if(block_status & PM_GPIO_ID_TO_BIT_MASK(gpio))
*status = 1;
else
*status = 0;
}
return ret;
}
int pm8921_pwrkey_status(uint8_t *is_pwrkey_pressed)
{
int ret = 0;
uint8_t block_status;
ret = pm8921_irq_get_block_status(PM_PWRKEY_BLOCK_ID, &block_status);
if (!ret)
{
if(block_status & PM_PWRKEY_PRESS_BIT)
*is_pwrkey_pressed = 1;
else
*is_pwrkey_pressed = 0;
}
return ret;
}
int pm8921_ldo_set_voltage(uint32_t ldo_id, uint32_t voltage)
{
uint8_t mult;
uint8_t val = 0;
uint32_t ldo_number = (ldo_id & ~LDO_P_MASK);
int32_t ret = 0;
/* Find the voltage multiplying factor */
if(ldo_id & LDO_P_MASK)
mult = ldo_p_voltage_mult[voltage];
else
mult = ldo_n_voltage_mult[voltage];
/* Program the TEST reg */
if (ldo_id & LDO_P_MASK){
/* Bank 2, only for p ldo, use 1.25V reference */
val = 0x0;
val |= ( 1 << PM8921_LDO_TEST_REG_RW );
val |= ( 2 << PM8921_LDO_TEST_REG_BANK_SEL);
ret = dev->write(&val, 1, PM8921_LDO_TEST_REG(ldo_number));
if (ret) {
dprintf(CRITICAL, "Failed to write to PM8921 LDO Test Reg ret=%d.\n", ret);
return -1;
}
/* Bank 4, only for p ldo, disable output range ext, normal capacitance */
val = 0x0;
val |= ( 1 << PM8921_LDO_TEST_REG_RW );
val |= ( 4 << PM8921_LDO_TEST_REG_BANK_SEL);
ret = dev->write(&val, 1, PM8921_LDO_TEST_REG(ldo_number));
if (ret) {
dprintf(CRITICAL, "Failed to write to PM8921 LDO Test Reg ret=%d.\n", ret);
return -1;
}
}
/* Program the CTRL reg */
val = 0x0;
val |= ( 1 << PM8921_LDO_CTRL_REG_ENABLE);
val |= ( 1 << PM8921_LDO_CTRL_REG_PULL_DOWN);
val |= ( 0 << PM8921_LDO_CTRL_REG_POWER_MODE);
val |= ( mult << PM8921_LDO_CTRL_REG_VOLTAGE);
ret = dev->write(&val, 1, PM8921_LDO_CTRL_REG(ldo_number));
if (ret) {
dprintf(CRITICAL, "Failed to write to PM8921 LDO Ctrl Reg ret=%d.\n", ret);
return -1;
}
return 0;
}
/*
* Configure PMIC for reset and power off.
* reset = 1: Configure reset.
* reset = 0: Configure power off.
*/
int pm8921_config_reset_pwr_off(unsigned reset)
{
int rc;
/* Enable SMPL(Short Momentary Power Loss) if resetting is desired. */
rc = pm8921_masked_write(PM8921_SLEEP_CTRL_REG,
SLEEP_CTRL_SMPL_EN_MASK,
(reset ? SLEEP_CTRL_SMPL_EN_RESET : SLEEP_CTRL_SMPL_EN_PWR_OFF));
if (rc)
{
goto read_write_err;
}
/*
* Select action to perform (reset or shutdown) when PS_HOLD goes low.
* Also ensure that KPD, CBL0, and CBL1 pull ups are enabled and that
* USB charging is enabled.
*/
rc = pm8921_masked_write(PM8921_PON_CTRL_1_REG,
PON_CTRL_1_PULL_UP_MASK | PON_CTRL_1_USB_PWR_EN
| PON_CTRL_1_WD_EN_MASK,
PON_CTRL_1_PULL_UP_MASK | PON_CTRL_1_USB_PWR_EN
| (reset ? PON_CTRL_1_WD_EN_RESET : PON_CTRL_1_WD_EN_PWR_OFF));
if (rc)
{
goto read_write_err;
}
read_write_err:
return rc;
}
/* A wrapper function to configure PMIC PWM
* pwm_id : Channel number to configure
* duty_us : duty cycle for output waveform in micro seconds
* period_us : period for output waveform in micro seconds
*/
int pm8921_set_pwm_config(uint8_t pwm_id, uint32_t duty_us, uint32_t period_us)
{
int rc;
rc = pm8921_pwm_config(pwm_id, duty_us, period_us, dev);
return rc;
}
/* A wrapper function to enable PMIC PWM
* pwm_id : Channel number to enable
*/
int pm8921_pwm_channel_enable(uint8_t pwm_id)
{
int rc;
rc = pm8921_pwm_enable(pwm_id, dev);
return rc;
}
/* Configure LED's for current sinks
* enable = 1: Configure external signal detection
* for the sink with the current level
* enable = 0: Turn off external signal detection
*
* Values for sink are defined as follows:
* 0 = MANUAL, turn on LED when curent [00000, 10100]
* 1 = PWM1
* 2 = PWM2
* 3 = PWM3
* 4 = DBUS1
* 5 = DBUS2
* 6 = DBUS3
* 7 = DBUS4
*
* Current settings are calculated as per the equation:
* [00000, 10100]: Iout = current * 2 mA
* [10101, 11111]: invalid settings
*/
int pm8921_config_led_current(enum pm8921_leds led_num,
uint8_t current,
enum led_mode sink,
int enable)
{
uint8_t val;
int ret;
/* Program the CTRL reg */
val = 0x0;
if (enable != 0)
{
if (current > 0x15)
{
dprintf(CRITICAL, "Invalid current settings for PM8921 LED Ctrl Reg \
current=%d.\n", current);
return -1;
}
if (sink > 0x7)
{
dprintf(CRITICAL, "Invalid signal selection for PM8921 LED Ctrl Reg \
sink=%d.\n", sink);
return -1;
}
val |= LED_CURRENT_SET(current);
val |= LED_SIGNAL_SELECT(sink);
}
ret = dev->write(&val, 1, PM8921_LED_CNTL_REG(led_num));
if (ret)
dprintf(CRITICAL, "Failed to write to PM8921 LED Ctrl Reg ret=%d.\n", ret);
return ret;
}
/* Configure DRV_KEYPAD
*drv_flash_sel:
* 0000 = off
* Iout = drv_flash_sel * 20 mA (300 mA driver)
* Iout = drv_flash_sel * 40 mA (600 mA driver)
*
* flash_logic = 0 : flash is on when DTEST is high
* flash_logic = 0 : flash is off when DTEST is high
*
* flash_ensel = 0 : manual mode, turn on flash when drv_flash_sel > 0
* flash_ensel = 1 : DBUS1
* flash_ensel = 2 : DBUS2
* flash_ensel = 3 : enable flash from LPG
*/
int pm8921_config_drv_keypad(unsigned int drv_flash_sel, unsigned int flash_logic, unsigned int flash_ensel)
{
uint8_t val;
int ret;
/* Program the CTRL reg */
val = 0x0;
if (drv_flash_sel != 0)
{
if (drv_flash_sel > 0x0F)
{
dprintf(CRITICAL, "Invalid current settings for PM8921 \
KEYPAD_DRV Ctrl Reg drv_flash_sel=%d.\n", drv_flash_sel);
return -1;
}
if (flash_logic > 1)
{
dprintf(CRITICAL, "Invalid signal selection for PM8921 \
KEYPAD_DRV Ctrl Reg flash_logic=%d.\n", flash_logic);
return -1;
}
if (flash_ensel > 3)
{
dprintf(CRITICAL, "Invalid signal selection for PM8921 \
KEYPAD_DRV Ctrl Reg flash_ensel=%d.\n", flash_ensel);
return -1;
}
val |= DRV_FLASH_SEL(drv_flash_sel);
val |= FLASH_LOGIC_SEL(flash_logic);
val |= FLASH_ENSEL(flash_ensel);
}
ret = dev->write(&val, 1, PM8921_DRV_KEYPAD_CNTL_REG);
if (ret)
dprintf(CRITICAL, "Failed to write to PM8921 KEYPAD_DRV Ctrl Reg ret=%d.\n", ret);
return ret;
}
int pm8921_low_voltage_switch_enable(uint8_t lvs_id)
{
int ret = NO_ERROR;
uint8_t val;
if (lvs_id < lvs_start || lvs_id > lvs_end) {
dprintf(CRITICAL, "Requested unsupported LVS.\n");
return ERROR;
}
if (lvs_id == lvs_2) {
dprintf(CRITICAL, "No support for LVS2 yet!\n");
return ERROR;
}
/* Read LVS_TEST Reg first*/
ret = dev->read(&val, 1, PM8921_LVS_TEST_REG(lvs_id));
if (ret) {
dprintf(CRITICAL, "Failed to read LVS_TEST Reg ret=%d.\n", ret);
return ret;
}
/* Check if switch is already ON */
val = val & PM8921_LVS_100_TEST_VOUT_OK;
if (val)
return ret;
/* Turn on switch in normal mode */
val = 0;
val |= PM8921_LVS_100_CTRL_SW_EN; /* Enable Switch */
val |= PM8921_LVS_100_CTRL_SLEEP_B_IGNORE; /* Ignore sleep mode pin */
ret = dev->write(&val, 1, PM8921_LVS_CTRL_REG(lvs_id));
if (ret)
dprintf(CRITICAL, "Failed to write LVS_CTRL Reg ret=%d.\n", ret);
return ret;
}
int pm8921_mpp_set_digital_output(uint8_t mpp_id)
{
int ret = NO_ERROR;
uint8_t val;
if (mpp_id < mpp_start || mpp_id > mpp_end) {
dprintf(CRITICAL, "Requested unsupported MPP.\n");
return ERROR;
}
val = 0;
/* Configure in digital output mode */
val |= PM8921_MPP_CTRL_DIGITAL_OUTPUT;
val |= PM8921_MPP_CTRL_VIO_1; /* Set input voltage to 1.8V */
val |= PM8921_MPP_CTRL_OUTPUT_HIGH; /* Set mpp to high */
ret = dev->write(&val, 1, PM8921_MPP_CTRL_REG(mpp_id));
if (ret) {
dprintf(CRITICAL, "Failed to write MPP_CTRL Reg ret=%d.\n",
ret);
}
return ret;
}
int pm8921_HDMI_Switch(void)
{
int ret = NO_ERROR;
uint8_t val;
/* Value for HDMI MVS 5V Switch */
val = 0x068;
/* Turn on MVS 5V HDMI switch */
ret = dev->write(&val, 1, PM8921_MVS_5V_HDMI_SWITCH);
if (ret) {
dprintf(CRITICAL,
"Failed to turn ON MVS 5V hdmi switch ret=%d.\n", ret);
}
return ret;
}
int pm8921_rtc_alarm_disable(void)
{
int rc;
uint8_t reg;
rc = dev->read(&reg, 1, PM8921_RTC_CTRL);
if (rc) {
dprintf(CRITICAL,"Failed to read RTC_CTRL reg = %d\n",rc);
return rc;
}
reg = (reg & ~PM8921_RTC_ALARM_ENABLE);
rc = dev->write(&reg, 1, PM8921_RTC_CTRL);
if (rc) {
dprintf(CRITICAL,"Failed to write RTC_CTRL reg = %d\n",rc);
return rc;
}
return rc;
}
/*
* Set battery alarm with low & high threshold values
*/
int pm89xx_bat_alarm_set(bat_vol_t up_thresh_vol, bat_vol_t low_thresh_vol)
{
int rc;
uint8_t reg = 0;
if ((up_thresh_vol > BAT_VOL_4_3) || (low_thresh_vol > BAT_VOL_4_3)) {
dprintf(CRITICAL, "Input voltage not in permissible range\n");
return 1;
}
/*
* Write upper & lower threshold values
*/
reg = (up_thresh_vol << PM89XX_BAT_UP_THRESH_VOL) | low_thresh_vol;
rc = dev->write(&reg, 1, PM89XX_BAT_ALRM_THRESH);
if (rc) {
dprintf(CRITICAL, "Failed to set BAT_THRESH reg = %d\n", rc);
return rc;
}
/* Read Alarm control to use the existing hysteresis values */
rc = dev->read(&reg, 1, PM89XX_BAT_ALRM_CTRL);
if (rc) {
dprintf(CRITICAL, "Failed to read BAT_ALARM reg = %d\n", rc);
return rc;
}
/* Enable battery alarm */
reg |= PM89XX_BAT_ALRM_ENABLE;
rc = dev->write(&reg, 1, PM89XX_BAT_ALRM_CTRL);
if (rc) {
dprintf(CRITICAL, "Failed to enable BAT_ALARM reg = %d\n", rc);
return rc;
}
/* Wait for the comparator o/p to settle */
mdelay(10);
return rc;
}
/*
* API to return status of battery
* if the vbatt is below upper threshold return 0
* if the vbatt is below lower threshold return 1
*/
int pm89xx_bat_alarm_status(uint8_t *high_status, uint8_t *low_status)
{
int rc = 0;
uint8_t reg = 0;
/* Read the battery status */
rc = dev->read(&reg, 1, PM89XX_BAT_ALRM_CTRL);
if (rc) {
dprintf(CRITICAL, "Failed to read BAT_ALARM reg = %d\n", rc);
return rc;
}
/* Return the status if battery alarm is enabled */
if (reg & PM89XX_BAT_ALRM_ENABLE) {
*high_status = (reg & PM89XX_BAT_UPR_STATUS);
*low_status = (reg & PM89XX_BAT_LWR_STATUS);
} else {
dprintf(CRITICAL, "Battery alarm is not enabled\n");
return 1;
}
return rc;
}
/*
* Return 1 if VBUS is connected, 0 otherwise
*/
int pm89xx_vbus_status(void)
{
int rc;
uint8_t reg = 0;
rc = dev->read(&reg, 1, PM89XX_USB_OVP_CTRL);
if (rc) {
dprintf(CRITICAL, "Failed to read USB OVP CTRL = %d\n", rc);
return rc;
}
reg &= PM89XX_VBUS_INPUT_STATUS;
return reg;
}
static struct pm89xx_vreg *ldo_get(const char *ldo_name)
{
uint8_t i;
struct pm89xx_vreg *ldo = NULL;
for (i = 0; i < ARRAY_SIZE(ldo_data); i++) {
ldo = &ldo_data[i];
if (!strncmp(ldo->name, ldo_name, strlen(ldo_name)))
break;
}
return ldo;
}
/*
* API takes LDO name & voltage as input
* Input voltage is taken in mVs
* PLDO voltage ranging from 1500mV to 3000mV
* NLDO voltage ranging from 750mV to 1525mV
*/
int pm89xx_ldo_set_voltage(const char *ldo_name, uint32_t voltage)
{
uint8_t mult;
uint8_t val = 0;
int32_t ret = 0;
struct pm89xx_vreg *ldo;
/* Find the LDO info from table */
ldo = ldo_get(ldo_name);
if (!ldo) {
dprintf(CRITICAL, "Requested LDO is not supported : \
%s\n", ldo_name);
return -1;
}
/* Find the voltage multiplying factor */
if (ldo->type == PLDO_TYPE) {
if (voltage < PLDO_MV_VMIN)
voltage = PLDO_MV_VMIN;
else if (voltage > PLDO_MV_VMAX)
voltage = PLDO_MV_VMAX;
mult = (voltage - PLDO_MV_VMIN) / PLDO_MV_VSTEP;
} else {
if (voltage < NLDO_MV_VMIN)
voltage = NLDO_MV_VMIN;
else if (voltage > NLDO_MV_VMAX)
voltage = NLDO_MV_VMAX;
mult = (voltage - NLDO_MV_VMIN) / NLDO_MV_VSTEP;
}
/* Program the TEST reg */
if (ldo->type == PLDO_TYPE) {
/* Bank 2, only for p ldo, use 1.25V reference */
val = 0x0;
val |= (1 << PM8921_LDO_TEST_REG_RW);
val |= (2 << PM8921_LDO_TEST_REG_BANK_SEL);
ret = dev->write(&val, 1, ldo->test_reg);
if (ret) {
dprintf(CRITICAL, "Failed to write to PM8921 LDO Test \
Reg ret=%d.\n", ret);
return -1;
}
/*
* Bank 4, only for p ldo, disable output range ext,
* normal capacitance
*/
val = 0x0;
val |= (1 << PM8921_LDO_TEST_REG_RW);
val |= (4 << PM8921_LDO_TEST_REG_BANK_SEL);
ret = dev->write(&val, 1, ldo->test_reg);
if (ret) {
dprintf(CRITICAL, "Failed to write to PM8921 LDO Test \
Reg ret=%d.\n", ret);
return -1;
}
}
/* Program the CTRL reg */
val = 0x0;
val |= (1 << PM8921_LDO_CTRL_REG_ENABLE);
val |= (1 << PM8921_LDO_CTRL_REG_PULL_DOWN);
val |= (0 << PM8921_LDO_CTRL_REG_POWER_MODE);
val |= (mult << PM8921_LDO_CTRL_REG_VOLTAGE);
ret = dev->write(&val, 1, ldo->ctrl_reg);
if (ret) {
dprintf(CRITICAL, "Failed to write to PM8921 LDO Ctrl Reg \
ret=%d.\n", ret);
return -1;
}
return 0;
}
@@ -0,0 +1,175 @@
/*
* Copyright (c) 2011-2012, Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Linux Foundation, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <bits.h>
#define PBL_ACCESS_2 0x005
#define PBL_ACCESS_2_ENUM_TIMER_STOP (1 << 1)
#define SYS_CONFIG_2 0x007
#define SYS_CONFIG_2_BOOT_DONE (1 << 6)
#define SYS_CONFIG_2_ADAPTIVE_BOOT_DISABLE (1 << 7)
#define PM8921_LDO_REG_BASE 0x0AE
#define PM8921_LDO_CTRL_REG(id) (PM8921_LDO_REG_BASE + (2 * (id-1)))
#define PM8921_LDO_TEST_REG(id) (PM8921_LDO_CTRL_REG(id) + 1)
/* Bit offsets LDO CTRL register */
#define PM8921_LDO_CTRL_REG_ENABLE 7
#define PM8921_LDO_CTRL_REG_PULL_DOWN 6
#define PM8921_LDO_CTRL_REG_POWER_MODE 5
#define PM8921_LDO_CTRL_REG_VOLTAGE 0
/* Bit offsets LDO Test register */
#define PM8921_LDO_TEST_REG_BANK_SEL 4
#define PM8921_LDO_TEST_REG_RW 7
#define PM8921_LDO_TEST_REG_BANK2_RANGE_SEL 2
#define PM8921_LDO_TEST_REG_BANK2_FINE_STEP 1
#define PM8921_LDO_TEST_REG_BANK4_RANGE_EXT 0
#define GPIO_CNTL_BASE 0x150
#define GPIO_CNTL(n) (GPIO_CNTL_BASE + n)
/* GPIO Bank register programming */
#define PM_GPIO_BANK_MASK 0x70
#define PM_GPIO_BANK_SHIFT 4
#define PM_GPIO_WRITE 0x80
/* Bank 0 */
#define PM_GPIO_VIN_MASK 0x0E
#define PM_GPIO_VIN_SHIFT 1
#define PM_GPIO_MODE_ENABLE 0x01
/* Bank 1 */
#define PM_GPIO_MODE_MASK 0x0C
#define PM_GPIO_MODE_SHIFT 2
#define PM_GPIO_OUT_BUFFER_OPEN_DRAIN 0x02
#define PM_GPIO_OUT_INVERT 0x01
#define PM_GPIO_MODE_OFF 3
#define PM_GPIO_MODE_OUTPUT 2
#define PM_GPIO_MODE_INPUT 0
#define PM_GPIO_MODE_BOTH 1
/* Bank 2 */
#define PM_GPIO_PULL_MASK 0x0E
#define PM_GPIO_PULL_SHIFT 1
/* Bank 3 */
#define PM_GPIO_OUT_STRENGTH_MASK 0x0C
#define PM_GPIO_OUT_STRENGTH_SHIFT 2
#define PM_GPIO_PIN_ENABLE 0x00
#define PM_GPIO_PIN_DISABLE 0x01
/* Bank 4 */
#define PM_GPIO_FUNC_MASK 0x0E
#define PM_GPIO_FUNC_SHIFT 1
/* Bank 5 */
#define PM_GPIO_NON_INT_POL_INV 0x08
/* PON CTRL 1 register */
#define PM8921_PON_CTRL_1_REG 0x01C
#define PON_CTRL_1_PULL_UP_MASK 0xE0
#define PON_CTRL_1_USB_PWR_EN 0x10
#define PON_CTRL_1_WD_EN_MASK 0x08
#define PON_CTRL_1_WD_EN_RESET 0x08
#define PON_CTRL_1_WD_EN_PWR_OFF 0x00
/* SLEEP CTRL register */
#define PM8921_SLEEP_CTRL_REG 0x10A
#define SLEEP_CTRL_SMPL_EN_MASK 0x04
#define SLEEP_CTRL_SMPL_EN_RESET 0x04
#define SLEEP_CTRL_SMPL_EN_PWR_OFF 0x00
#define IRQ_BLOCK_SEL_USR_ADDR 0x1C0
#define IRQ_STATUS_RT_USR_ADDR 0x1C3
#define PM8921_LVS_REG_BASE 0x060
#define PM8921_LVS_CTRL_REG(id) (PM8921_LVS_REG_BASE + (2 * (id-1)))
#define PM8921_LVS_TEST_REG(id) (PM8921_LVS_CTRL_REG(id) + 1)
#define PM8921_RTC_CTRL 0x11D
#define PM8921_RTC_ALARM_ENABLE (1 << 1)
#define PM8921_LVS_100_CTRL_SW_EN (1 << 7)
#define PM8921_LVS_100_CTRL_SLEEP_B_IGNORE (1 << 4)
#define PM8921_LVS_100_TEST_VOUT_OK (1 << 6)
#define PM8921_MPP_REG_BASE 0x050
#define PM8921_MPP_CTRL_REG(id) (PM8921_MPP_REG_BASE + (id-1))
#define PM8921_MPP_CTRL_DIGITAL_OUTPUT (1 << 5)
#define PM8921_MPP_CTRL_VIO_1 (1 << 2)
#define PM8921_MPP_CTRL_OUTPUT_HIGH (1 << 0)
#define PM89XX_BAT_UP_THRESH_VOL 4
#define PM89XX_BAT_ALRM_THRESH 0x23
#define PM89XX_BAT_ALRM_CTRL 0x24
#define PM89XX_USB_OVP_CTRL 0x21C
#define PM89XX_BAT_ALRM_ENABLE BIT(7)
#define PM89XX_BAT_UPR_STATUS BIT(1)
#define PM89XX_BAT_LWR_STATUS BIT(0)
#define PM89XX_VBUS_INPUT_STATUS BIT(0)
/* voltages are specified in mV */
#define PLDO_MV_VMIN 1500
#define PLDO_MV_VMAX 3000
#define PLDO_MV_VSTEP 50
#define NLDO_MV_VMIN 750
#define NLDO_MV_VMAX 1525
#define NLDO_MV_VSTEP 25
#define PLDO_TYPE 0
#define NLDO_TYPE 1
#define PM8921_MVS_5V_HDMI_SWITCH 0x70
#define LDO(_name, _type, _test_reg, _ctrl_reg) \
{\
.name = _name,\
.type = _type,\
.test_reg = _test_reg,\
.ctrl_reg = _ctrl_reg, \
}
struct pm89xx_vreg ldo_data[] = {
LDO("LDO30", PLDO_TYPE, 0x0A3, 0x0A4),
LDO("LDO31", PLDO_TYPE, 0x0A5, 0x0A6),
LDO("LDO32", PLDO_TYPE, 0x0A7, 0x0A8),
LDO("LDO33", PLDO_TYPE, 0x0C6, 0x0C7),
LDO("LDO34", PLDO_TYPE, 0x0D2, 0x0D3),
LDO("LDO35", PLDO_TYPE, 0x0D4, 0x0D5),
LDO("LDO36", PLDO_TYPE, 0x0A9, 0x0AA),
};
@@ -0,0 +1,327 @@
/*
* * Copyright (c) 2011, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <debug.h>
#include <dev/pm8921.h>
#include <dev/pm8921_pwm.h>
static char *clks[NUM_CLOCKS] = {
"1K", "32768", "19.2M"
};
static unsigned pre_div[NUM_PRE_DIVIDE] = {
PRE_DIVIDE_0, PRE_DIVIDE_1, PRE_DIVIDE_2, PRE_DIVIDE_3
};
static unsigned int pt_t[NUM_PRE_DIVIDE][NUM_CLOCKS] = {
{ PRE_DIVIDE_0 * NSEC_1000HZ,
PRE_DIVIDE_0 * NSEC_32768HZ,
PRE_DIVIDE_0 * NSEC_19P2MHZ,
},
{ PRE_DIVIDE_1 * NSEC_1000HZ,
PRE_DIVIDE_1 * NSEC_32768HZ,
PRE_DIVIDE_1 * NSEC_19P2MHZ,
},
{ PRE_DIVIDE_2 * NSEC_1000HZ,
PRE_DIVIDE_2 * NSEC_32768HZ,
PRE_DIVIDE_2 * NSEC_19P2MHZ,
},
{ PRE_DIVIDE_2 * NSEC_1000HZ,
PRE_DIVIDE_2 * NSEC_32768HZ,
PRE_DIVIDE_2 * NSEC_19P2MHZ,
},
};
static uint16_t duty_msec[PM_PWM_1KHZ_COUNT_MAX + 1] = {
0, 1, 2, 3, 4, 6, 8, 16, 18, 24, 32, 36, 64, 128, 256, 512
};
static uint16_t pause_count[PM_PWM_PAUSE_COUNT_MAX + 1] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
23, 28, 31, 42, 47, 56, 63, 83, 94, 111, 125, 167, 188, 222, 250, 333,
375, 500, 667, 750, 800, 900, 1000, 1100,
1200, 1300, 1400, 1500, 1600, 1800, 2000, 2500,
3000, 3500, 4000, 4500, 5000, 5500, 6000, 6500,
7000
};
/* Function to get the PWM size, divider, clock for the given period */
static void pm8921_pwm_calc_period(uint32_t period_us,
struct pm8921_pwm_config *pwm_conf)
{
int n, m, clk, div;
int best_m, best_div, best_clk;
int last_err, cur_err, better_err, better_m;
uint32_t tmp_p, last_p, min_err, period_n;
/* PWM Period / N : handle underflow or overflow */
if (period_us < (PM_PWM_PERIOD_MAX / NSEC_PER_USEC))
period_n = (period_us * NSEC_PER_USEC) >> 6;
else
period_n = (period_us >> 6) * NSEC_PER_USEC;
if (period_n >= MAX_MPT)
{
n = 9;
period_n >>= 3;
}
else
n = 6;
min_err = MAX_MPT;
best_m = 0;
best_clk = 0;
best_div = 0;
for (clk = 0; clk < NUM_CLOCKS; clk++)
{
for (div = 0; div < NUM_PRE_DIVIDE; div++)
{
tmp_p = period_n;
last_p = tmp_p;
for (m = 0; m <= PM_PWM_M_MAX; m++)
{
if (tmp_p <= pt_t[div][clk])
{
/* Found local best */
if (!m)
{
better_err = pt_t[div][clk] - tmp_p;
better_m = m;
}
else
{
last_err = last_p - pt_t[div][clk];
cur_err = pt_t[div][clk] - tmp_p;
if (cur_err < last_err)
{
better_err = cur_err;
better_m = m;
}
else
{
better_err = last_err;
better_m = m - 1;
}
}
if (better_err < min_err)
{
min_err = better_err;
best_m = better_m;
best_clk = clk;
best_div = div;
}
break;
}
else
{
last_p = tmp_p;
tmp_p >>= 1;
}
}
}
}
pwm_conf->pwm_size = n;
pwm_conf->clk = best_clk;
pwm_conf->pre_div = best_div;
pwm_conf->pre_div_exp = best_m;
}
/* Function to configure PWM control registers with clock, divider values */
static int pm8921_pwm_configure(uint8_t pwm_id,
struct pm8921_pwm_config *pwm_conf,
pm8921_dev_t *dev)
{
int i, len, rc = -1;
uint8_t reg;
reg = (pwm_conf->pwm_size > 6) ? PM_PWM_SIZE_9_BIT : 0;
pwm_conf->pwm_ctl[5] = reg;
reg = ((pwm_conf->clk + 1) << PM_PWM_CLK_SEL_SHIFT)
& PM_PWM_CLK_SEL_MASK;
reg |= (pwm_conf->pre_div << PM_PWM_PREDIVIDE_SHIFT)
& PM_PWM_PREDIVIDE_MASK;
reg |= pwm_conf->pre_div_exp & PM_PWM_M_MASK;
pwm_conf->pwm_ctl[4] = reg;
/* Just to let know we bypass LUT */
if (pwm_conf->bypass_lut)
{
/* CTL0 is set in pwm_enable() */
pwm_conf->pwm_ctl[0] &= PM_PWM_PWM_START;
pwm_conf->pwm_ctl[1] = PM_PWM_BYPASS_LUT;
pwm_conf->pwm_ctl[2] = 0;
if (pwm_conf->pwm_size > 6)
{
pwm_conf->pwm_ctl[3] = pwm_conf->pwm_value
& PM_PWM_VALUE_BIT7_0;
pwm_conf->pwm_ctl[4] |= (pwm_conf->pwm_value >> 1)
& PM_PWM_VALUE_BIT8;
}
else
{
pwm_conf->pwm_ctl[3] = pwm_conf->pwm_value
& PM_PWM_VALUE_BIT5_0;
}
len = 6;
}
else
{
/* Right now, we are not using LUT */
goto bail_out;
}
/* Selecting the bank */
rc = dev->write(&pwm_id, 1, PM8921_LPG_BANK_SEL);
if (rc)
goto bail_out;
for (i = 0; i < len; i++)
{
rc = dev->write(&pwm_conf->pwm_ctl[i], 1, PM8921_LPG_CTL(i));
if (rc)
{
dprintf(CRITICAL, "pm8921_write() failed in \
pwm_configure %d\n", rc);
break;
}
}
bail_out:
if (rc)
dprintf(CRITICAL, "Error in pm8921_pwm_configure()\n");
return rc;
}
/* Top level function for configuring PWM
* Always called from the main pm8921.c file
*/
int pm8921_pwm_config(uint8_t pwm_id,
uint32_t duty_us,
uint32_t period_us,
pm8921_dev_t *dev)
{
struct pm8921_pwm_config pwm_conf;
uint32_t max_pwm_value, tmp;
int rc = -1;
if ((duty_us > period_us) || (period_us > PM_PWM_PERIOD_MAX) ||
(period_us < PM_PWM_PERIOD_MIN))
{
dprintf(CRITICAL, "Error in duty cycle and period\n");
return -1;
}
pm8921_pwm_calc_period(period_us, &pwm_conf);
/* Figure out pwm_value with overflow handling */
if (period_us > (1 << pwm_conf.pwm_size))
{
tmp = period_us;
tmp >>= pwm_conf.pwm_size;
pwm_conf.pwm_value = duty_us / tmp;
}
else
{
tmp = duty_us;
tmp <<= pwm_conf.pwm_size;
pwm_conf.pwm_value = tmp / period_us;
}
max_pwm_value = (1 << pwm_conf.pwm_size) - 1;
if (pwm_conf.pwm_value > max_pwm_value)
pwm_conf.pwm_value = max_pwm_value;
/* Bypassing LUT */
pwm_conf.bypass_lut = 1;
dprintf(SPEW, "duty/period=%u/%u usec: pwm_value=%d (of %d)\n",
duty_us, period_us, pwm_conf.pwm_value,
1 << pwm_conf.pwm_size);
rc = pm8921_pwm_configure(pwm_id, &pwm_conf, dev);
if (rc)
dprintf(CRITICAL, "Error in pwm_config()\n");
return rc;
}
/* Top level function to enable PWM with specified id
* Always called from the main pm8921.c file
*/
int pm8921_pwm_enable(uint8_t pwm_id, pm8921_dev_t *dev)
{
int rc = -1;
uint8_t reg;
/* Read it before enabling other bank */
rc = dev->read(&reg, 1, PM8921_LPG_BANK_ENABLE);
if (rc)
goto bail_out;
reg |= (1 << pwm_id);
rc = dev->write(&reg, 1, PM8921_LPG_BANK_ENABLE);
if (rc)
goto bail_out;
/* Selecting the bank */
rc = dev->write(&pwm_id, 1, PM8921_LPG_BANK_SEL);
if (rc)
goto bail_out;
/* Read it before setting PWM start */
rc = dev->read(&reg, 1, PM8921_LPG_CTL(0));
if (rc)
goto bail_out;
reg |= PM_PWM_PWM_START;
reg &= ~PM_PWM_RAMP_GEN_START;
rc = dev->write(&reg, 1, PM8921_LPG_CTL(0));
bail_out:
if (rc)
dprintf(CRITICAL, "Error in pwm_enable()\n");
return rc;
}
@@ -0,0 +1,8 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
INCLUDES += -I$(LOCAL_DIR)/include
OBJS += \
$(LOCAL_DIR)/pm8921.o \
$(LOCAL_DIR)/pm8921_pwm.o \
@@ -0,0 +1,107 @@
/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _PM8x41_H_
#define _PM8x41_H_
#include <sys/types.h>
#define PM_GPIO_DIR_OUT 0x01
#define PM_GPIO_DIR_IN 0x00
#define PM_GPIO_DIR_BOTH 0x02
#define PM_GPIO_PULL_UP_30 0
#define PM_GPIO_PULL_UP_1_5 1
#define PM_GPIO_PULL_UP_31_5 2
/* 1.5uA + 30uA boost */
#define PM_GPIO_PULL_UP_1_5_30 3
#define PM_GPIO_PULL_RESV_1 4
#define PM_GPIO_PULL_RESV_2 5
#define PM_GPIO_OUT_CMOS 0x00
#define PM_GPIO_OUT_DRAIN_NMOS 0x01
#define PM_GPIO_OUT_DRAIN_PMOS 0x02
#define PM_GPIO_OUT_DRIVE_LOW 0x01
#define PM_GPIO_OUT_DRIVE_MED 0x02
#define PM_GPIO_OUT_DRIVE_HIGH 0x03
#define PM_GPIO_FUNC_LOW 0x00
#define PM_GPIO_FUNC_HIGH 0x01
#define PM_GPIO_MODE_MASK 0x70
#define PM_GPIO_OUTPUT_MASK 0x0F
#define PON_PSHOLD_WARM_RESET 0x1
#define PON_PSHOLD_SHUTDOWN 0x4
#define PMIC_VERSION_V2 1
/*Target power on reasons*/
#define DC_CHG 8
#define USB_CHG 16
#define PON1 32
#define CBLPWR_N 64
#define KPDPWR_N 128
struct pm8x41_gpio {
int direction;
int output_buffer;
int output_value;
int pull;
int vin_sel;
int out_strength;
int function;
int inv_int_pol;
int disable_pin;
};
int pm8x41_gpio_get(uint8_t gpio, uint8_t *status);
int pm8x41_gpio_set(uint8_t gpio, uint8_t value);
int pm8x41_gpio_config(uint8_t gpio, struct pm8x41_gpio *config);
void pm8x41_set_boot_done();
uint32_t pm8x41_resin_status();
uint32_t pm8x41_resin_bark_workaround_status();
void pm8x41_reset_configure(uint8_t);
void pm8x41_v2_reset_configure(uint8_t);
int pm8x41_ldo_set_voltage(const char *, uint32_t);
int pm8x41_ldo_control(const char *, uint8_t);
uint8_t pm8x41_get_pmic_rev();
uint8_t pm8x41_get_pon_reason();
struct pm8x41_ldo {
const char *name;
uint8_t type;
uint32_t base;
uint32_t range_reg;
uint32_t step_reg;
uint32_t enable_reg;
};
#endif
@@ -0,0 +1,170 @@
/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _PM8X41_ADC_H_
#define _PM8X41_ADC_H_
#include <bits.h>
#include <stdint.h>
struct adc_conf {
uint32_t base;
uint8_t mode;
uint16_t chan;
uint8_t adc_param;
uint8_t hw_set_time;
uint8_t fast_avg;
uint8_t calib_type;
};
#define CHAN_INIT(_base, _chan, _mode, _adc_param, _hw_set_time, _fast_avg, _calib_type) \
{\
.base = _base, \
.chan = _chan, \
.mode = _mode, \
.adc_param = _adc_param, \
.hw_set_time = _hw_set_time, \
.fast_avg = _fast_avg, \
.calib_type = _calib_type, \
}
/* ADC1 Apps base */
#define VADC_USR1_BASE 0x3100
/* ADC mode control */
#define VADC_MODE_CTRL 0x40
#define VADC_MODE_NORMAL 0x0
#define VADC_MODE_BIT_NORMAL 3
/* ADC channel control */
#define VADC_CHAN_SEL 0x48
/* ADC dig param setup */
#define VADC_DIG_ADC_PARAM 0x50
#define VADC_DECIM_RATIO_VAL 0x1
#define VADC_DECIM_RATIO_SEL 2
#define VADC_CLK_SEL 1
/* ADC HE settle time */
#define VADC_HW_SETTLE_TIME 0x51
#define VADC_HW_SET_TIME_SEL 7
#define HW_SET_DELAY_100US 0x1
/* Request VADC conversion */
#define VADC_CONV_REQ 0x52
#define VADC_CON_REQ_BIT BIT(7)
/* ADC fast avg setup */
#define VADC_FAST_AVG 0x5A
#define VADC_FAST_AVG_EN 0x5B
#define FAST_AVG_SAMP_1 0x0
/* VADC status */
#define VADC_STATUS 0x08
#define VADC_STATUS_EOC 0x1
#define VADC_STATUS_MASK 0x3
/* VADC Enable */
#define VADC_EN_CTL 0x46
#define VADC_CTL_EN_BIT BIT(7)
/* VADC result */
#define VADC_REG_DATA_MSB 0x61
#define VADC_REG_DATA_LSB 0x60
/* Channel IDs */
#define VADC_BAT_VOL_CHAN_ID 6
#define VREF_625_CHAN_ID 9
#define VREF_125_CHAN_ID 10
#define GND_REF_CHAN_ID 14
#define VDD_VADC_CHAN_ID 15
#define VADC_BAT_CHAN_ID 49
/* Calibration type */
#define CALIB_ABS 0
#define CALIB_RATIO 1
/* VADC result range */
#define VADC_MIN_VAL 0x6000
#define VADC_MAX_VAL 0xA800
/* Data points needed for calibration */
/* Absolute calibration */
#define VREF_625_MV 625000
#define OFFSET_GAIN_DNOM 3
#define OFFSET_GAIN_NUME 1
/* Ratiometric calibration */
#define VREF_18_V 1800000
/* Current value for USB & BAT */
#define USB_CUR_100UA 100000
#define USB_CUR_150UA 150000
#define IUSB_MAX_REG 0x1344
#define BAT_CUR_100UA 100000
#define BAT_CUR_STEP 50000
#define IBAT_MAX_REG 0x1044
#define IUSB_MIN_UA 100000
#define IBAT_MIN_UA 100000
#define IBAT_MAX_UA 3250000
#define IUSB_MAX_UA 2500000
/* Macros for setting VDD max & charge control */
#define CHGR_VDD_MAX 0x1040
#define VDD_MIN_UA 3240000
#define VDD_MAX_UA 5790000
#define VDD_VOL_STEP 10000
/* Macros for charge control */
#define CHGR_CHG_CTRL 0x1049
#define CHGR_ENABLE 1
#define CHGR_EN_BIT 7
#define CHGR_DISABLE 0x0
/* Macros for boot done */
#define MISC_BOOT_DONE 0x1642
#define BOOT_DONE 1
#define BOOT_DONE_BIT 7
/* Function declations */
uint32_t pm8x41_adc_channel_read(uint16_t ch_num);
int pm8x41_iusb_max_config(uint32_t current);
int pm8x41_ibat_max_config(uint32_t current);
/* API: To set VDD max */
int pm8x41_chgr_vdd_max_config(uint32_t voltage);
/* API: To enable charging */
int pm8x41_chgr_ctl_enable(uint8_t enable);
/* API: Get battery voltage*/
uint32_t pm8x41_get_batt_voltage();
/* API: Get Voltage based State of Charge */
uint32_t pm8x41_get_voltage_based_soc(uint32_t cutoff_vol, uint32_t vdd_max);
#endif /* _PM8X41_ADC_H_ */
@@ -0,0 +1,133 @@
/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _PM8x41_HW_H_
#define _PM8x41_HW_H_
/* SMBB Registers */
#define SMBB_MISC_BOOT_DONE 0x1642
/* SMBB bit values */
#define BOOT_DONE_BIT 7
#define REVID_REVISION4 0x103
/* GPIO Registers */
#define GPIO_PERIPHERAL_BASE 0xC000
/* Peripheral base address for GPIO_X */
#define GPIO_N_PERIPHERAL_BASE(x) (GPIO_PERIPHERAL_BASE + ((x) - 1) * 0x100)
/* Register offsets within GPIO */
#define GPIO_STATUS 0x08
#define GPIO_MODE_CTL 0x40
#define GPIO_DIG_VIN_CTL 0x41
#define GPIO_DIG_PULL_CTL 0x42
#define GPIO_DIG_OUT_CTL 0x45
#define GPIO_EN_CTL 0x46
/* GPIO bit values */
#define PERPH_EN_BIT 7
#define GPIO_STATUS_VAL_BIT 0
/* PON Peripheral registers */
#define PON_PON_REASON1 0x808
#define PON_INT_RT_STS 0x810
#define PON_INT_SET_TYPE 0x811
#define PON_INT_POLARITY_HIGH 0x812
#define PON_INT_POLARITY_LOW 0x813
#define PON_INT_LATCHED_CLR 0x814
#define PON_INT_EN_SET 0x815
#define PON_INT_LATCHED_STS 0x818
#define PON_INT_PENDING_STS 0x819
#define PON_RESIN_N_RESET_S1_TIMER 0x844 /* bits 0:3 : S1_TIMER */
#define PON_RESIN_N_RESET_S2_TIMER 0x845 /* bits 0:2 : S2_TIMER */
#define PON_RESIN_N_RESET_S2_CTL 0x846 /* bit 7: S2_RESET_EN, bit 0:3 : RESET_TYPE */
#define PON_PS_HOLD_RESET_CTL 0x85A /* bit 7: S2_RESET_EN, bit 0:3 : RESET_TYPE */
#define PON_PS_HOLD_RESET_CTL2 0x85B
/* PON Peripheral register bit values */
#define RESIN_ON_INT_BIT 1
#define RESIN_BARK_INT_BIT 4
#define S2_RESET_EN_BIT 7
#define S2_RESET_TYPE_WARM 0x1
#define PON_RESIN_N_RESET_S2_TIMER_MAX_VALUE 0x7
void pm8x41_reg_write(uint32_t addr, uint8_t val);
uint8_t pm8x41_reg_read(uint32_t addr);
/* SPMI Macros */
#define REG_READ(_a) pm8x41_reg_read(_a)
#define REG_WRITE(_a, _v) pm8x41_reg_write(_a, _v)
#define REG_OFFSET(_addr) ((_addr) & 0xFF)
#define PERIPH_ID(_addr) (((_addr) & 0xFF00) >> 8)
#define SLAVE_ID(_addr) ((_addr) >> 16)
/* LDO voltage ranges */
#define NLDO_UV_MIN 375000
#define NLDO_UV_MAX 1537500
#define NLDO_UV_STEP 12500
#define NLDO_UV_VMIN_LOW 750000
#define PLDO_UV_VMIN_LOW 750000
#define PLDO_UV_VMIN_MID 1500000
#define PLDO_UV_VMIN_HIGH 1750000
#define PLDO_UV_MIN 1537500
#define PDLO_UV_MID 3075000
#define PLDO_UV_MAX 4900000
#define PLDO_UV_STEP_LOW 12500
#define PLDO_UV_STEP_MID 25000
#define PLDO_UV_STEP_HIGH 50000
#define LDO_RANGE_SEL_BIT 0
#define LDO_VSET_SEL_BIT 0
#define LDO_VREG_ENABLE_BIT 7
#define LDO_NORMAL_PWR_BIT 7
#define LDO_RANGE_CTRL 0x40
#define LDO_STEP_CTRL 0x41
#define LDO_POWER_MODE 0x45
#define LDO_EN_CTL_REG 0x46
#define PLDO_TYPE 0
#define NLDO_TYPE 1
#define LDO(_name, _type, _base, _range, _step, _enable) \
{ \
.name = _name, \
.type = _type, \
.base = _base, \
.range_reg = _range, \
.step_reg = _step, \
.enable_reg = _enable, \
}
#endif
@@ -0,0 +1,69 @@
/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <bits.h>
#include <debug.h>
#include <reg.h>
#define PM_WLED_BASE 0x1D800
#define PM_WLED_CTNL_REG(n) (PM_WLED_BASE + n)
#define PM_WLED_LED1_BRIGHTNESS_LSB PM_WLED_CTNL_REG(0x40)
#define PM_WLED_LED1_BRIGHTNESS_MSB PM_WLED_CTNL_REG(0x41)
#define PM_WLED_LED2_BRIGHTNESS_LSB PM_WLED_CTNL_REG(0x42)
#define PM_WLED_LED2_BRIGHTNESS_MSB PM_WLED_CTNL_REG(0x43)
#define PM_WLED_LED3_BRIGHTNESS_LSB PM_WLED_CTNL_REG(0x44)
#define PM_WLED_LED3_BRIGHTNESS_MSB PM_WLED_CTNL_REG(0x45)
#define PM_WLED_ENABLE PM_WLED_CTNL_REG(0x46)
#define PM_WLED_ILED_SYNC_BIT PM_WLED_CTNL_REG(0x47)
#define PM_WLED_MODULATION_SCHEME PM_WLED_CTNL_REG(0x4A)
#define PM_WLED_MAX_DUTY_CYCLE PM_WLED_CTNL_REG(0x4B)
#define PM_WLED_CURRENT_SINK PM_WLED_CTNL_REG(0x4F)
#define PM_WLED_LED1_SINK_MASK BIT(7)
#define PM_WLED_LED2_SINK_MASK BIT(6)
#define PM_WLED_LED3_SINK_MASK BIT(5)
#define PM_WLED_LED1_ILED_SYNC_MASK BIT(2)
#define PM_WLED_LED2_ILED_SYNC_MASK BIT(1)
#define PM_WLED_LED3_ILED_SYNC_MASK BIT(0)
#define PM_WLED_ENABLE_MODULE_MASK BIT(7)
struct pm8x41_wled_data{
uint8_t mod_scheme;
uint16_t led1_brightness;
uint16_t led2_brightness;
uint16_t led3_brightness;
uint8_t max_duty_cycle;
};
void pm8x41_wled_config(struct pm8x41_wled_data *wled_ctrl);
void pm8x41_wled_iled_sync_control(uint8_t enable);
void pm8x41_wled_sink_control(uint8_t enable);
void pm8x41_wled_enable(uint8_t enable);
@@ -0,0 +1,371 @@
/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <bits.h>
#include <debug.h>
#include <reg.h>
#include <spmi.h>
#include <string.h>
#include <pm8x41_hw.h>
#include <pm8x41.h>
#include <platform/timer.h>
struct pm8x41_ldo ldo_data[] = {
LDO("LDO2", NLDO_TYPE, 0x14100, LDO_RANGE_CTRL, LDO_STEP_CTRL, LDO_EN_CTL_REG),
LDO("LDO12", PLDO_TYPE, 0x14B00, LDO_RANGE_CTRL, LDO_STEP_CTRL, LDO_EN_CTL_REG),
LDO("LDO22", PLDO_TYPE, 0x15500, LDO_RANGE_CTRL, LDO_STEP_CTRL, LDO_EN_CTL_REG),
};
/* SPMI helper functions */
uint8_t pm8x41_reg_read(uint32_t addr)
{
uint8_t val = 0;
struct pmic_arb_cmd cmd;
struct pmic_arb_param param;
cmd.address = PERIPH_ID(addr);
cmd.offset = REG_OFFSET(addr);
cmd.slave_id = SLAVE_ID(addr);
cmd.priority = 0;
param.buffer = &val;
param.size = 1;
pmic_arb_read_cmd(&cmd, &param);
return val;
}
void pm8x41_reg_write(uint32_t addr, uint8_t val)
{
struct pmic_arb_cmd cmd;
struct pmic_arb_param param;
cmd.address = PERIPH_ID(addr);
cmd.offset = REG_OFFSET(addr);
cmd.slave_id = SLAVE_ID(addr);
cmd.priority = 0;
param.buffer = &val;
param.size = 1;
pmic_arb_write_cmd(&cmd, &param);
}
/* Exported functions */
/* Set the boot done flag */
void pm8x41_set_boot_done()
{
uint8_t val;
val = REG_READ(SMBB_MISC_BOOT_DONE);
val |= BIT(BOOT_DONE_BIT);
REG_WRITE(SMBB_MISC_BOOT_DONE, val);
}
/* Configure GPIO */
int pm8x41_gpio_config(uint8_t gpio, struct pm8x41_gpio *config)
{
uint8_t val;
uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
/* Disable the GPIO */
val = REG_READ(gpio_base + GPIO_EN_CTL);
val &= ~BIT(PERPH_EN_BIT);
REG_WRITE(gpio_base + GPIO_EN_CTL, val);
/* Select the mode */
val = config->function | (config->direction << 4);
REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
/* Set the right pull */
val = config->pull;
REG_WRITE(gpio_base + GPIO_DIG_PULL_CTL, val);
/* Select the VIN */
val = config->vin_sel;
REG_WRITE(gpio_base + GPIO_DIG_VIN_CTL, val);
if (config->direction == PM_GPIO_DIR_OUT) {
/* Set the right dig out control */
val = config->out_strength | (config->output_buffer << 4);
REG_WRITE(gpio_base + GPIO_DIG_OUT_CTL, val);
}
/* Enable the GPIO */
val = REG_READ(gpio_base + GPIO_EN_CTL);
val |= BIT(PERPH_EN_BIT);
REG_WRITE(gpio_base + GPIO_EN_CTL, val);
return 0;
}
/* Reads the status of requested gpio */
int pm8x41_gpio_get(uint8_t gpio, uint8_t *status)
{
uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
*status = REG_READ(gpio_base + GPIO_STATUS);
/* Return the value of the GPIO pin */
*status &= BIT(GPIO_STATUS_VAL_BIT);
dprintf(SPEW, "GPIO %d status is %d\n", gpio, *status);
return 0;
}
/* Write the output value of the requested gpio */
int pm8x41_gpio_set(uint8_t gpio, uint8_t value)
{
uint32_t gpio_base = GPIO_N_PERIPHERAL_BASE(gpio);
uint8_t val;
/* Set the output value of the gpio */
val = REG_READ(gpio_base + GPIO_MODE_CTL);
val = (val & ~PM_GPIO_OUTPUT_MASK) | value;
REG_WRITE(gpio_base + GPIO_MODE_CTL, val);
return 0;
}
/* Prepare PON RESIN S2 reset (bite) */
void pm8x41_resin_s2_reset_enable()
{
uint8_t val;
/* disable s2 reset */
REG_WRITE(PON_RESIN_N_RESET_S2_CTL, 0x0);
/* Delay needed for disable to kick in. */
udelay(300);
/* configure s1 timer to 0 */
REG_WRITE(PON_RESIN_N_RESET_S1_TIMER, 0x0);
/* configure s2 timer to 2s */
REG_WRITE(PON_RESIN_N_RESET_S2_TIMER, PON_RESIN_N_RESET_S2_TIMER_MAX_VALUE);
/* configure reset type */
REG_WRITE(PON_RESIN_N_RESET_S2_CTL, S2_RESET_TYPE_WARM);
val = REG_READ(PON_RESIN_N_RESET_S2_CTL);
/* enable s2 reset */
val |= BIT(S2_RESET_EN_BIT);
REG_WRITE(PON_RESIN_N_RESET_S2_CTL, val);
}
/* Disable PON RESIN S2 reset. (bite)*/
void pm8x41_resin_s2_reset_disable()
{
/* disable s2 reset */
REG_WRITE(PON_RESIN_N_RESET_S2_CTL, 0x0);
/* Delay needed for disable to kick in. */
udelay(300);
}
/* Resin irq status for faulty pmic*/
uint32_t pm8x41_resin_bark_workaround_status()
{
uint8_t rt_sts = 0;
/* Enable S2 reset so we can detect the volume down key press */
pm8x41_resin_s2_reset_enable();
/* Delay before interrupt triggering.
* See PON_DEBOUNCE_CTL reg.
*/
mdelay(100);
rt_sts = REG_READ(PON_INT_RT_STS);
/* Must disable S2 reset otherwise PMIC will reset if key
* is held longer than S2 timer.
*/
pm8x41_resin_s2_reset_disable();
return (rt_sts & BIT(RESIN_BARK_INT_BIT));
}
/* Resin pin status */
uint32_t pm8x41_resin_status()
{
uint8_t rt_sts = 0;
rt_sts = REG_READ(PON_INT_RT_STS);
return (rt_sts & BIT(RESIN_ON_INT_BIT));
}
void pm8x41_v2_reset_configure(uint8_t reset_type)
{
uint8_t val;
/* disable PS_HOLD_RESET */
REG_WRITE(PON_PS_HOLD_RESET_CTL, 0x0);
/* Delay needed for disable to kick in. */
udelay(300);
/* configure reset type */
REG_WRITE(PON_PS_HOLD_RESET_CTL, reset_type);
val = REG_READ(PON_PS_HOLD_RESET_CTL);
/* enable PS_HOLD_RESET */
val |= BIT(S2_RESET_EN_BIT);
REG_WRITE(PON_PS_HOLD_RESET_CTL, val);
}
void pm8x41_reset_configure(uint8_t reset_type)
{
/* disable PS_HOLD_RESET */
REG_WRITE(PON_PS_HOLD_RESET_CTL2, 0x0);
/* Delay needed for disable to kick in. */
udelay(300);
/* configure reset type */
REG_WRITE(PON_PS_HOLD_RESET_CTL, reset_type);
/* enable PS_HOLD_RESET */
REG_WRITE(PON_PS_HOLD_RESET_CTL2, BIT(S2_RESET_EN_BIT));
}
static struct pm8x41_ldo *ldo_get(const char *ldo_name)
{
uint8_t i;
struct pm8x41_ldo *ldo = NULL;
for (i = 0; i < ARRAY_SIZE(ldo_data); i++) {
ldo = &ldo_data[i];
if (!strncmp(ldo->name, ldo_name, strlen(ldo_name)))
break;
}
return ldo;
}
/*
* LDO set voltage, takes ldo name & voltage in UV as input
*/
int pm8x41_ldo_set_voltage(const char *name, uint32_t voltage)
{
uint32_t range = 0;
uint32_t step = 0;
uint32_t mult = 0;
uint32_t val = 0;
uint32_t vmin = 0;
struct pm8x41_ldo *ldo;
ldo = ldo_get(name);
if (!ldo) {
dprintf(CRITICAL, "LDO requsted is not supported: %s\n", name);
return 1;
}
/* Program Normal power mode */
val = 0x0;
val = (1 << LDO_NORMAL_PWR_BIT);
REG_WRITE((ldo->base + LDO_POWER_MODE), val);
/*
* Select range, step & vmin based on input voltage & type of LDO
* LDO can operate in low, mid, high power mode
*/
if (ldo->type == PLDO_TYPE) {
if (voltage < PLDO_UV_MIN) {
range = 2;
step = PLDO_UV_STEP_LOW;
vmin = PLDO_UV_VMIN_LOW;
} else if (voltage < PDLO_UV_MID) {
range = 3;
step = PLDO_UV_STEP_MID;
vmin = PLDO_UV_VMIN_MID;
} else {
range = 4;
step = PLDO_UV_STEP_HIGH;
vmin = PLDO_UV_VMIN_HIGH;
}
} else {
range = 2;
step = NLDO_UV_STEP;
vmin = NLDO_UV_VMIN_LOW;
}
mult = (voltage - vmin) / step;
/* Set Range in voltage ctrl register */
val = 0x0;
val = range << LDO_RANGE_SEL_BIT;
REG_WRITE((ldo->base + ldo->range_reg), val);
/* Set multiplier in voltage ctrl register */
val = 0x0;
val = mult << LDO_VSET_SEL_BIT;
REG_WRITE((ldo->base + ldo->step_reg), val);
return 0;
}
/*
* Enable or Disable LDO
*/
int pm8x41_ldo_control(const char *name, uint8_t enable)
{
uint32_t val = 0;
struct pm8x41_ldo *ldo;
ldo = ldo_get(name);
if (!ldo) {
dprintf(CRITICAL, "Requested LDO is not supported : %s\n", name);
return 1;
}
/* Enable LDO */
if (enable)
val = (1 << LDO_VREG_ENABLE_BIT);
else
val = (0 << LDO_VREG_ENABLE_BIT);
REG_WRITE((ldo->base + ldo->enable_reg), val);
return 0;
}
uint8_t pm8x41_get_pmic_rev()
{
return REG_READ(REVID_REVISION4);
}
uint8_t pm8x41_get_pon_reason()
{
return REG_READ(PON_PON_REASON1);
}
@@ -0,0 +1,385 @@
/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <bits.h>
#include <debug.h>
#include <reg.h>
#include <spmi.h>
#include <platform/timer.h>
#include <pm8x41_adc.h>
#include <pm8x41_hw.h>
/*
* This is the predefined adc configuration values for the supported
* channels
*/
static struct adc_conf adc_data[] = {
CHAN_INIT(VADC_USR1_BASE, VADC_BAT_CHAN_ID, VADC_MODE_NORMAL, VADC_DECIM_RATIO_VAL, HW_SET_DELAY_100US, FAST_AVG_SAMP_1, CALIB_RATIO),
CHAN_INIT(VADC_USR1_BASE, VADC_BAT_VOL_CHAN_ID, VADC_MODE_NORMAL, VADC_DECIM_RATIO_VAL, HW_SET_DELAY_100US, FAST_AVG_SAMP_1, CALIB_ABS),
};
static struct adc_conf* get_channel_prop(uint16_t ch_num)
{
struct adc_conf *chan_data = NULL;
uint8_t i;
for(i = 0; i < ARRAY_SIZE(adc_data) ; i++) {
chan_data = &adc_data[i];
if (chan_data->chan == ch_num)
break;
}
return chan_data;
}
static void adc_limit_result_range(uint16_t *result)
{
if (*result < VADC_MIN_VAL)
*result = VADC_MIN_VAL;
else if(*result > VADC_MAX_VAL)
*result = VADC_MAX_VAL;
}
static void adc_read_conv_result(struct adc_conf *adc, uint16_t *result)
{
uint8_t val = 0;
/* Read the MSB part */
val = REG_READ(adc->base + VADC_REG_DATA_MSB);
*result = val;
/* Read the LSB part */
val = REG_READ(adc->base + VADC_REG_DATA_LSB);
*result = ((*result) << 8) | val;
adc_limit_result_range(result);
}
static void adc_enable(struct adc_conf *adc, uint8_t enable)
{
if (enable)
REG_WRITE((adc->base + VADC_EN_CTL), VADC_CTL_EN_BIT);
else
REG_WRITE((adc->base + VADC_EN_CTL), (uint8_t) (~VADC_CTL_EN_BIT));
}
static void adc_measure(struct adc_conf *adc, uint16_t *result)
{
uint8_t status;
/* Request conversion */
REG_WRITE((adc->base + VADC_CONV_REQ), VADC_CON_REQ_BIT);
/* Poll for the conversion to complete */
do {
status = REG_READ(adc->base + VADC_STATUS);
status &= VADC_STATUS_MASK;
if (status == VADC_STATUS_EOC) {
dprintf(SPEW, "ADC conversion is complete\n");
break;
}
/* Wait for sometime before polling for the status again */
udelay(10);
} while(1);
/* Now read the conversion result */
adc_read_conv_result(adc, result);
}
/*
* This function configures adc & requests for conversion
*/
static uint16_t adc_configure(struct adc_conf *adc)
{
uint8_t mode;
uint8_t adc_p;
uint16_t result;
/* Mode Selection */
mode = (adc->mode << VADC_MODE_BIT_NORMAL);
REG_WRITE((adc->base + VADC_MODE_CTRL), mode);
/* Select Channel */
REG_WRITE((adc->base + VADC_CHAN_SEL), adc->chan);
/* ADC digital param setup */
adc_p = (adc->adc_param << VADC_DECIM_RATIO_SEL);
REG_WRITE((adc->base + VADC_DIG_ADC_PARAM), adc_p);
/* hardware settling time */
REG_WRITE((adc->base + VADC_HW_SETTLE_TIME), adc->hw_set_time);
/* For normal mode set the fast avg */
REG_WRITE((adc->base + VADC_FAST_AVG), adc->fast_avg);
/* Enable Vadc */
adc_enable(adc, true);
/* Measure the result */
adc_measure(adc, &result);
/* Disable vadc */
adc_enable(adc, false);
return result;
}
static uint32_t vadc_calibrate(uint16_t result, uint8_t calib_type)
{
struct adc_conf calib;
uint16_t calib1;
uint16_t calib2;
uint32_t calib_result = 0;
uint32_t mul;
if(calib_type == CALIB_ABS) {
/*
* Measure the calib data for 1.25 V ref
*/
calib.base = VADC_USR1_BASE;
calib.chan = VREF_125_CHAN_ID;
calib.mode = VADC_MODE_NORMAL;
calib.adc_param = VADC_DECIM_RATIO_VAL;
calib.hw_set_time = 0x0;
calib.fast_avg = 0x0;
calib1 = adc_configure(&calib);
/*
* Measure the calib data for 0.625 V ref
*/
calib.base = VADC_USR1_BASE;
calib.chan = VREF_625_CHAN_ID;
calib.mode = VADC_MODE_NORMAL;
calib.adc_param = VADC_DECIM_RATIO_VAL;
calib.hw_set_time = 0x0;
calib.fast_avg = 0x0;
calib2 = adc_configure(&calib);
mul = VREF_625_MV / (calib1 - calib2);
calib_result = (result - calib2) * mul;
calib_result += VREF_625_MV;
calib_result *= OFFSET_GAIN_DNOM;
calib_result /= OFFSET_GAIN_NUME;
} else if(calib_type == CALIB_RATIO) {
/*
* Measure the calib data for VDD_ADC ref
*/
calib.base = VADC_USR1_BASE;
calib.chan = VDD_VADC_CHAN_ID;
calib.mode = VADC_MODE_NORMAL;
calib.adc_param = VADC_DECIM_RATIO_VAL;
calib.hw_set_time = 0;
calib.fast_avg = 0;
calib1 = adc_configure(&calib);
/*
* Measure the calib data for ADC_GND
*/
calib.base = VADC_USR1_BASE;
calib.chan = GND_REF_CHAN_ID;
calib.mode = VADC_MODE_NORMAL;
calib.adc_param = VADC_DECIM_RATIO_VAL;
calib.hw_set_time = 0;
calib.fast_avg = 0;
calib2 = adc_configure(&calib);
mul = VREF_18_V / (calib1 - calib2);
calib_result = (result - calib2) * mul;
}
return calib_result;
}
/*
* This API takes channel number as input
* & returns the calibrated voltage as output
* The calibrated result is the voltage in uVs
*/
uint32_t pm8x41_adc_channel_read(uint16_t ch_num)
{
struct adc_conf *adc;
uint16_t result;
uint32_t calib_result;
adc = get_channel_prop(ch_num);
if (!adc) {
dprintf(CRITICAL, "Error: requested channel is not supported: %u\n", ch_num);
return 0;
}
result = adc_configure(adc);
calib_result = vadc_calibrate(result, adc->calib_type);
dprintf(SPEW, "Result: Raw %u\tCalibrated:%llu\n", result, calib_result);
return calib_result;
}
/*
* This function configures the maximum
* current for USB in uA
*/
int pm8x41_iusb_max_config(uint32_t current)
{
uint32_t mul;
if(current < IUSB_MIN_UA || current > IUSB_MAX_UA) {
dprintf(CRITICAL, "Error: Current value for USB are not in permissible range\n");
return -1;
}
if (current == USB_CUR_100UA)
mul = 0x0;
else if (current == USB_CUR_150UA)
mul = 0x1;
else
mul = current / USB_CUR_100UA;
REG_WRITE(IUSB_MAX_REG, mul);
return 0;
}
/*
* This function configures the maximum
* current for battery in uA
*/
int pm8x41_ibat_max_config(uint32_t current)
{
uint32_t mul;
if(current < IBAT_MIN_UA || current > IBAT_MAX_UA) {
dprintf(CRITICAL, "Error: Current value for BAT are not in permissible range\n");
return -1;
}
mul = (current - BAT_CUR_100UA) / BAT_CUR_STEP;
REG_WRITE(IBAT_MAX_REG, mul);
return 0;
}
/*
* API: pm8x41_chgr_vdd_max_config
* Configure the VDD max to i/p value
*/
int pm8x41_chgr_vdd_max_config(uint32_t vol)
{
uint8_t mul;
/* Check for permissible range of i/p */
if (vol < VDD_MIN_UA || vol > VDD_MAX_UA)
{
dprintf(CRITICAL, "Error: Voltage values are not in permissible range\n");
return -1;
}
/* Calculate the multiplier */
mul = (vol - VDD_MIN_UA) / VDD_VOL_STEP;
/* Write to VDD_MAX register */
REG_WRITE(CHGR_VDD_MAX, mul);
return 0;
}
/*
* API: pm8x41_chgr_ctl_enable
* Enable FSM-controlled autonomous charging
*/
int pm8x41_chgr_ctl_enable(uint8_t enable)
{
/* If charging has to be enabled?
* 1. Enable charging in charge control
* 2. Enable boot done to enable charging
*/
if (enable)
{
REG_WRITE(CHGR_CHG_CTRL, (CHGR_ENABLE << CHGR_EN_BIT));
REG_WRITE(MISC_BOOT_DONE, (BOOT_DONE << BOOT_DONE_BIT));
}
else
REG_WRITE(CHGR_CHG_CTRL, CHGR_DISABLE);
return 0;
}
/*
* API: pm8x41_get_batt_voltage
* Get calibrated battery voltage from VADC, in UV
*/
uint32_t pm8x41_get_batt_voltage()
{
uint32_t voltage;
voltage = pm8x41_adc_channel_read(VADC_BAT_VOL_CHAN_ID);
if(!voltage)
{
dprintf(CRITICAL, "Error getting battery Voltage\n");
return 0;
}
return voltage;
}
/*
* API: pm8x41_get_voltage_based_soc
* Get voltage based State Of Charge, this takes vdd max & battery cutoff
* voltage as i/p in uV
*/
uint32_t pm8x41_get_voltage_based_soc(uint32_t cutoff_vol, uint32_t vdd_max)
{
uint32_t vol_soc;
uint32_t batt_vol;
batt_vol = pm8x41_get_batt_voltage();
if(!batt_vol)
{
dprintf(CRITICAL, "Error: Getting battery voltage based Soc\n");
return 0;
}
if (cutoff_vol >= vdd_max)
{
dprintf(CRITICAL, "Cutoff is greater than VDD max, Voltage based soc can't be calculated\n");
return 0;
}
vol_soc = ((batt_vol - cutoff_vol) * 100) / (vdd_max - cutoff_vol);
return vol_soc;
}
@@ -0,0 +1,99 @@
/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <bits.h>
#include <reg.h>
#include <pm8x41_hw.h>
#include <pm8x41_wled.h>
void pm8x41_wled_config(struct pm8x41_wled_data *wled_ctrl) {
if (!wled_ctrl) {
dprintf(CRITICAL, "Error: Invalid WLED data.\n");
return;
}
REG_WRITE(PM_WLED_MODULATION_SCHEME, wled_ctrl->mod_scheme);
REG_WRITE(PM_WLED_LED1_BRIGHTNESS_LSB, (wled_ctrl->led1_brightness & 0xFF));
REG_WRITE(PM_WLED_LED1_BRIGHTNESS_MSB, ((wled_ctrl->led1_brightness >> 8) & 0xFF));
REG_WRITE(PM_WLED_LED2_BRIGHTNESS_LSB, (wled_ctrl->led2_brightness & 0xFF));
REG_WRITE(PM_WLED_LED2_BRIGHTNESS_MSB, ((wled_ctrl->led2_brightness >> 8) & 0xFF));
REG_WRITE(PM_WLED_LED3_BRIGHTNESS_LSB, (wled_ctrl->led3_brightness & 0xFF));
REG_WRITE(PM_WLED_LED3_BRIGHTNESS_MSB, ((wled_ctrl->led3_brightness >> 8) & 0xFF));
REG_WRITE(PM_WLED_MAX_DUTY_CYCLE, wled_ctrl->max_duty_cycle);
dprintf(SPEW, "WLED Configuration Success.\n");
}
void pm8x41_wled_sink_control(uint8_t enable) {
uint8_t value = 0x0;
if (enable) {
value = PM_WLED_LED1_SINK_MASK |
PM_WLED_LED2_SINK_MASK |
PM_WLED_LED3_SINK_MASK;
}
REG_WRITE(PM_WLED_CURRENT_SINK, value);
dprintf(SPEW, "WLED Sink Success\n");
}
void pm8x41_wled_iled_sync_control(uint8_t enable) {
uint8_t value = 0x0;
if (enable) {
value = PM_WLED_LED1_ILED_SYNC_MASK |
PM_WLED_LED1_ILED_SYNC_MASK |
PM_WLED_LED1_ILED_SYNC_MASK;
}
REG_WRITE(PM_WLED_ILED_SYNC_BIT, value);
dprintf(SPEW, "WLED ILED Sync Success\n");
}
void pm8x41_wled_enable(uint8_t enable) {
uint8_t value = 0x0;
if (enable)
value = PM_WLED_ENABLE_MODULE_MASK;
REG_WRITE(PM_WLED_ENABLE, value);
dprintf(SPEW, "WLED Enable Success\n");
}
@@ -0,0 +1,8 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
INCLUDES += -I$(LOCAL_DIR)/include
OBJS += \
$(LOCAL_DIR)/pm8x41.o \
$(LOCAL_DIR)/pm8x41_adc.o \
$(LOCAL_DIR)/pm8x41_wled.o
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2008 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __DEV_TWL4030_H
#define __DEV_TWL4030_H
#include <sys/types.h>
void twl4030_init(void);
/* USB parts of the pmic */
int twl4030_usb_reset(void);
int twl4030_set_usb_pullup(bool pullup);
int twl4030_init_hs(void);
#endif
@@ -0,0 +1,7 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
INCLUDES += -I$(LOCAL_DIR)/include
OBJS += \
$(LOCAL_DIR)/twl4030.o
@@ -0,0 +1,169 @@
/*
* Copyright (c) 2008 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <debug.h>
#include <sys/types.h>
#include <dev/i2c.h>
#include <dev/twl4030.h>
#include "twl4030_hw.h"
// XXX move to target specific setup
#define TWL_I2C_BUS 0
void twl4030_init(void)
{
}
static int twl4030_usb_write(uint8_t address, uint8_t data)
{
return i2c_write_reg(TWL_I2C_BUS, TWL_USB_ADDR, address, data);
}
static int twl4030_usb_read(uint8_t address)
{
uint8_t data;
int err = i2c_read_reg(TWL_I2C_BUS, TWL_USB_ADDR, address, &data);
if (err < 0)
return err;
return data;
}
static int twl4030_usb_set_bits(uint8_t reg, uint8_t bits)
{
return twl4030_usb_write(reg + 1, bits);
}
static int twl4030_usb_clear_bits(uint8_t reg, uint8_t bits)
{
return twl4030_usb_write(reg + 2, bits);
}
static void twl4030_i2c_access(bool on)
{
int val;
if ((val = twl4030_usb_read(PHY_CLK_CTRL)) >= 0) {
if (on) {
/* enable DPLL to access PHY registers over I2C */
val |= REQ_PHY_DPLL_CLK;
twl4030_usb_write(PHY_CLK_CTRL, (uint8_t)val);
while (!(twl4030_usb_read(PHY_CLK_CTRL_STS) & PHY_DPLL_CLK)) {
spin(10);
}
if (!(twl4030_usb_read(PHY_CLK_CTRL_STS) & PHY_DPLL_CLK))
printf("Timeout setting T2 HSUSB " "PHY DPLL clock\n");
} else {
/* let ULPI control the DPLL clock */
val &= ~REQ_PHY_DPLL_CLK;
twl4030_usb_write(PHY_CLK_CTRL, (uint8_t)val);
}
}
return;
}
int twl4030_usb_reset(void)
{
TRACE_ENTRY;
#if 0
twl4030_usb_clear_bits(OTG_CTRL, DMPULLDOWN | DPPULLDOWN);
twl4030_usb_clear_bits(USB_INT_EN_RISE, ~0);
twl4030_usb_clear_bits(USB_INT_EN_FALL, ~0);
twl4030_usb_clear_bits(MCPC_IO_CTRL, ~TXDTYP);
twl4030_usb_set_bits(MCPC_IO_CTRL, TXDTYP);
twl4030_usb_clear_bits(OTHER_FUNC_CTRL, (BDIS_ACON_EN | FIVEWIRE_MODE));
twl4030_usb_clear_bits(OTHER_IFC_CTRL, ~0);
twl4030_usb_clear_bits(OTHER_INT_EN_RISE, ~0);
twl4030_usb_clear_bits(OTHER_INT_EN_FALL, ~0);
twl4030_usb_clear_bits(OTHER_IFC_CTRL2, ~0);
twl4030_usb_clear_bits(REG_CTRL_EN, ULPI_I2C_CONFLICT_INTEN);
twl4030_usb_clear_bits(OTHER_FUNC_CTRL2, VBAT_TIMER_EN);
#endif
/* Enable writing to power configuration registers */
i2c_write_reg(TWL_I2C_BUS, TWL_PM_RECEIVER_ADDR, PROTECT_KEY, 0xC0);
i2c_write_reg(TWL_I2C_BUS, TWL_PM_RECEIVER_ADDR, PROTECT_KEY, 0x0C);
/* put VUSB3V1 LDO in active state */
i2c_write_reg(TWL_I2C_BUS, TWL_PM_RECEIVER_ADDR, VUSB_DEDICATED2, 0);
/* input to VUSB3V1 LDO is from VBAT, not VBUS */
i2c_write_reg(TWL_I2C_BUS, TWL_PM_RECEIVER_ADDR, VUSB_DEDICATED1, 0x14);
/* turn on 3.1V regulator */
i2c_write_reg(TWL_I2C_BUS, TWL_PM_RECEIVER_ADDR, VUSB3V1_DEV_GRP, 0x20);
i2c_write_reg(TWL_I2C_BUS, TWL_PM_RECEIVER_ADDR, VUSB3V1_TYPE, 0);
/* turn on 1.5V regulator */
i2c_write_reg(TWL_I2C_BUS, TWL_PM_RECEIVER_ADDR, VUSB1V5_DEV_GRP, 0x20);
i2c_write_reg(TWL_I2C_BUS, TWL_PM_RECEIVER_ADDR, VUSB1V5_TYPE, 0);
/* turn on 1.8V regulator */
i2c_write_reg(TWL_I2C_BUS, TWL_PM_RECEIVER_ADDR, VUSB1V8_DEV_GRP, 0x20);
i2c_write_reg(TWL_I2C_BUS, TWL_PM_RECEIVER_ADDR, VUSB1V8_TYPE, 0);
/* disable access to power configuration registers */
i2c_write_reg(TWL_I2C_BUS, TWL_PM_RECEIVER_ADDR, PROTECT_KEY, 0);
/* turn on the phy */
uint8_t pwr = twl4030_usb_read(PHY_PWR_CTRL);
pwr &= ~PHYPWD;
twl4030_usb_write(PHY_PWR_CTRL, pwr);
twl4030_usb_write(PHY_CLK_CTRL,
twl4030_usb_read(PHY_CLK_CTRL) |
(CLOCKGATING_EN | CLK32K_EN));
/* set DPLL i2c access mode */
twl4030_i2c_access(true);
/* set ulpi mode */
twl4030_usb_clear_bits(IFC_CTRL, CARKITMODE);
twl4030_usb_set_bits(POWER_CTRL, OTG_ENAB);
twl4030_usb_write(FUNC_CTRL, XCVRSELECT_HS); // set high speed mode
// twl4030_usb_write(FUNC_CTRL, XCVRSELECT_FS); // set full speed mode
twl4030_i2c_access(false);
return 0;
}
int twl4030_init_hs(void)
{
return 0;
}
int twl4030_set_usb_pullup(bool pullup)
{
TRACE_ENTRY;
if (pullup) {
twl4030_usb_clear_bits(OTG_CTRL, DPPULLDOWN);
twl4030_usb_set_bits(FUNC_CTRL, TERMSELECT);
} else {
twl4030_usb_clear_bits(FUNC_CTRL, TERMSELECT);
twl4030_usb_set_bits(OTG_CTRL, DPPULLDOWN);
}
return 0;
}
@@ -0,0 +1,369 @@
/*
* Copyright (c) 2008 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __TWL4030_HW_H
#define __TWL4030_HW_H
/* TWL i2c addresses */
#define TWL_I2C_ADDR0 0x48
#define TWL_I2C_ADDR1 0x49
#define TWL_I2C_ADDR2 0x4a
#define TWL_I2C_ADDR3 0x4b
#define TWL_USB_ADDR TWL_I2C_ADDR0
#define TWL_INTBR_ADDR TWL_I2C_ADDR1
#define TWL_PM_RECEIVER_ADDR TWL_I2C_ADDR3
/* TWL registers */
#define PROTECT_KEY 0x44
#define VAUX1_DEV_GRP 0x72
#define VAUX1_TYPE 0x73
#define VAUX1_REMAP 0x74
#define VAUX1_DEDICATED 0x75
#define VAUX2_DEV_GRP 0x76
#define VAUX2_TYPE 0x77
#define VAUX2_REMAP 0x78
#define VAUX2_DEDICATED 0x79
#define VAUX3_DEV_GRP 0x7a
#define VAUX3_TYPE 0x7b
#define VAUX3_REMAP 0x7c
#define VAUX3_DEDICATED 0x7d
#define VAUX4_DEV_GRP 0x7e
#define VAUX4_TYPE 0x7f
#define VAUX4_REMAP 0x80
#define VAUX4_DEDICATED 0x81
#define VMMC1_DEV_GRP 0x82
#define VMMC1_TYPE 0x83
#define VMMC1_REMAP 0x84
#define VMMC1_DEDICATED 0x85
#define VMMC2_DEV_GRP 0x86
#define VMMC2_TYPE 0x87
#define VMMC2_REMAP 0x88
#define VMMC2_DEDICATED 0x89
#define VPLL1_DEV_GRP 0x8a
#define VPLL1_TYPE 0x8b
#define VPLL1_REMAP 0x8c
#define VPLL1_DEDICATED 0x8d
#define VPLL2_DEV_GRP 0x8e
#define VPLL2_TYPE 0x8f
#define VPLL2_REMAP 0x90
#define VPLL2_DEDICATED 0x91
#define VDAC_DEV_GRP 0x96
#define VDAC_DEDICATED 0x99
#define VDD2_DEV_GRP 0xBE
#define VDD2_TYPE 0xBF
#define VDD2_REMAP 0xC0
#define VDD2_CFG 0xC1
#define VSIM_DEV_GRP 0x92
#define VSIM_TYPE 0x93
#define VSIM_REMAP 0x94
#define VSIM_DEDICATED 0x95
#define PMBR1 0x92
#define SECONDS_REG 0x1C
#define MINUTES_REG 0x1D
#define ALARM_SECONDS_REG 0x23
#define ALARM_MINUTES_REG 0x24
#define ALARM_HOURS_REG 0x25
#define RTC_STATUS_REG 0x2A
#define RTC_INTERRUPTS_REG 0x2B
#define PWR_ISR1 0x2E
#define PWR_IMR1 0x2F
#define PWR_ISR2 0x30
#define PWR_IMR2 0x31
#define PWR_EDR1 0x33
#define CFG_PWRANA2 0x3F
#define RTC_INTERRUPTS_REG 0x2B
#define STS_HW_CONDITIONS 0x45
#define P1_SW_EVENTS 0x46
#define P2_SW_EVENTS 0x47
#define P3_SW_EVENTS 0x48
#define VDD1_TRIM1 0x62
#define VDD1_TRIM2 0x63
#define VDD1_VFLOOR 0xBB
#define VDD1_VROOF 0xBC
#define PB_CFG 0x4A
#define PB_WORD_MSB 0x4B
#define PB_WORD_LSB 0x4C
#define VSIM_REMAP 0x94
#define VDAC_REMAP 0x98
#define VINTANA1_DEV_GRP 0x9A
#define VINTANA1_REMAP 0x9C
#define VINTANA2_REMAP 0xA0
#define VINTANA2_DEV_GRP 0x9E
#define VINTDIG_DEV_GRP 0xA2
#define VINTDIG_REMAP 0xA4
#define VIO_DEV_GRP 0xA6
#define VIO_REMAP 0xA8
#define VDD1_REMAP 0xB2
#define VDD2_REMAP 0xC0
#define REGEN_REMAP 0xDC
#define NRESPWRON_REMAP 0xDF
#define CLKEN_REMAP 0xE2
#define SYSEN_REMAP 0xE5
#define HFCLKOUT_REMAP 0xE8
#define HFCLKOUT_DEV_GRP 0xE6
#define T32KCLKOUT_REMAP 0xEB
#define TRITON_RESET_REMAP 0xEE
#define MAINREF_REMAP 0xF1
#define VIBRA_CTL 0x45
#define VUSB1V5_DEV_GRP 0xCC
#define VUSB1V5_TYPE 0xCD
#define VUSB1V5_REMAP 0xCE
#define VUSB1V8_DEV_GRP 0xCF
#define VUSB1V8_TYPE 0xD0
#define VUSB1V8_REMAP 0xD1
#define VUSB3V1_DEV_GRP 0xD2
#define VUSB3V1_TYPE 0xD3
#define VUSB3V1_REMAP 0xD4
#define VUSBCP_DEV_GRP 0xD5
#define VUSBCP_TYPE 0xD6
#define VUSBCP_REMAP 0xD7
#define VUSB_DEDICATED1 0xD8
#define VUSB_DEDICATED2 0xD9
/* USB registers */
#define VENDOR_ID_LO 0x0
#define VENDOR_ID_HI 0x1
#define PRODUCT_ID_LO 0x2
#define PRODUCT_ID_HI 0x3
#define FUNC_CTRL 0x4
#define FUNC_CTRL_SET 0x5
#define FUNC_CTRL_CLR 0x6
# define SUSPENDM (1 << 6)
# define RESET (1 << 5)
# define OPMODE_MASK (3 << 3) /* bits 3 and 4 */
# define OPMODE_NORMAL (0 << 3)
# define OPMODE_NONDRIVING (1 << 3)
# define OPMODE_DISABLE_BIT_NRZI (2 << 3)
# define TERMSELECT (1 << 2)
# define XCVRSELECT_MASK (3 << 0) /* bits 0 and 1 */
# define XCVRSELECT_HS (0 << 0)
# define XCVRSELECT_FS (1 << 0)
# define XCVRSELECT_LS (2 << 0)
# define XCVRSELECT_FS4LS (3 << 0)
#define IFC_CTRL 0x7
#define IFC_CTRL_SET 0x8
#define IFC_CTRL_CLR 0x9
# define INTERFACE_PROTECT_DISABLE (1 << 7)
# define AUTORESUME (1 << 4)
# define CLOCKSUSPENDM (1 << 3)
# define CARKITMODE (1 << 2)
# define FSLSSERIALMODE_3PIN (1 << 1)
#define OTG_CTRL 0xa
#define OTG_CTRL_SET 0xb
#define OTG_CTRL_CLR 0xc
#define DRVVBUS (1 << 5)
#define CHRGVBUS (1 << 4)
#define DISCHRGVBUS (1 << 3)
#define DMPULLDOWN (1 << 2)
#define DPPULLDOWN (1 << 1)
#define IDPULLUP (1 << 0)
#define USB_INT_EN_RISE 0xd
#define USB_INT_EN_RISE_SET 0xe
#define USB_INT_EN_RISE_CLR 0xf
#define USB_INT_EN_FALL 0x10
#define USB_INT_EN_FALL_SET 0x11
#define USB_INT_EN_FALL_CLR 0x12
# define HOSTDISCONNECT (1 << 0)
#define USB_INT_STS 0x13
#define USB_INT_LATCH 0x14
#define USB_DEBUG 0x15
#define SCRATCH_REG 0x16
#define SCRATCH_REG_SET 0x17
#define SCRATCH_REG_CLR 0x18
#define CARKIT_CTRL 0x19
#define CARKIT_CTRL_SET 0x1a
#define CARKIT_CTRL_CLR 0x1b
#define MICEN (1 << 6)
#define SPKRIGHTEN (1 << 5)
#define SPKLEFTEN (1 << 4)
#define RXDEN (1 << 3)
#define TXDEN (1 << 2)
#define IDGNDDRV (1 << 1)
#define CARKITPWR (1 << 0)
#define CARKIT_INT_DELAY 0x1c
#define CARKIT_INT_EN 0x1d
#define CARKIT_INT_EN_SET 0x1e
#define CARKIT_INT_EN_CLR 0x1f
#define CARKIT_INT_STS 0x20
#define CARKIT_INT_LATCH 0x21
#define CARKIT_PLS_CTRL 0x22
#define CARKIT_PLS_CTRL_SET 0x23
#define CARKIT_PLS_CTRL_CLR 0x24
# define SPKRRIGHT_BIASEN (1 << 3)
# define SPKRLEFT_BIASEN (1 << 2)
# define RXPLSEN (1 << 1)
# define TXPLSEN (1 << 0)
#define TRANS_POS_WIDTH 0x25
#define TRANS_NEG_WIDTH 0x26
#define RCV_PLTY_RECOVERY 0x27
#define MCPC_CTRL 0x30
#define MCPC_CTRL_SET 0x31
#define MCPC_CTRL_CLR 0x32
#define RTSOL (1 << 7)
#define EXTSWR (1 << 6)
#define EXTSWC (1 << 5)
#define VOICESW (1 << 4)
#define OUT64K (1 << 3)
#define RTSCTSSW (1 << 2)
#define HS_UART (1 << 0)
#define MCPC_IO_CTRL 0x033
#define MCPC_IO_CTRL_SET 0x034
#define MCPC_IO_CTRL_CLR 0x035
#define MICBIASEN (1<< 5)
#define CTS_NPU (1 << 4)
#define RXD_PU (1 << 3)
#define TXDTYP (1 << 2)
#define CTSTYP (1 << 1)
#define RTSTYP (1 << 0)
#define MCPC_CTRL2 0x036
#define MCPC_CTRL2_SET 0x037
#define MCPC_CTRL2_CLR 0x038
# define MCPC_CK_EN (1 << 0)
#define OTHER_FUNC_CTRL 0x080
#define OTHER_FUNC_CTRL_SET 0x081
#define OTHER_FUNC_CTRL_CLR 0x082
#define BDIS_ACON_EN (1<< 4)
#define FIVEWIRE_MODE (1 << 2)
#define OTHER_IFC_CTRL 0x083
#define OTHER_IFC_CTRL_SET 0x084
#define OTHER_IFC_CTRL_CLR 0x085
# define OE_INT_EN (1 << 6)
# define CEA2011_MODE (1 << 5)
# define FSLSSERIALMODE_4PIN (1 << 4)
# define HIZ_ULPI_60MHZ_OUT (1 << 3)
# define HIZ_ULPI (1 << 2)
# define ALT_INT_REROUTE (1 << 0)
#define OTHER_INT_EN_RISE 0x086
#define OTHER_INT_EN_RISE_SET 0x087
#define OTHER_INT_EN_RISE_CLR 0x088
#define OTHER_INT_EN_FALL 0x089
#define OTHER_INT_EN_FALL_SET 0x08A
#define OTHER_INT_EN_FALL_CLR 0x08B
#define OTHER_INT_STS 0x8C
#define OTHER_INT_LATCH 0x8D
#define ID_INT_EN_RISE 0x08E
#define ID_INT_EN_RISE_SET 0x08F
#define ID_INT_EN_RISE_CLR 0x090
#define ID_INT_EN_FALL 0x091
#define ID_INT_EN_FALL_SET 0x092
#define ID_INT_EN_FALL_CLR 0x093
#define ID_INT_STS 0x094
#define ID_INT_LATCH 0x95
#define ID_STATUS 0x96
#define CARKIT_SM_1_INT_EN 0x097
#define CARKIT_SM_1_INT_EN_SET 0x098
#define CARKIT_SM_1_INT_EN_CLR 0x099
#define CARKIT_SM_1_INT_STS 0x09A
#define CARKIT_SM_1_INT_LATCH 0x9B
#define CARKIT_SM_2_INT_EN 0x09C
#define CARKIT_SM_2_INT_EN_SET 0x09D
#define CARKIT_SM_2_INT_EN_CLR 0x09E
#define CARKIT_SM_2_INT_STS 0x09F
#define CARKIT_SM_2_INT_LATCH 0xA0
#define CARKIT_SM_CTRL 0x0A1
#define CARKIT_SM_CTRL_SET 0x0A2
#define CARKIT_SM_CTRL_CLR 0x0A3
#define CARKIT_SM_CMD 0x0A4
#define CARKIT_SM_CMD_SET 0x0A5
#define CARKIT_SM_CMD_CLR 0x0A6
#define CARKIT_SM_CMD_STS 0xA7
#define CARKIT_SM_STATUS 0xA8
#define CARKIT_SM_NEXT_STATUS 0xA9
#define CARKIT_SM_ERR_STATUS 0xAA
#define CARKIT_SM_CTRL_STATE 0xAB
#define POWER_CTRL 0xAC
#define POWER_CTRL_SET 0xAD
#define POWER_CTRL_CLR 0xAE
# define OTG_ENAB (1 << 5)
#define OTHER_IFC_CTRL2 0xAF
#define OTHER_IFC_CTRL2_SET 0xB0
#define OTHER_IFC_CTRL2_CLR 0xB1
# define ULPI_TXEN_POL (1 << 3)
# define ULPI_4PIN_2430 (1 << 2)
#define REG_CTRL_EN 0xB2
#define REG_CTRL_EN_SET 0xB3
#define REG_CTRL_EN_CLR 0xB4
#define REG_CTRL_ERROR 0xB5
#define ULPI_I2C_CONFLICT_INTEN (1 << 0)
#define OTHER_FUNC_CTRL2 0xB8
#define OTHER_FUNC_CTRL2_SET 0xB9
#define OTHER_FUNC_CTRL2_CLR 0xBA
#define VBAT_TIMER_EN (1 << 0)
#define CARKIT_ANA_CTRL 0xBB
#define CARKIT_ANA_CTRL_SET 0xBC
#define CARKIT_ANA_CTRL_CLR 0xBD
#define VBUS_DEBOUNCE 0xC0
#define ID_DEBOUNCE 0xC1
#define TPH_DP_CON_MIN 0xC2
#define TPH_DP_CON_MAX 0xC3
#define TCR_DP_CON_MIN 0xC4
#define TCR_DP_CON_MAX 0xC5
#define TPH_DP_PD_SHORT 0xC6
#define TPH_CMD_DLY 0xC7
#define TPH_DET_RST 0xC8
#define TPH_AUD_BIAS 0xC9
#define TCR_UART_DET_MIN 0xCA
#define TCR_UART_DET_MAX 0xCB
#define TPH_ID_INT_PW 0xCD
#define TACC_ID_INT_WAIT 0xCE
#define TACC_ID_INT_PW 0xCF
#define TPH_CMD_WAIT 0xD0
#define TPH_ACK_WAIT 0xD1
#define TPH_DP_DISC_DET 0xD2
#define VBAT_TIMER 0xD3
#define CARKIT_4W_DEBUG 0xE0
#define CARKIT_5W_DEBUG 0xE1
#define CARKIT_5W_DEBUG 0xE1
#define TEST_CTRL_CLR 0xEB
#define TEST_CARKIT_SET 0xEC
#define TEST_CARKIT_CLR 0xED
#define TEST_POWER_SET 0xEE
#define TEST_POWER_CLR 0xEF
#define TEST_ULPI 0xF0
#define TXVR_EN_TEST_SET 0xF2
#define TXVR_EN_TEST_CLR 0xF3
#define VBUS_EN_TEST 0xF4
#define ID_EN_TEST 0xF5
#define PSM_EN_TEST_SET 0xF6
#define PSM_EN_TEST_CLR 0xF7
#define PHY_TRIM_CTRL 0xFC
#define PHY_PWR_CTRL 0xFD
# define PHYPWD (1 << 0)
#define PHY_CLK_CTRL 0xFE
# define CLOCKGATING_EN (1 << 2)
# define CLK32K_EN (1 << 1)
# define REQ_PHY_DPLL_CLK (1 << 0)
#define PHY_CLK_CTRL_STS 0xFF
# define PHY_DPLL_CLK (1 << 0)
#endif