nuttx/drivers/power/supply/act8945a.c

1098 lines
30 KiB
C
Raw Permalink Normal View History

/****************************************************************************
* drivers/power/supply/act8945a.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <string.h>
#include <debug.h>
#include <poll.h>
#include <fcntl.h>
#include <assert.h>
#include <nuttx/fs/fs.h>
#include <nuttx/spinlock.h>
#include <nuttx/kmalloc.h>
#include <nuttx/i2c/i2c_master.h>
#include <nuttx/power/regulator.h>
#include <nuttx/power/act8945a.h>
#if defined(CONFIG_I2C) && defined(CONFIG_REGULATOR_ACT8945A)
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define ACT8945A_BUS_SPEED 300000
#define ACT8945A_SLAVE_ADDRESS 0x5b
#ifdef CONFIG_DEBUG_POWER_ERROR
# define act8945a_err(x, ...) _err(x, ##__VA_ARGS__)
#else
# define act8945a_err(x, ...) uerr(x, ##__VA_ARGS__)
#endif
#ifdef CONFIG_DEBUG_POWER_WARN
# define act8945a_warn(x, ...) _warn(x, ##__VA_ARGS__)
#else
# define act8945a_warn(x, ...) uwarn(x, ##__VA_ARGS__)
#endif
#ifdef CONFIG_DEBUG_POWER_INFO
# define act8945a_info(x, ...) _info(x, ##__VA_ARGS__)
#else
# define act8945a_info(x, ...) uinfo(x, ##__VA_ARGS__)
#endif
#define ACT8945A_NUM_VOLTAGES 64
#define ACT8945A_SYS0 (0x00)
#define ACT8945A_SYS1 (0x01)
#define ACT8945A_DCDC1_VSET0 (0x20)
#define ACT8945A_DCDC1_VSET1 (0x21)
#define ACT8945A_DCDC1_CONTROL (0x22)
#define ACT8945A_DCDC2_VSET0 (0x30)
#define ACT8945A_DCDC2_VSET1 (0x31)
#define ACT8945A_DCDC2_CONTROL (0x32)
#define ACT8945A_DCDC3_VSET0 (0x40)
#define ACT8945A_DCDC3_VSET1 (0x41)
#define ACT8945A_DCDC3_CONTROL (0x42)
#define ACT8945A_LDO1_VSET (0x50)
#define ACT8945A_LDO1_CONTROL (0x51)
#define ACT8945A_LDO2_VSET (0x54)
#define ACT8945A_LDO2_CONTROL (0x55)
#define ACT8945A_LDO3_VSET (0x60)
#define ACT8945A_LDO3_CONTROL (0x61)
#define ACT8945A_LDO4_VSET (0x64)
#define ACT8945A_LDO4_CONTROL (0x65)
#define ACT8945A_SYSTRST_MASK (0x80)
#define ACT8945A_SYSMODE_MASK (0x40)
#define ACT8945A_SYSLEV_MASK (0x0f)
#define ACT8945A_VSET_MASK (0x3f)
#define ACT8945A_EN_MASK (0x80)
#define ACT8945A_SCRATCH_MASK (0x0f)
#define SCRATCH_TEST_VAL (0x05)
#define ACT8945A_PULLDOWN_MASK (0x40)
#ifdef CONFIG_ACT8945A_TRST_64
# define ACT8945A_TRST (0x80) /* 64ms*/
#else
# define ACT8945A_TRST (0) /* 260ms */
#endif
#ifdef CONFIG_ACT8945A_SYSLEV_MODE_INTERRUPT
# define ACT8945A_SYSLEV_MODE (0x40) /* Interrupt */
#else
# define ACT8945A_SYSLEV_MODE (0) /* Shutdown */
#endif
#if defined(CONFIG_ACT8945A_SYSLEV_2300)
# define ACT8945A_SYSLEV 0
#elif defined(CONFIG_ACT8945A_SYSLEV_2400)
# define ACT8945A_SYSLEV 1
#elif defined(CONFIG_ACT8945A_SYSLEV_2500)
# define ACT8945A_SYSLEV 2
#elif defined(CONFIG_ACT8945A_SYSLEV_2600)
# define ACT8945A_SYSLEV 3
#elif defined(CONFIG_ACT8945A_SYSLEV_2700)
# define ACT8945A_SYSLEV 4
#elif defined(CONFIG_ACT8945A_SYSLEV_2800)
# define ACT8945A_SYSLEV 5
#elif defined(CONFIG_ACT8945A_SYSLEV_2900)
# define ACT8945A_SYSLEV 6
#elif defined(CONFIG_ACT8945A_SYSLEV_3000)
# define ACT8945A_SYSLEV 7
#elif defined(CONFIG_ACT8945A_SYSLEV_3100)
# define ACT8945A_SYSLEV 8
#elif defined(CONFIG_ACT8945A_SYSLEV_3200)
# define ACT8945A_SYSLEV 9
#elif defined(CONFIG_ACT8945A_SYSLEV_3300)
# define ACT8945A_SYSLEV 10
#elif defined(CONFIG_ACT8945A_SYSLEV_3400)
# define ACT8945A_SYSLEV 11
#elif defined(CONFIG_ACT8945A_SYSLEV_3500)
# define ACT8945A_SYSLEV 12
#elif defined(CONFIG_ACT8945A_SYSLEV_3600)
# define ACT8945A_SYSLEV 13
#elif defined(CONFIG_ACT8945A_SYSLEV_3700)
# define ACT8945A_SYSLEV 14
#elif defined(CONFIG_ACT8945A_SYSLEV_3800)
# define ACT8945A_SYSLEV 15
#else
# error No act8945a sys level detect threshold defined
#endif
#ifdef CONFIG_ACT8945A_DCDC1_BOOT_ON
# define ACT8945A_DCDC1_BOOT_ON 1
#else
# define ACT8945A_DCDC1_BOOT_ON 0
#endif
#ifdef CONFIG_ACT8945A_DCDC2_BOOT_ON
# define ACT8945A_DCDC2_BOOT_ON 1
#else
# define ACT8945A_DCDC2_BOOT_ON 0
#endif
#ifdef CONFIG_ACT8945A_DCDC3_BOOT_ON
# define ACT8945A_DCDC3_BOOT_ON 1
#else
# define ACT8945A_DCDC3_BOOT_ON 0
#endif
#ifdef CONFIG_ACT8945A_LDO1_BOOT_ON
# define ACT8945A_LDO1_BOOT_ON 1
#else
# define ACT8945A_LDO1_BOOT_ON 0
#endif
#ifdef CONFIG_ACT8945A_LDO2_BOOT_ON
# define ACT8945A_LDO2_BOOT_ON 1
#else
# define ACT8945A_LDO2_BOOT_ON 0
#endif
#ifdef CONFIG_ACT8945A_LDO3_BOOT_ON
# define ACT8945A_LDO3_BOOT_ON 1
#else
# define ACT8945A_LDO3_BOOT_ON 0
#endif
#ifdef CONFIG_ACT8945A_LDO4_BOOT_ON
# define ACT8945A_LDO4_BOOT_ON 1
#else
# define ACT8945A_LDO4_BOOT_ON 0
#endif
#ifdef CONFIG_ACT8945A_DCDC1_APPLY_UV
# define ACT8945A_DCDC1_APPLY_UV 1
#else
# define ACT8945A_DCDC1_APPLY_UV 0
#endif
#ifdef CONFIG_ACT8945A_DCDC2_APPLY_UV
# define ACT8945A_DCDC2_APPLY_UV 1
#else
# define ACT8945A_DCDC2_APPLY_UV 0
#endif
#ifdef CONFIG_ACT8945A_DCDC3_APPLY_UV
# define ACT8945A_DCDC3_APPLY_UV 1
#else
# define ACT8945A_DCDC3_APPLY_UV 0
#endif
#ifdef CONFIG_ACT8945A_LDO1_APPLY_UV
# define ACT8945A_LDO1_APPLY_UV 1
#else
# define ACT8945A_LDO1_APPLY_UV 0
#endif
#ifdef CONFIG_ACT8945A_LDO2_APPLY_UV
# define ACT8945A_LDO2_APPLY_UV 1
#else
# define ACT8945A_LDO2_APPLY_UV 0
#endif
#ifdef CONFIG_ACT8945A_LDO3_APPLY_UV
# define ACT8945A_LDO3_APPLY_UV 1
#else
# define ACT8945A_LDO3_APPLY_UV 0
#endif
#ifdef CONFIG_ACT8945A_LDO4_APPLY_UV
# define ACT8945A_LDO4_APPLY_UV 1
#else
# define ACT8945A_LDO4_APPLY_UV 0
#endif
#define ACT8945A_DCDC1_PULLDOWN 0
#define ACT8945A_DCDC2_PULLDOWN 0
#define ACT8945A_DCDC3_PULLDOWN 0
#ifdef CONFIG_ACT8945A_LDO1_PULLDOWN
# define ACT8945A_LDO1_PULLDOWN 1
#else
# define ACT8945A_LDO1_PULLDOWN 0
#endif
#ifdef CONFIG_ACT8945A_LDO2_PULLDOWN
# define ACT8945A_LDO2_PULLDOWN 1
#else
# define ACT8945A_LDO2_PULLDOWN 0
#endif
#ifdef CONFIG_ACT8945A_LDO3_PULLDOWN
# define ACT8945A_LDO3_PULLDOWN 1
#else
# define ACT8945A_LDO3_PULLDOWN 0
#endif
#ifdef CONFIG_ACT8945A_LDO4_PULLDOWN
# define ACT8945A_LDO4_PULLDOWN 1
#else
# define ACT8945A_LDO4_PULLDOWN 0
#endif
/* Ramp times are fixed for this regulator */
#define ETIME_0 0
#define ETIME_400 400
#define ETIME_800 800
#define ACT8945A_REG(_id, _vsel, _etime) \
[ACT8945A_##_id] = \
{ \
.n_voltages = ACT8945A_NUM_VOLTAGES, \
.vsel_reg = ACT8945A_##_id##_##_vsel, \
.vsel_mask = ACT8945A_VSET_MASK, \
.name = CONFIG_ACT8945A_##_id##_NAME, \
.id = ACT8945A_##_id, \
.enable_reg = ACT8945A_##_id##_CONTROL, \
.enable_mask = ACT8945A_EN_MASK, \
.enable_time = (_etime), \
.ramp_delay = 400, \
.uv_step = 0, \
.min_uv = CONFIG_ACT8945A_##_id##_MIN_UV, \
.max_uv = CONFIG_ACT8945A_##_id##_MAX_UV, \
.pulldown = ACT8945A_##_id##_PULLDOWN, \
.pulldown_reg = ACT8945A_##_id##_CONTROL, \
.pulldown_mask = ACT8945A_PULLDOWN_MASK, \
.apply_uv = ACT8945A_##_id##_APPLY_UV, \
.boot_on = ACT8945A_##_id##_BOOT_ON, \
}
/****************************************************************************
* Private type
****************************************************************************/
struct regulator_act8945a_priv
{
FAR struct i2c_master_s *i2c;
uint8_t i2c_addr;
int i2c_freq;
FAR const struct regulator_desc_s *regulators;
FAR struct regulator_dev_s *rdev;
};
struct act8945a_dev_s
{
/* Common part of the regulator driver visible to the upper-half driver */
FAR struct regulator_desc_s *regulator_desc_s;
/* Data fields specific to the lower half act8945a driver follow */
FAR struct i2c_master_s *i2c; /* I2C interface */
uint8_t addr; /* I2C address */
uint32_t frequency; /* I2C frequency */
};
enum
{
ACT8945A_DCDC1 = 0,
ACT8945A_DCDC2,
ACT8945A_DCDC3,
ACT8945A_LDO1,
ACT8945A_LDO2,
ACT8945A_LDO3,
ACT8945A_LDO4,
ACT8945A_MAX,
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* Character driver methods */
/* regulator lower half methods */
static int act8945a_list_voltage(struct regulator_dev_s *rdev,
unsigned int selector);
static int act8945a_set_voltage_sel(FAR struct regulator_dev_s *rdev,
unsigned int selector);
static int act8945a_get_voltage_sel(FAR struct regulator_dev_s *rdev);
static int act8945a_enable(struct regulator_dev_s *rdev);
static int act8945a_is_enabled(struct regulator_dev_s *rdev);
static int act8945a_disable(struct regulator_dev_s *rdev);
static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
uint8_t value);
static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
uint8_t * scratch);
static int act8945a_enable_pulldown(struct regulator_dev_s *rdev);
static int act8945a_disable_pulldown(struct regulator_dev_s *rdev);
static int act89845a_set_sysmode(struct regulator_act8945a_priv *priv,
uint8_t mode);
static int act89845a_set_trstmode(struct regulator_act8945a_priv *priv,
uint8_t timer);
static int act89845a_set_syslev(struct regulator_act8945a_priv *priv,
uint8_t level);
/* I2C support */
static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
uint8_t regaddr, uint8_t *regval);
static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
uint8_t regaddr, uint8_t regval);
/****************************************************************************
* Private Data
****************************************************************************/
static const int mv_list[] =
{
600, 625, 650, 675, 700, 725, 750, 775,
800, 825, 850, 875, 900, 925, 950, 975,
1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950,
2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350,
2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100,
3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900,
};
static const struct regulator_desc_s g_act8945a_regulators[] =
{
ACT8945A_REG(DCDC1, VSET0, ETIME_0),
ACT8945A_REG(DCDC2, VSET0, ETIME_400),
ACT8945A_REG(DCDC3, VSET0, ETIME_0),
ACT8945A_REG(LDO1, VSET, ETIME_800),
ACT8945A_REG(LDO2, VSET, ETIME_0),
ACT8945A_REG(LDO3, VSET, ETIME_0),
ACT8945A_REG(LDO4, VSET, ETIME_0),
};
static const struct regulator_desc_s g_alt_act8945a_regulators[] =
{
ACT8945A_REG(DCDC1, VSET1, ETIME_0),
ACT8945A_REG(DCDC2, VSET1, 400000),
ACT8945A_REG(DCDC3, VSET1, ETIME_0),
ACT8945A_REG(LDO1, VSET, 800000),
ACT8945A_REG(LDO2, VSET, ETIME_0),
ACT8945A_REG(LDO3, VSET, ETIME_0),
ACT8945A_REG(LDO4, VSET, ETIME_0),
};
/* Regulator operations */
static const struct regulator_ops_s g_act8945a_ops =
{
act8945a_list_voltage, /* list_voltage */
NULL, /* set_voltage */
act8945a_set_voltage_sel, /* set_voltage_sel */
NULL, /* get_voltage */
act8945a_get_voltage_sel, /* get_voltage_sel */
act8945a_enable, /* enable */
act8945a_is_enabled, /* is_enabled */
act8945a_disable, /* disable */
act8945a_enable_pulldown, /* enable pulldown if reg. disabled */
act8945a_disable_pulldown, /* disable pulldown if reg. disabled */
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: act8945a_getreg
*
* Description:
* Reads a single register from the ACT8945A regulator
*
* Input Parameters:
*
* priv - private act8945a device structure
* regaddr - the act8945a register address
* regval - location to return the act8945a register value
*
* Returned value:
*
* Success, or fail reason
*
****************************************************************************/
static int act8945a_getreg(FAR struct regulator_act8945a_priv *priv,
uint8_t regaddr, uint8_t *regval)
{
struct i2c_config_s config;
int ret;
irqstate_t flags;
/* Sanity check */
DEBUGASSERT(priv != NULL);
DEBUGASSERT(regval != NULL);
/* Set up the I2C configuration */
config.frequency = priv->i2c_freq;
config.address = priv->i2c_addr;
config.addrlen = 7;
/* Write the register address */
flags = spin_lock_irqsave(NULL);
ret = i2c_write(priv->i2c, &config, &regaddr, sizeof(regaddr));
spin_unlock_irqrestore(NULL, flags);
if (ret < 0)
{
act8945a_err("ERROR: i2c_write failed: %d\n", ret);
return ret;
}
/* Restart and read 8 bits from the register */
flags = spin_lock_irqsave(NULL);
ret = i2c_read(priv->i2c, &config, regval, sizeof(*regval));
spin_unlock_irqrestore(NULL, flags);
if (ret < 0)
{
act8945a_err("ERROR: i2c_read failed: %d\n", ret);
return ret;
}
act8945a_info("INFO: addr: %02x value: %02x\n", regaddr, *regval);
return OK;
}
/****************************************************************************
* Name: act8945a_putreg
*
* Description:
* Writes a single byte to one of the ACT8945A registers.
*
* Input Parameters:
*
* priv - private act8945a device structure
* regaddr - the act8945a register address
* regval - value to write to the act8945a register
*
* Returned value:
*
* Success, or fail reason
*
****************************************************************************/
static int act8945a_putreg(FAR struct regulator_act8945a_priv *priv,
uint8_t regaddr, uint8_t regval)
{
struct i2c_config_s config;
uint8_t buffer[2];
int ret;
irqstate_t flags;
/* Sanity check */
DEBUGASSERT(priv != NULL);
/* Set up a 2-byte message to send */
buffer[0] = regaddr;
buffer[1] = regval;
/* Set up the I2C configuration */
config.frequency = priv->i2c_freq;
config.address = priv->i2c_addr;
config.addrlen = 7;
/* Write the register address followed by the data (no RESTART) */
flags = spin_lock_irqsave(NULL);
ret = i2c_write(priv->i2c, &config, buffer, sizeof(buffer));
spin_unlock_irqrestore(NULL, flags);
if (ret < 0)
{
act8945a_err("ERROR: i2c_write failed: %d\n", ret);
return ret;
}
act8945a_info("INFO:addr: %02x value: %02x\n", regaddr, regval);
return OK;
}
/****************************************************************************
* Name: act8945a_list_voltage
*
* Description:
*
* Input Parameters:
*
* rdev - The regulator device pointer.
* selector - The selector for the voltage look-up
*
* Returned Value:
*
* The voltage for the selector, or error code.
*
****************************************************************************/
static int act8945a_list_voltage(FAR struct regulator_dev_s *rdev,
unsigned int selector)
{
if (selector < ACT8945A_NUM_VOLTAGES)
{
return (mv_list[selector]);
}
else
{
return -EINVAL;
}
}
/****************************************************************************
* Name: act8945a_enable_pulldown
*
* Description:
*
* Input Parameters:
*
* rdev - The regulator device pointer.
*
* Returned Value
*
* Success or error code.
*
****************************************************************************/
static int act8945a_enable_pulldown(struct regulator_dev_s *rdev)
{
FAR struct regulator_act8945a_priv *priv = rdev->priv;
FAR const struct regulator_desc_s *regulator = rdev->desc;
uint8_t regval;
/* for ease of code commonality we skip any calls for DCDC1-3 */
if (regulator->id < ACT8945A_LDO1)
{
return OK;
}
if (act8945a_getreg(priv, regulator->enable_reg, &regval) == 0)
{
regval |= regulator->pulldown_mask;
if (act8945a_putreg(priv, regulator->pulldown_reg, regval) == 0)
{
pwrinfo("INFO: Output discharge control enabled %s\n",
regulator->name);
return OK;
}
}
return -EIO;
}
/****************************************************************************
* Name: act8945a_disable_pulldown
*
* Description:
*
* Input Parameters:
*
* rdev - The regulator device pointer.
*
* Returned Value:
*
* Success or error code.
*
****************************************************************************/
static int act8945a_disable_pulldown(struct regulator_dev_s *rdev)
{
FAR struct regulator_act8945a_priv *priv = rdev->priv;
FAR const struct regulator_desc_s *regulator = rdev->desc;
uint8_t regval;
/* for ease of code commonality we skip any calls for DCDC1-3 */
if (regulator->id < ACT8945A_LDO1)
{
return OK;
}
if (act8945a_getreg(priv, regulator->pulldown_reg, &regval) == 0)
{
regval &= ~regulator->pulldown_mask;
if (act8945a_putreg(priv, regulator->enable_reg, regval) == 0)
{
pwrinfo("INFO: Output discharge control disabled %s\n",
regulator->name);
return OK;
}
}
return -EIO;
}
/****************************************************************************
* Name: act8945a_write_scratch
*
* Description:
*
* Input Parameters:
*
* priv - private act8945a device structure
* value - The value to write to the 4 scratch bits
*
* Returned Value:
*
* Success or error code.
*
****************************************************************************/
static int act8945a_write_scratch(struct regulator_act8945a_priv *priv,
uint8_t value)
{
uint8_t regval;
if (act8945a_getreg(priv, ACT8945A_SYS1, &regval) == 0)
{
regval &= ~ACT8945A_SCRATCH_MASK;
regval |= value & ACT8945A_SCRATCH_MASK;
if (act8945a_putreg(priv, ACT8945A_SYS1, regval) == 0)
{
return OK;
}
}
return -EIO;
}
/****************************************************************************
* Name: act8945a_read_scratch
*
* Description:
*
* Input Parameters:
*
* priv - private act8945a device structure
* scratch - pointer to the scratch value read
*
* Returned Value:
*
* The scratch value read, and success or error code.
*
****************************************************************************/
static int act8945a_read_scratch(struct regulator_act8945a_priv *priv,
uint8_t *scratch)
{
if (act8945a_getreg(priv, ACT8945A_SYS1, scratch) == 0)
{
return OK;
}
else
{
return -EIO;
}
}
/****************************************************************************
* Name: act89845a_set_sysmode
*
* Description:
*
* Input Parameters:
*
* priv - private act8945a device structure
* mode - The system mode to set
*
* Returned Value:
*
* Success or error code.
*
****************************************************************************/
static int act89845a_set_sysmode(struct regulator_act8945a_priv *priv,
uint8_t mode)
{
uint8_t regval;
if (act8945a_getreg(priv, ACT8945A_SYS0, &regval) == 0)
{
regval &= ~ACT8945A_SYSMODE_MASK;
regval |= mode & ACT8945A_SYSMODE_MASK;
if (act8945a_putreg(priv, ACT8945A_SYS0, regval) == 0)
{
pwrinfo ("INFO: sysmode set to %d\n", mode >> 6);
return OK;
}
}
return -EIO;
}
/****************************************************************************
* Name: act89845a_set_trstmode
*
* Description:
*
* Input Parameters:
*
* priv - private act8945a device structure
* mode - The system reset timer setting to set
*
* Returned Value:
*
* Success or error code.
*
****************************************************************************/
static int act89845a_set_trstmode(struct regulator_act8945a_priv *priv,
uint8_t timer)
{
uint8_t regval;
if (act8945a_getreg(priv, ACT8945A_SYS0, &regval) == 0)
{
regval &= ~ACT8945A_SYSTRST_MASK;
regval |= timer & ACT8945A_SYSTRST_MASK;
if (act8945a_putreg(priv, ACT8945A_SYS0, regval) == 0)
{
pwrinfo ("INFO: sysmode set to %d\n", timer >> 7);
return OK;
}
}
return -EIO;
}
/****************************************************************************
* Name: act89845a_set_syslev
*
* Description:
*
* Input Parameters:
*
* priv - private act8945a device structure
* level - The system voltage level detect threshold to set
*
* Returned Value:
*
* Success or error code.
*
****************************************************************************/
static int act89845a_set_syslev(struct regulator_act8945a_priv *priv,
uint8_t level)
{
uint8_t regval;
if (act8945a_getreg(priv, ACT8945A_SYS0, &regval) == 0)
{
regval &= ~ACT8945A_SYSLEV_MASK;
regval |= level & ACT8945A_SYSLEV_MASK;
if (act8945a_putreg(priv, ACT8945A_SYS0, regval) == 0)
{
pwrinfo ("INFO: syslevel set to %d\n", level);
return OK;
}
}
return -EIO;
}
/****************************************************************************
* Name: act8945a_set_voltage_sel
*
* Description:
*
* Input Parameters:
*
* rdev - The regulator device pointer.
* selector - The selector to use for the regulator
*
* Returned Value:
*
* Success or error code.
*
****************************************************************************/
static int act8945a_set_voltage_sel(struct regulator_dev_s *rdev,
unsigned selector)
{
FAR struct regulator_act8945a_priv *priv = rdev->priv;
FAR const struct regulator_desc_s *regulator = rdev->desc;
if (selector >= ACT8945A_NUM_VOLTAGES)
{
return -EINVAL;
}
else
{
if (act8945a_putreg(priv, regulator->vsel_reg,
selector & regulator->vsel_mask) == 0)
{
pwrinfo("INFO: reg %s set to %d mV using selector %d \n",
regulator->name, mv_list[selector], selector);
return OK;
}
else
{
return -EIO;
}
}
}
/****************************************************************************
* Name: act8945a_get_voltage_sel
*
* Description:
*
* Input Parameters:
*
* rdev - The regulator device pointer.
*
* Returned Value:
*
* The current selector from the device, or error code.
*
****************************************************************************/
static int act8945a_get_voltage_sel(struct regulator_dev_s *rdev)
{
FAR struct regulator_act8945a_priv *priv = rdev->priv;
FAR const struct regulator_desc_s *regulator = rdev->desc;
uint8_t regval;
if (act8945a_getreg(priv, regulator->vsel_reg, &regval) == 0)
{
return regval;
}
else
{
return -EIO;
}
}
/****************************************************************************
* Name: act8945a_enable
*
* Description:
*
* Input Parameters:
*
* rdev - The regulator device pointer.
*
* Returned Value:
*
* Success, or error code.
*
****************************************************************************/
static int act8945a_enable(struct regulator_dev_s *rdev)
{
FAR struct regulator_act8945a_priv *priv = rdev->priv;
FAR const struct regulator_desc_s *regulator = rdev->desc;
uint8_t regval;
if (act8945a_getreg(priv, regulator->vsel_reg, &regval) == 0)
{
regval |= regulator->enable_mask;
if (act8945a_putreg(priv, regulator->enable_reg, regval) == 0)
{
pwrinfo("INFO: reg %s enabled\n", regulator->name);
return OK;
}
}
return -EIO;
}
/****************************************************************************
* Name: act8945a_is_enabled
*
* Description:
*
* Input Parameters:
*
* rdev - The regulator device pointer.
*
* Returned Value:
*
* 0 - disabled
* 1 - enabled or disabled
* -value - error code.
*
****************************************************************************/
static int act8945a_is_enabled(struct regulator_dev_s *rdev)
{
FAR struct regulator_act8945a_priv *priv = rdev->priv;
FAR const struct regulator_desc_s *regulator = rdev->desc;
uint8_t regval;
if (act8945a_getreg(priv, regulator->enable_reg, &regval) == 0)
{
return (regval & regulator->enable_mask);
}
else
{
return -ENODEV;
}
}
/****************************************************************************
* Name: act8945a_disable
*
* Description:
*
* Input Parameters:
*
* rdev - The regulator device pointer.
*
* Returned Value:
*
* Success, or error code.
*
****************************************************************************/
static int act8945a_disable(struct regulator_dev_s *rdev)
{
FAR struct regulator_act8945a_priv *priv = rdev->priv;
FAR const struct regulator_desc_s *regulator = rdev->desc;
uint8_t regval;
if (act8945a_getreg(priv, regulator->vsel_reg, &regval) == 0)
{
regval &= ~regulator->enable_mask;
if (act8945a_putreg(priv, regulator->enable_reg, regval) == 0)
{
pwrinfo("INFO: reg %s disabled\n", regulator->name);
return OK;
}
}
return -EIO;
}
/****************************************************************************
* Public Functions
****************************************************************************/
int act8945a_initialize(FAR struct i2c_master_s *i2c, unsigned int vsel)
{
FAR struct regulator_act8945a_priv *priv;
uint8_t scratch;
int regnum;
bool reg_failed = false;
DEBUGASSERT(vsel == 0 || vsel == 1);
if (!i2c)
{
return -ENODEV;
}
priv = kmm_zalloc(sizeof(struct regulator_act8945a_priv));
if (!priv)
{
return -ENOMEM;
}
priv->i2c = i2c;
priv->i2c_addr = ACT8945A_SLAVE_ADDRESS;
priv->i2c_freq = ACT8945A_BUS_SPEED;
/* Early test to see if we can read the ACT8945A.
*
* We do this by writing a data pattern into the 4 scratch bits of SYS1
* register and making sure we can read it back OK.
*/
if (!act8945a_write_scratch(priv, SCRATCH_TEST_VAL))
{
if (!act8945a_read_scratch(priv, &scratch))
{
if (scratch != SCRATCH_TEST_VAL)
{
goto error;
}
}
}
else
{
goto error;
}
/* Initialise with Kconfig values, using correct struct depending on VSEL.
* - Some hardware may set VSEL via software.
* - Some hardware may have it hard coded and may or may not
* - allow the pin to be read back.
* - The value must be determined by board specific logic.
*/
if (vsel == 0)
{
priv->regulators = g_act8945a_regulators;
}
else
{
priv->regulators = g_alt_act8945a_regulators;
}
for (regnum = ACT8945A_DCDC1; regnum < ACT8945A_NUM_REGS; regnum++)
{
priv->rdev = regulator_register(&priv->regulators[regnum],
&g_act8945a_ops, priv);
if (priv->rdev == NULL)
{
reg_failed = true;
pwrerr("ERROR: failed to register act8945a regulator %s\n",
priv->regulators[regnum].name);
}
}
if (reg_failed)
{
goto error;
}
act89845a_set_sysmode(priv, ACT8945A_SYSLEV_MODE);
act89845a_set_trstmode(priv, ACT8945A_TRST);
act89845a_set_syslev(priv, ACT8945A_SYSLEV);
return OK;
error:
kmm_free(priv);
return -ENODEV;
}
#endif /* CONFIG_I2C && CONFIG_REGULATOR_ACT8945A */