/**************************************************************************** * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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, ®addr, 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, ®val) == 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, ®val) == 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, ®val) == 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, ®val) == 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, ®val) == 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, ®val) == 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, ®val) == 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, ®val) == 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, ®val) == 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, ®val) == 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 */