mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 01:04:41 +01:00
Add support for the Maxim Integrated MAX77675 PMIC regulator. The MAX77675 is a compact, highly efficient SIMO (Single Inductor Multiple Output) power management IC that provides four programmable buck-boost switching regulators with only one inductor. It supports up to 700mA total output current and operates from a single-cell Li-ion battery. An integrated power-up sequencer and I2C interface allow flexible startup configuration and runtime control. Signed-off-by: Joan Na <joan.na@analog.com> Link: https://patch.msgid.link/20251207032907.4850-3-joan.na@analog.com Signed-off-by: Mark Brown <broonie@kernel.org>
1056 lines
32 KiB
C
1056 lines
32 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Copyright (c) 2025 Analog Devices, Inc.
|
|
* ADI regulator driver for MAX77675.
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/mod_devicetable.h>
|
|
#include <linux/cleanup.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/of.h>
|
|
#include <linux/i2c.h>
|
|
#include <linux/regmap.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/regulator/driver.h>
|
|
#include <linux/regulator/consumer.h>
|
|
#include <linux/regulator/of_regulator.h>
|
|
#include <linux/bitfield.h>
|
|
#include <linux/bitops.h>
|
|
|
|
/* Register Addresses */
|
|
#define MAX77675_REG_CNFG_GLBL_A 0x00
|
|
#define MAX77675_REG_CNFG_GLBL_B 0x01
|
|
#define MAX77675_REG_INT_GLBL 0x02
|
|
#define MAX77675_REG_INTM_GLBL 0x03
|
|
#define MAX77675_REG_STAT_GLBL 0x04
|
|
#define MAX77675_REG_ERCF_GLBL 0x05
|
|
#define MAX77675_REG_CID 0x06
|
|
#define MAX77675_REG_CNFG_SBB_TOP_A 0x07
|
|
#define MAX77675_REG_CNFG_SBB0_A 0x08
|
|
#define MAX77675_REG_CNFG_SBB0_B 0x09
|
|
#define MAX77675_REG_CNFG_SBB1_A 0x0A
|
|
#define MAX77675_REG_CNFG_SBB1_B 0x0B
|
|
#define MAX77675_REG_CNFG_SBB2_A 0x0C
|
|
#define MAX77675_REG_CNFG_SBB2_B 0x0D
|
|
#define MAX77675_REG_CNFG_SBB3_A 0x0E
|
|
#define MAX77675_REG_CNFG_SBB3_B 0x0F
|
|
#define MAX77675_REG_CNFG_SBB_TOP_B 0x10
|
|
|
|
/* CNFG_GLBL_A (0x00) bit masks and shifts */
|
|
#define MAX77675_MRT_MASK GENMASK(7, 6) /* Manual Reset Time (bits 7:6) */
|
|
#define MAX77675_MRT_SHIFT 6
|
|
#define MAX77675_PU_DIS_BIT BIT(5) /* Pullup Disable (bit 5) */
|
|
#define MAX77675_PU_DIS_SHIFT 5
|
|
#define MAX77675_BIAS_LPM_BIT BIT(4) /* Bias Low Power Mode (bit 4) */
|
|
#define MAX77675_BIAS_LPM_SHIFT 4
|
|
#define MAX77675_SIMO_CH_DIS_BIT BIT(3) /* SIMO Internal Channel Disable (bit 3) */
|
|
#define MAX77675_SIMO_CH_DIS_SHIFT 3
|
|
#define MAX77675_EN_MODE_MASK GENMASK(2, 1) /* nEN Mode (bits 2:1) */
|
|
#define MAX77675_EN_MODE_SHIFT 1
|
|
#define MAX77675_DBEN_EN_BIT BIT(0) /* Debounce Enable (bit 0) */
|
|
#define MAX77675_DBEN_EN_SHIFT 0
|
|
|
|
/* CNFG_GLBL_B (0x01) */
|
|
#define MAX77675_SFT_CTRL_MASK GENMASK(2, 0) /* Soft Start Control */
|
|
#define MAX77675_SFT_CTRL_SHIFT 0
|
|
|
|
/* INT_GLBL (0x02) bit bits and shifts */
|
|
#define MAX77675_INT_SBB3_F_BIT BIT(7)
|
|
#define MAX77675_INT_SBB3_F_SHIFT 7
|
|
#define MAX77675_INT_SBB2_F_BIT BIT(6)
|
|
#define MAX77675_INT_SBB2_F_SHIFT 6
|
|
#define MAX77675_INT_SBB1_F_BIT BIT(5)
|
|
#define MAX77675_INT_SBB1_F_SHIFT 5
|
|
#define MAX77675_INT_SBB0_F_BIT BIT(4)
|
|
#define MAX77675_INT_SBB0_F_SHIFT 4
|
|
#define MAX77675_INT_TJAL2_R_BIT BIT(3)
|
|
#define MAX77675_INT_TJAL2_R_SHIFT 3
|
|
#define MAX77675_INT_TJAL1_R_BIT BIT(2)
|
|
#define MAX77675_INT_TJAL1_R_SHIFT 2
|
|
#define MAX77675_INT_EN_R_BIT BIT(1)
|
|
#define MAX77675_INT_EN_R_SHIFT 1
|
|
#define MAX77675_INT_EN_F_BIT BIT(0)
|
|
#define MAX77675_INT_EN_F_SHIFT 0
|
|
|
|
/* INTM_GLBL (0x03) bits and shifts */
|
|
#define MAX77675_INTM_SBB3_F_BIT BIT(7)
|
|
#define MAX77675_INTM_SBB3_F_SHIFT 7
|
|
#define MAX77675_INTM_SBB2_F_BIT BIT(6)
|
|
#define MAX77675_INTM_SBB2_F_SHIFT 6
|
|
#define MAX77675_INTM_SBB1_F_BIT BIT(5)
|
|
#define MAX77675_INTM_SBB1_F_SHIFT 5
|
|
#define MAX77675_INTM_SBB0_F_BIT BIT(4)
|
|
#define MAX77675_INTM_SBB0_F_SHIFT 4
|
|
#define MAX77675_INTM_TJAL2_R_BIT BIT(3)
|
|
#define MAX77675_INTM_TJAL2_R_SHIFT 3
|
|
#define MAX77675_INTM_TJAL1_R_BIT BIT(2)
|
|
#define MAX77675_INTM_TJAL1_R_SHIFT 2
|
|
#define MAX77675_INTM_EN_R_BIT BIT(1)
|
|
#define MAX77675_INTM_EN_R_SHIFT 1
|
|
#define MAX77675_INTM_EN_F_BIT BIT(0)
|
|
#define MAX77675_INTM_EN_F_SHIFT 0
|
|
|
|
/* STAT_GLBL (0x04) bits and shifts */
|
|
#define MAX77675_STAT_SBB3_S_BIT BIT(7)
|
|
#define MAX77675_STAT_SBB3_S_SHIFT 7
|
|
#define MAX77675_STAT_SBB2_S_BIT BIT(6)
|
|
#define MAX77675_STAT_SBB2_S_SHIFT 6
|
|
#define MAX77675_STAT_SBB1_S_BIT BIT(5)
|
|
#define MAX77675_STAT_SBB1_S_SHIFT 5
|
|
#define MAX77675_STAT_SBB0_S_BIT BIT(4)
|
|
#define MAX77675_STAT_SBB0_S_SHIFT 4
|
|
#define MAX77675_STAT_TJAL2_S_BIT BIT(2)
|
|
#define MAX77675_STAT_TJAL2_S_SHIFT 2
|
|
#define MAX77675_STAT_TJAL1_S_BIT BIT(1)
|
|
#define MAX77675_STAT_TJAL1_S_SHIFT 1
|
|
#define MAX77675_STAT_STAT_EN_BIT BIT(0)
|
|
#define MAX77675_STAT_STAT_EN_SHIFT 0
|
|
|
|
#define MAX77675_STAT_STAT_EN_BIT BIT(0)
|
|
#define MAX77675_STAT_STAT_EN_SHIFT 0
|
|
|
|
/* ERCFLAG (0x05) bits and shifts */
|
|
#define MAX77675_SFT_CRST_F_BIT BIT(5) /* Software Cold Reset Flag */
|
|
#define MAX77675_SFT_CRST_F_SHIFT 5
|
|
#define MAX77675_SFT_OFF_F_BIT BIT(4) /* Software Off Flag */
|
|
#define MAX77675_SFT_OFF_F_SHIFT 4
|
|
#define MAX77675_MRST_BIT BIT(3) /* Manual Reset Timer Flag */
|
|
#define MAX77675_MRST_SHIFT 3
|
|
#define MAX77675_UVLO_BIT BIT(2) /* Undervoltage Lockout Flag */
|
|
#define MAX77675_UVLO_SHIFT 2
|
|
#define MAX77675_OVLO_BIT BIT(1) /* Overvoltage Lockout Flag */
|
|
#define MAX77675_OVLO_SHIFT 1
|
|
#define MAX77675_TOVLD_BIT BIT(0) /* Thermal Overload Flag */
|
|
#define MAX77675_TOVLD_SHIFT 0
|
|
|
|
/* CID (0x06) bits and shifts */
|
|
#define MAX77675_CID_MASK GENMASK(4, 0) /* Chip Identification Code mask */
|
|
#define MAX77675_CID_SHIFT 0 /* Starts at bit 0 */
|
|
|
|
/* CNFG_SBB_TOP_A (0x07) bits and shifts */
|
|
#define MAX77675_STEP_SZ_SBB3_BIT BIT(5)
|
|
#define MAX77675_STEP_SZ_SBB3_SHIFT 5
|
|
#define MAX77675_STEP_SZ_SBB2_BIT BIT(4)
|
|
#define MAX77675_STEP_SZ_SBB2_SHIFT 4
|
|
#define MAX77675_STEP_SZ_SBB1_BIT BIT(3)
|
|
#define MAX77675_STEP_SZ_SBB1_SHIFT 3
|
|
#define MAX77675_STEP_SZ_SBB0_BIT BIT(2)
|
|
#define MAX77675_STEP_SZ_SBB0_SHIFT 2
|
|
#define MAX77675_DRV_SBB_MASK GENMASK(1, 0)
|
|
#define MAX77675_DRV_SBB_SHIFT 0
|
|
|
|
/* CNFG_SBB0_A (0x08) bits and shifts */
|
|
#define MAX77675_TV_SBB0_MASK GENMASK(7, 0)
|
|
#define MAX77675_TV_SBB0_SHIFT 0
|
|
|
|
/* CNFG_SBB0_B (0x09) bits and shifts */
|
|
#define MAX77675_ADE_SBB0_BIT BIT(3)
|
|
#define MAX77675_ADE_SBB0_SHIFT 3
|
|
#define MAX77675_EN_SBB0_MASK GENMASK(2, 0)
|
|
#define MAX77675_EN_SBB0_SHIFT 0
|
|
|
|
/* CNFG_SBB1_A (0x0A) bits and shifts */
|
|
#define MAX77675_TV_SBB1_MASK GENMASK(7, 0)
|
|
#define MAX77675_TV_SBB1_SHIFT 0
|
|
|
|
/* CNFG_SBB1_B (0x0B) bits and shifts */
|
|
#define MAX77675_ADE_SBB1_BIT BIT(3)
|
|
#define MAX77675_ADE_SBB1_SHIFT 3
|
|
#define MAX77675_EN_SBB1_MASK GENMASK(2, 0)
|
|
#define MAX77675_EN_SBB1_SHIFT 0
|
|
|
|
/* CNFG_SBB2_A (0x0C) bits and shifts */
|
|
#define MAX77675_TV_SBB2_MASK GENMASK(7, 0)
|
|
#define MAX77675_TV_SBB2_SHIFT 0
|
|
|
|
/* CNFG_SBB2_B (0x0D) bits and shifts */
|
|
#define MAX77675_ADE_SBB2_BIT BIT(3)
|
|
#define MAX77675_ADE_SBB2_SHIFT 3
|
|
#define MAX77675_EN_SBB2_MASK GENMASK(2, 0)
|
|
#define MAX77675_EN_SBB2_SHIFT 0
|
|
|
|
/* CNFG_SBB3_A (0x0E) bits and shifts */
|
|
#define MAX77675_TV_SBB3_MASK GENMASK(7, 0)
|
|
#define MAX77675_TV_SBB3_SHIFT 0
|
|
|
|
/* CNFG_SBB3_B (0x0F) bits and shifts */
|
|
#define MAX77675_ADE_SBB3_BIT BIT(3)
|
|
#define MAX77675_ADE_SBB3_SHIFT 3
|
|
#define MAX77675_EN_SBB3_MASK GENMASK(2, 0)
|
|
#define MAX77675_EN_SBB3_SHIFT 0
|
|
|
|
#define MAX77675_EN_SBB_MASK GENMASK(2, 0)
|
|
|
|
/* CNFG_SBB_TOP_B (0x10) bits and shifts */
|
|
#define MAX77675_DVS_SLEW_BIT BIT(5)
|
|
#define MAX77675_DVS_SLEW_SHIFT 5
|
|
#define MAX77675_LAT_MODE_BIT BIT(4)
|
|
#define MAX77675_LAT_MODE_SHIFT 4
|
|
#define MAX77675_SR_SBB3_BIT BIT(3)
|
|
#define MAX77675_SR_SBB3_SHIFT 3
|
|
#define MAX77675_SR_SBB2_BIT BIT(2)
|
|
#define MAX77675_SR_SBB2_SHIFT 2
|
|
#define MAX77675_SR_SBB1_BIT BIT(1)
|
|
#define MAX77675_SR_SBB1_SHIFT 1
|
|
#define MAX77675_SR_SBB0_BIT BIT(0)
|
|
#define MAX77675_SR_SBB0_SHIFT 0
|
|
|
|
#define MAX77675_MAX_REGISTER 0x10
|
|
|
|
/* Common minimum voltage (in microvolts) */
|
|
#define MAX77675_MIN_UV 500000 // 500 mV
|
|
|
|
/* Voltage step configuration for 25mV mode */
|
|
#define MAX77675_STEP_25MV 25000 // Step size: 25 mV
|
|
#define MAX77675_MAX_UV_25MV 5500000 // Max voltage: 5.5 V
|
|
#define MAX77675_NUM_LEVELS_25MV 201 // levels = (5500mV - 500mV) / 25mV + 1
|
|
|
|
/* Voltage step configuration for 12.5mV mode */
|
|
#define MAX77675_STEP_12_5MV 12500 // Step size: 12.5 mV
|
|
#define MAX77675_MAX_UV_12_5MV 3687500 // Max voltage: 3.6875 V
|
|
#define MAX77675_NUM_LEVELS_12_5MV 255 // levels = (3687.5mV - 500mV) / 12.5mV + 1
|
|
|
|
#define MAX77675_ENABLE_OFF 0x04
|
|
#define MAX77675_ENABLE_ON 0x06
|
|
|
|
#define MAX77675_REGULATOR_AD_OFF 0x00
|
|
#define MAX77675_REGULATOR_AD_ON BIT(3)
|
|
|
|
/* FPS source */
|
|
#define MAX77675_FPS_SLOT_0 0x0
|
|
#define MAX77675_FPS_SLOT_1 0x1
|
|
#define MAX77675_FPS_SLOT_2 0x2
|
|
#define MAX77675_FPS_SLOT_3 0x3
|
|
#define MAX77675_FPS_DEF 0x4
|
|
|
|
/* nEN Manual Reset Time Configuration (MRT) */
|
|
#define MAX77675_MRT_4S 0x0
|
|
#define MAX77675_MRT_8S 0x1
|
|
#define MAX77675_MRT_12S 0x2
|
|
#define MAX77675_MRT_16S 0x3
|
|
|
|
/* nEN Mode Configuration */
|
|
#define MAX77675_EN_PUSH_BUTTON 0x0
|
|
#define MAX77675_EN_SLIDE_SWITCH 0x1
|
|
#define MAX77675_EN_LOGIC 0x2
|
|
|
|
/* Debounce Timer Enable (DBEN_nEN) */
|
|
#define MAX77675_DBEN_100US 0x0
|
|
#define MAX77675_DBEN_30000US 0x1
|
|
|
|
/* Rising slew rate control for SBB0 when ramping up */
|
|
#define MAX77675_SR_2MV_PER_US 0x0 // 2 mV/us
|
|
#define MAX77675_SR_USE_DVS 0x1 // Use DVS slew rate setting (adi,dvs-slew-rate)
|
|
|
|
/* Latency Mode */
|
|
#define MAX77675_HIGH_LATENCY_MODE 0x0 // High latency, low quiescent current (~100us)
|
|
#define MAX77675_LOW_LATENCY_MODE 0x1 // Low latency, high quiescent current (~10us)
|
|
|
|
/* Dynamic Voltage Scaling (DVS) Slew Rate */
|
|
#define MAX77675_DVS_SLEW_5MV_PER_US 0x0 // 5 mV/us
|
|
#define MAX77675_DVS_SLEW_10MV_PER_US 0x1 // 10 mV/us
|
|
|
|
/* SIMO Buck-Boost Drive Strength (All Channels) */
|
|
#define MAX77675_DRV_SBB_STRENGTH_MAX 0x0 // Maximum drive strength (~0.6 ns transition time)
|
|
#define MAX77675_DRV_SBB_STRENGTH_HIGH 0x1 // High drive strength (~1.2 ns transition time)
|
|
#define MAX77675_DRV_SBB_STRENGTH_LOW 0x2 // Low drive strength (~1.8 ns transition time)
|
|
#define MAX77675_DRV_SBB_STRENGTH_MIN 0x3 // Minimum drive strength (~8 ns transition time)
|
|
|
|
/* Regulator ID enumeration */
|
|
enum max77675_regulator_id {
|
|
MAX77675_ID_SBB0 = 0,
|
|
MAX77675_ID_SBB1,
|
|
MAX77675_ID_SBB2,
|
|
MAX77675_ID_SBB3,
|
|
MAX77675_ID_NUM_MAX,
|
|
};
|
|
|
|
struct max77675_regulator_sbb_setting {
|
|
u8 fps_slot;
|
|
bool fixed_slew_rate;
|
|
};
|
|
|
|
struct max77675_config {
|
|
u8 en_mode;
|
|
u8 voltage_change_latency;
|
|
u8 drv_sbb_strength;
|
|
u8 dvs_slew_rate;
|
|
u8 debounce_time;
|
|
u8 manual_reset_time;
|
|
bool en_pullup_disable;
|
|
bool bias_low_power_request;
|
|
bool simo_ldo_always_on;
|
|
};
|
|
|
|
struct max77675_regulator {
|
|
struct device *dev;
|
|
struct regmap *regmap;
|
|
struct max77675_config config;
|
|
struct max77675_regulator_sbb_setting sbb_setting[MAX77675_ID_NUM_MAX];
|
|
};
|
|
|
|
static int max77675_regulator_get_fps_src(struct max77675_regulator *maxreg, int id)
|
|
{
|
|
unsigned int reg_addr;
|
|
unsigned int val;
|
|
int ret;
|
|
|
|
switch (id) {
|
|
case MAX77675_ID_SBB0:
|
|
reg_addr = MAX77675_REG_CNFG_SBB0_B;
|
|
break;
|
|
case MAX77675_ID_SBB1:
|
|
reg_addr = MAX77675_REG_CNFG_SBB1_B;
|
|
break;
|
|
case MAX77675_ID_SBB2:
|
|
reg_addr = MAX77675_REG_CNFG_SBB2_B;
|
|
break;
|
|
case MAX77675_ID_SBB3:
|
|
reg_addr = MAX77675_REG_CNFG_SBB3_B;
|
|
break;
|
|
default:
|
|
dev_err(maxreg->dev, "Invalid regulator id: %d\n", id);
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = regmap_read(maxreg->regmap, reg_addr, &val);
|
|
if (ret < 0) {
|
|
dev_err(maxreg->dev, "Failed to read FPS source (reg 0x%02x): %d\n",
|
|
reg_addr, ret);
|
|
return ret;
|
|
}
|
|
|
|
return FIELD_GET(MAX77675_EN_SBB_MASK, val);
|
|
}
|
|
|
|
static int max77675_regulator_set_fps_src(struct max77675_regulator *maxreg, int id, u8 fps_src)
|
|
{
|
|
unsigned int reg_addr;
|
|
|
|
switch (id) {
|
|
case MAX77675_ID_SBB0:
|
|
reg_addr = MAX77675_REG_CNFG_SBB0_B;
|
|
break;
|
|
case MAX77675_ID_SBB1:
|
|
reg_addr = MAX77675_REG_CNFG_SBB1_B;
|
|
break;
|
|
case MAX77675_ID_SBB2:
|
|
reg_addr = MAX77675_REG_CNFG_SBB2_B;
|
|
break;
|
|
case MAX77675_ID_SBB3:
|
|
reg_addr = MAX77675_REG_CNFG_SBB3_B;
|
|
break;
|
|
default:
|
|
dev_err(maxreg->dev, "Invalid regulator id: %d\n", id);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return regmap_update_bits(maxreg->regmap, reg_addr, MAX77675_EN_SBB_MASK, fps_src);
|
|
}
|
|
|
|
static int max77675_set_sbb_slew_rate_fixed(struct max77675_regulator *maxreg, int id, bool fixed)
|
|
{
|
|
u8 mask, value;
|
|
u8 slew_src_ctrl_bit = fixed ? 0 : 1;
|
|
|
|
switch (id) {
|
|
case MAX77675_ID_SBB0:
|
|
mask = MAX77675_SR_SBB0_BIT;
|
|
value = FIELD_PREP(MAX77675_SR_SBB0_BIT, slew_src_ctrl_bit);
|
|
break;
|
|
|
|
case MAX77675_ID_SBB1:
|
|
mask = MAX77675_SR_SBB1_BIT;
|
|
value = FIELD_PREP(MAX77675_SR_SBB1_BIT, slew_src_ctrl_bit);
|
|
break;
|
|
|
|
case MAX77675_ID_SBB2:
|
|
mask = MAX77675_SR_SBB2_BIT;
|
|
value = FIELD_PREP(MAX77675_SR_SBB2_BIT, slew_src_ctrl_bit);
|
|
break;
|
|
|
|
case MAX77675_ID_SBB3:
|
|
mask = MAX77675_SR_SBB3_BIT;
|
|
value = FIELD_PREP(MAX77675_SR_SBB3_BIT, slew_src_ctrl_bit);
|
|
break;
|
|
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
return regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_SBB_TOP_B, mask, value);
|
|
}
|
|
|
|
static int max77675_init_regulator(struct max77675_regulator *maxreg, int id)
|
|
{
|
|
struct max77675_regulator_sbb_setting *sbb_setting = &maxreg->sbb_setting[id];
|
|
int ret;
|
|
|
|
if (sbb_setting->fps_slot == MAX77675_FPS_DEF) {
|
|
ret = max77675_regulator_get_fps_src(maxreg, id);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
sbb_setting->fps_slot = ret;
|
|
} else {
|
|
ret = max77675_regulator_set_fps_src(maxreg, id, sbb_setting->fps_slot);
|
|
if (ret < 0)
|
|
return ret;
|
|
}
|
|
|
|
ret = max77675_set_sbb_slew_rate_fixed(maxreg, id, sbb_setting->fixed_slew_rate);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int max77675_of_parse_cb(struct device_node *np,
|
|
const struct regulator_desc *desc,
|
|
struct regulator_config *config)
|
|
{
|
|
struct max77675_regulator *maxreg = config->driver_data;
|
|
struct max77675_regulator_sbb_setting *sbb_setting = &maxreg->sbb_setting[desc->id];
|
|
static const char * const fps_slots[] = { "slot0", "slot1", "slot2", "slot3", "default" };
|
|
const char *fps_str;
|
|
int slot;
|
|
|
|
/* Parse FPS slot from DT */
|
|
if (of_property_read_string(np, "adi,fps-slot", &fps_str)) {
|
|
/* Property not set, use default */
|
|
sbb_setting->fps_slot = MAX77675_FPS_DEF;
|
|
} else {
|
|
/* Match string to index */
|
|
slot = match_string(fps_slots, ARRAY_SIZE(fps_slots), fps_str);
|
|
if (slot < 0) {
|
|
dev_dbg(maxreg->dev, "Invalid fps-slot '%s', using default\n", fps_str);
|
|
sbb_setting->fps_slot = MAX77675_FPS_DEF;
|
|
} else {
|
|
sbb_setting->fps_slot = slot;
|
|
}
|
|
}
|
|
|
|
/* Parse slew rate control source */
|
|
sbb_setting->fixed_slew_rate = of_property_read_bool(np, "adi,fixed-slew-rate");
|
|
|
|
/* Apply parsed configuration */
|
|
return max77675_init_regulator(maxreg, desc->id);
|
|
}
|
|
|
|
static int max77675_get_error_flags(struct regulator_dev *rdev, unsigned int *flags)
|
|
{
|
|
struct max77675_regulator *maxreg = rdev_get_drvdata(rdev);
|
|
unsigned int int_flags;
|
|
int id = rdev_get_id(rdev);
|
|
int ret;
|
|
|
|
ret = regmap_read(maxreg->regmap, MAX77675_REG_INT_GLBL, &int_flags);
|
|
if (ret) {
|
|
dev_err(maxreg->dev, "Failed to read INT_GLBL: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
*flags = 0;
|
|
|
|
switch (id) {
|
|
case MAX77675_ID_SBB0:
|
|
if (int_flags & MAX77675_INT_SBB0_F_BIT)
|
|
*flags |= REGULATOR_ERROR_FAIL;
|
|
break;
|
|
case MAX77675_ID_SBB1:
|
|
if (int_flags & MAX77675_INT_SBB1_F_BIT)
|
|
*flags |= REGULATOR_ERROR_FAIL;
|
|
break;
|
|
case MAX77675_ID_SBB2:
|
|
if (int_flags & MAX77675_INT_SBB2_F_BIT)
|
|
*flags |= REGULATOR_ERROR_FAIL;
|
|
break;
|
|
case MAX77675_ID_SBB3:
|
|
if (int_flags & MAX77675_INT_SBB3_F_BIT)
|
|
*flags |= REGULATOR_ERROR_FAIL;
|
|
break;
|
|
default:
|
|
dev_warn(maxreg->dev, "Unsupported regulator ID: %d\n", id);
|
|
break;
|
|
}
|
|
|
|
if (int_flags & MAX77675_INT_TJAL2_R_BIT) {
|
|
/* TJAL2 interrupt: Over-temperature condition (above 120 degree) */
|
|
*flags |= REGULATOR_ERROR_OVER_TEMP;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct regulator_ops max77675_regulator_ops = {
|
|
.list_voltage = regulator_list_voltage_linear,
|
|
.enable = regulator_enable_regmap,
|
|
.disable = regulator_disable_regmap,
|
|
.is_enabled = regulator_is_enabled_regmap,
|
|
.map_voltage = regulator_map_voltage_linear,
|
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
|
.set_active_discharge = regulator_set_active_discharge_regmap,
|
|
.get_error_flags = max77675_get_error_flags,
|
|
};
|
|
|
|
static struct regulator_desc max77675_regulators[MAX77675_ID_NUM_MAX] = {
|
|
{
|
|
.name = "sbb0",
|
|
.of_match = of_match_ptr("sbb0"),
|
|
.regulators_node = of_match_ptr("regulators"),
|
|
.of_parse_cb = max77675_of_parse_cb,
|
|
.id = MAX77675_ID_SBB0,
|
|
.ops = &max77675_regulator_ops,
|
|
.type = REGULATOR_VOLTAGE,
|
|
.owner = THIS_MODULE,
|
|
.n_voltages = MAX77675_NUM_LEVELS_25MV,
|
|
.min_uV = MAX77675_MIN_UV,
|
|
.uV_step = MAX77675_STEP_25MV,
|
|
.vsel_reg = MAX77675_REG_CNFG_SBB0_A,
|
|
.vsel_mask = MAX77675_TV_SBB0_MASK,
|
|
.enable_reg = MAX77675_REG_CNFG_SBB0_B,
|
|
.enable_mask = MAX77675_EN_SBB0_MASK,
|
|
.enable_val = MAX77675_ENABLE_ON,
|
|
.disable_val = MAX77675_ENABLE_OFF,
|
|
.active_discharge_off = MAX77675_REGULATOR_AD_OFF,
|
|
.active_discharge_on = MAX77675_REGULATOR_AD_ON,
|
|
.active_discharge_mask = MAX77675_ADE_SBB0_BIT,
|
|
.active_discharge_reg = MAX77675_REG_CNFG_SBB0_B,
|
|
},
|
|
{
|
|
.name = "sbb1",
|
|
.of_match = of_match_ptr("sbb1"),
|
|
.regulators_node = of_match_ptr("regulators"),
|
|
.of_parse_cb = max77675_of_parse_cb,
|
|
.id = MAX77675_ID_SBB1,
|
|
.ops = &max77675_regulator_ops,
|
|
.type = REGULATOR_VOLTAGE,
|
|
.owner = THIS_MODULE,
|
|
.n_voltages = MAX77675_NUM_LEVELS_25MV,
|
|
.min_uV = MAX77675_MIN_UV,
|
|
.uV_step = MAX77675_STEP_25MV,
|
|
.vsel_reg = MAX77675_REG_CNFG_SBB1_A,
|
|
.vsel_mask = MAX77675_TV_SBB1_MASK,
|
|
.enable_reg = MAX77675_REG_CNFG_SBB1_B,
|
|
.enable_mask = MAX77675_EN_SBB1_MASK,
|
|
.enable_val = MAX77675_ENABLE_ON,
|
|
.disable_val = MAX77675_ENABLE_OFF,
|
|
.active_discharge_off = MAX77675_REGULATOR_AD_OFF,
|
|
.active_discharge_on = MAX77675_REGULATOR_AD_ON,
|
|
.active_discharge_mask = MAX77675_ADE_SBB1_BIT,
|
|
.active_discharge_reg = MAX77675_REG_CNFG_SBB1_B,
|
|
},
|
|
{
|
|
.name = "sbb2",
|
|
.of_match = of_match_ptr("sbb2"),
|
|
.regulators_node = of_match_ptr("regulators"),
|
|
.of_parse_cb = max77675_of_parse_cb,
|
|
.id = MAX77675_ID_SBB2,
|
|
.ops = &max77675_regulator_ops,
|
|
.type = REGULATOR_VOLTAGE,
|
|
.owner = THIS_MODULE,
|
|
.n_voltages = MAX77675_NUM_LEVELS_25MV,
|
|
.min_uV = MAX77675_MIN_UV,
|
|
.uV_step = MAX77675_STEP_25MV,
|
|
.vsel_reg = MAX77675_REG_CNFG_SBB2_A,
|
|
.vsel_mask = MAX77675_TV_SBB2_MASK,
|
|
.enable_reg = MAX77675_REG_CNFG_SBB2_B,
|
|
.enable_mask = MAX77675_EN_SBB2_MASK,
|
|
.enable_val = MAX77675_ENABLE_ON,
|
|
.disable_val = MAX77675_ENABLE_OFF,
|
|
.active_discharge_off = MAX77675_REGULATOR_AD_OFF,
|
|
.active_discharge_on = MAX77675_REGULATOR_AD_ON,
|
|
.active_discharge_mask = MAX77675_ADE_SBB2_BIT,
|
|
.active_discharge_reg = MAX77675_REG_CNFG_SBB2_B,
|
|
},
|
|
{
|
|
.name = "sbb3",
|
|
.of_match = of_match_ptr("sbb3"),
|
|
.regulators_node = of_match_ptr("regulators"),
|
|
.of_parse_cb = max77675_of_parse_cb,
|
|
.id = MAX77675_ID_SBB3,
|
|
.ops = &max77675_regulator_ops,
|
|
.type = REGULATOR_VOLTAGE,
|
|
.owner = THIS_MODULE,
|
|
.n_voltages = MAX77675_NUM_LEVELS_25MV,
|
|
.min_uV = MAX77675_MIN_UV,
|
|
.uV_step = MAX77675_STEP_25MV,
|
|
.vsel_reg = MAX77675_REG_CNFG_SBB3_A,
|
|
.vsel_mask = MAX77675_TV_SBB3_MASK,
|
|
.enable_reg = MAX77675_REG_CNFG_SBB3_B,
|
|
.enable_mask = MAX77675_EN_SBB3_MASK,
|
|
.enable_val = MAX77675_ENABLE_ON,
|
|
.disable_val = MAX77675_ENABLE_OFF,
|
|
.active_discharge_off = MAX77675_REGULATOR_AD_OFF,
|
|
.active_discharge_on = MAX77675_REGULATOR_AD_ON,
|
|
.active_discharge_mask = MAX77675_ADE_SBB3_BIT,
|
|
.active_discharge_reg = MAX77675_REG_CNFG_SBB3_B,
|
|
},
|
|
};
|
|
|
|
static bool max77675_volatile_reg(struct device *dev, unsigned int reg)
|
|
{
|
|
switch (reg) {
|
|
case MAX77675_REG_CNFG_GLBL_B:
|
|
/* This register can be updated by an internal state machine */
|
|
case MAX77675_REG_INT_GLBL:
|
|
case MAX77675_REG_STAT_GLBL:
|
|
case MAX77675_REG_ERCF_GLBL:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static const struct regmap_config max77675_regmap_config = {
|
|
.reg_bits = 8,
|
|
.val_bits = 8,
|
|
.max_register = MAX77675_MAX_REGISTER,
|
|
.cache_type = REGCACHE_MAPLE,
|
|
.volatile_reg = max77675_volatile_reg,
|
|
};
|
|
|
|
static int max77675_apply_config(struct max77675_regulator *maxreg)
|
|
{
|
|
const struct max77675_config *cfg = &maxreg->config;
|
|
int ret;
|
|
|
|
/* Set EN pin mode */
|
|
ret = regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_GLBL_A,
|
|
MAX77675_EN_MODE_MASK,
|
|
FIELD_PREP(MAX77675_EN_MODE_MASK, cfg->en_mode));
|
|
if (ret) {
|
|
dev_err(maxreg->dev, "Failed to set EN mode: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/* Set the latency between output voltage change and SBBx voltage ramp start */
|
|
ret = regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_SBB_TOP_B,
|
|
MAX77675_LAT_MODE_BIT,
|
|
FIELD_PREP(MAX77675_LAT_MODE_BIT, cfg->voltage_change_latency));
|
|
if (ret) {
|
|
dev_err(maxreg->dev, "Failed to set latency mode: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/* Set drive strength */
|
|
ret = regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_SBB_TOP_A,
|
|
MAX77675_DRV_SBB_MASK,
|
|
FIELD_PREP(MAX77675_DRV_SBB_MASK, cfg->drv_sbb_strength));
|
|
if (ret) {
|
|
dev_err(maxreg->dev, "Failed to set drive strength: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/* Set DVS slew rate */
|
|
ret = regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_SBB_TOP_B,
|
|
MAX77675_DVS_SLEW_BIT,
|
|
FIELD_PREP(MAX77675_DVS_SLEW_BIT, cfg->dvs_slew_rate));
|
|
if (ret) {
|
|
dev_err(maxreg->dev, "Failed to set DVS slew rate: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/* Set debounce time for EN pin */
|
|
ret = regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_GLBL_A,
|
|
MAX77675_DBEN_EN_BIT,
|
|
FIELD_PREP(MAX77675_DBEN_EN_BIT, cfg->debounce_time));
|
|
if (ret) {
|
|
dev_err(maxreg->dev, "Failed to set EN debounce time: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/* Set manual reset time (MRT) for EN pin */
|
|
ret = regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_GLBL_A,
|
|
MAX77675_MRT_MASK,
|
|
FIELD_PREP(MAX77675_MRT_MASK, cfg->manual_reset_time));
|
|
if (ret) {
|
|
dev_err(maxreg->dev, "Failed to set manual reset time: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/* Enable or disable internal pull-up resistor on EN pin */
|
|
ret = regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_GLBL_A,
|
|
MAX77675_PU_DIS_BIT,
|
|
FIELD_PREP(MAX77675_PU_DIS_BIT, cfg->en_pullup_disable));
|
|
if (ret) {
|
|
dev_err(maxreg->dev, "Failed to set EN pull-up disable: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/* Request main bias to enter low-power mode */
|
|
ret = regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_GLBL_A,
|
|
MAX77675_BIAS_LPM_BIT,
|
|
FIELD_PREP(MAX77675_BIAS_LPM_BIT, cfg->bias_low_power_request));
|
|
if (ret) {
|
|
dev_err(maxreg->dev, "Failed to set bias low-power request: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/* Force SIMO internal LDO to always supply 1.8V */
|
|
ret = regmap_update_bits(maxreg->regmap, MAX77675_REG_CNFG_GLBL_A,
|
|
MAX77675_SIMO_CH_DIS_BIT,
|
|
FIELD_PREP(MAX77675_SIMO_CH_DIS_BIT, cfg->simo_ldo_always_on));
|
|
if (ret) {
|
|
dev_err(maxreg->dev, "Failed to set SIMO internal LDO always-on: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int max77675_parse_en_mode(struct device *dev,
|
|
struct device_node *np,
|
|
u8 *en_mode)
|
|
{
|
|
static const char * const en_modes[] = {"push-button", "slide-switch", "logic"};
|
|
const char *str;
|
|
int index;
|
|
|
|
*en_mode = MAX77675_EN_SLIDE_SWITCH;
|
|
|
|
if (of_property_read_string(np, "adi,en-mode", &str))
|
|
return 0;
|
|
|
|
index = match_string(en_modes, ARRAY_SIZE(en_modes), str);
|
|
if (index < 0) {
|
|
dev_err(dev, "Invalid 'adi,en-mode' value '%s'\n", str);
|
|
return -EINVAL;
|
|
}
|
|
|
|
*en_mode = index;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int max77675_parse_voltage_change_latency(struct device *dev,
|
|
struct device_node *np,
|
|
u8 *latency_mode)
|
|
{
|
|
u32 val;
|
|
|
|
*latency_mode = MAX77675_HIGH_LATENCY_MODE;
|
|
|
|
if (!of_property_read_u32(np, "adi,voltage-change-latency-us", &val)) {
|
|
switch (val) {
|
|
case 10:
|
|
*latency_mode = MAX77675_LOW_LATENCY_MODE;
|
|
break;
|
|
case 100:
|
|
*latency_mode = MAX77675_HIGH_LATENCY_MODE;
|
|
break;
|
|
default:
|
|
dev_err(dev, "Invalid voltage-change-latency-us value: %u\n", val);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int max77675_parse_manual_reset_time(struct device *dev,
|
|
struct device_node *np,
|
|
u8 *reset_time)
|
|
{
|
|
u32 val;
|
|
|
|
*reset_time = MAX77675_MRT_4S;
|
|
|
|
if (!of_property_read_u32(np, "reset-time-sec", &val)) {
|
|
switch (val) {
|
|
case 4:
|
|
*reset_time = MAX77675_MRT_4S;
|
|
break;
|
|
case 8:
|
|
*reset_time = MAX77675_MRT_8S;
|
|
break;
|
|
case 12:
|
|
*reset_time = MAX77675_MRT_12S;
|
|
break;
|
|
case 16:
|
|
*reset_time = MAX77675_MRT_16S;
|
|
break;
|
|
default:
|
|
dev_err(dev, "Invalid reset-time-sec value: %u\n", val);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int max77675_parse_dvs_slew_rate(struct device *dev, struct device_node *np, u8 *slew_rate)
|
|
{
|
|
u32 val;
|
|
|
|
/* Set default: 5 mV/us */
|
|
*slew_rate = MAX77675_DVS_SLEW_5MV_PER_US;
|
|
|
|
if (!of_property_read_u32(np, "adi,dvs-slew-rate-mv-per-us", &val)) {
|
|
switch (val) {
|
|
case 5:
|
|
*slew_rate = MAX77675_DVS_SLEW_5MV_PER_US;
|
|
break;
|
|
case 10:
|
|
*slew_rate = MAX77675_DVS_SLEW_10MV_PER_US;
|
|
break;
|
|
default:
|
|
dev_err(dev, "Invalid dvs-slew-rate-mv-per-us value: %u\n", val);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int max77675_parse_drv_sbb_strength(struct device *dev, struct device_node *np, u8 *strength)
|
|
{
|
|
static const char * const strength_names[] = {"max", "high", "low", "min"};
|
|
const char *str;
|
|
int index;
|
|
|
|
/* Set default: maximum drive strength */
|
|
*strength = MAX77675_DRV_SBB_STRENGTH_MAX;
|
|
|
|
if (of_property_read_string(np, "adi,drv-sbb-strength", &str))
|
|
return 0;
|
|
|
|
index = match_string(strength_names, ARRAY_SIZE(strength_names), str);
|
|
if (index < 0) {
|
|
dev_err(dev, "Invalid 'adi,drv-sbb-strength' value: '%s'\n", str);
|
|
return -EINVAL;
|
|
}
|
|
|
|
*strength = index;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int max77675_parse_debounce_time_us(struct device *dev,
|
|
struct device_node *np,
|
|
u8 *debounce_time)
|
|
{
|
|
u32 val;
|
|
|
|
*debounce_time = MAX77675_DBEN_100US;
|
|
|
|
if (!of_property_read_u32(np, "input-debounce", &val)) {
|
|
switch (val) {
|
|
case 100:
|
|
*debounce_time = MAX77675_DBEN_100US;
|
|
break;
|
|
case 30000:
|
|
*debounce_time = MAX77675_DBEN_30000US;
|
|
break;
|
|
default:
|
|
dev_err(dev, "Invalid input-debounce value: %u\n", val);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int max77675_parse_config(struct max77675_regulator *maxreg)
|
|
{
|
|
struct device_node *np = maxreg->dev->of_node;
|
|
struct max77675_config *cfg = &maxreg->config;
|
|
int ret;
|
|
|
|
/* EN pin mode */
|
|
ret = max77675_parse_en_mode(maxreg->dev, np, &cfg->en_mode);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
/* voltage change latency */
|
|
ret = max77675_parse_voltage_change_latency(maxreg->dev, np, &cfg->voltage_change_latency);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
/* drive strength */
|
|
ret = max77675_parse_drv_sbb_strength(maxreg->dev, np, &cfg->drv_sbb_strength);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
/* dvs slew rate */
|
|
ret = max77675_parse_dvs_slew_rate(maxreg->dev, np, &cfg->dvs_slew_rate);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
/* Debounce time for EN pin */
|
|
ret = max77675_parse_debounce_time_us(maxreg->dev, np, &cfg->debounce_time);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
/* Manual reset time for EN pin */
|
|
ret = max77675_parse_manual_reset_time(maxreg->dev, np, &cfg->manual_reset_time);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
/* Disable internal pull-up resistor on EN pin */
|
|
cfg->en_pullup_disable = of_property_read_bool(np, "bias-disable");
|
|
|
|
/* Request low-power mode for main bias */
|
|
cfg->bias_low_power_request = of_property_read_bool(np, "adi,bias-low-power-request");
|
|
|
|
/* Force internal LDO to always supply 1.8V */
|
|
cfg->simo_ldo_always_on = of_property_read_bool(np, "adi,simo-ldo-always-on");
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int max77675_init_event(struct max77675_regulator *maxreg)
|
|
{
|
|
unsigned int ercflag, int_glbl;
|
|
int ret;
|
|
|
|
ret = regmap_read(maxreg->regmap, MAX77675_REG_ERCF_GLBL, &ercflag);
|
|
if (ret) {
|
|
dev_err(maxreg->dev, "Failed to read CID register: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = regmap_read(maxreg->regmap, MAX77675_REG_INT_GLBL, &int_glbl);
|
|
if (ret) {
|
|
dev_err(maxreg->dev, "Failed to read INT_GLBL register: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
if (ercflag & MAX77675_SFT_CRST_F_BIT)
|
|
dev_dbg(maxreg->dev, "Software Cold Reset Flag is set\n");
|
|
|
|
if (ercflag & MAX77675_SFT_OFF_F_BIT)
|
|
dev_dbg(maxreg->dev, "Software Off Flag is set\n");
|
|
|
|
if (ercflag & MAX77675_MRST_BIT)
|
|
dev_dbg(maxreg->dev, "Manual Reset Timer Flag is set\n");
|
|
|
|
if (ercflag & MAX77675_UVLO_BIT)
|
|
dev_dbg(maxreg->dev, "Undervoltage Lockout Flag is set\n");
|
|
|
|
if (ercflag & MAX77675_OVLO_BIT)
|
|
dev_dbg(maxreg->dev, "Overvoltage Lockout Flag is set\n");
|
|
|
|
if (ercflag & MAX77675_TOVLD_BIT)
|
|
dev_dbg(maxreg->dev, "Thermal Overload Flag is set\n");
|
|
|
|
if (int_glbl & MAX77675_INT_SBB3_F_BIT)
|
|
dev_dbg(maxreg->dev, "SBB3 Channel Fault Interrupt occurred\n");
|
|
|
|
if (int_glbl & MAX77675_INT_SBB2_F_BIT)
|
|
dev_dbg(maxreg->dev, "SBB2 Channel Fault Interrupt occurred\n");
|
|
|
|
if (int_glbl & MAX77675_INT_SBB1_F_BIT)
|
|
dev_dbg(maxreg->dev, "SBB1 Channel Fault Interrupt occurred\n");
|
|
|
|
if (int_glbl & MAX77675_INT_SBB0_F_BIT)
|
|
dev_dbg(maxreg->dev, "SBB0 Channel Fault Interrupt occurred\n");
|
|
|
|
if (int_glbl & MAX77675_INT_TJAL2_R_BIT)
|
|
dev_dbg(maxreg->dev, "Thermal Alarm 2 Rising Interrupt occurred\n");
|
|
|
|
if (int_glbl & MAX77675_INT_TJAL1_R_BIT)
|
|
dev_dbg(maxreg->dev, "Thermal Alarm 1 Rising Interrupt occurred\n");
|
|
|
|
if (int_glbl & MAX77675_INT_EN_R_BIT)
|
|
dev_dbg(maxreg->dev, "nEN Rising Edge Interrupt occurred\n");
|
|
|
|
if (int_glbl & MAX77675_INT_EN_F_BIT)
|
|
dev_dbg(maxreg->dev, "nEN Falling Edge Interrupt occurred\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int max77675_regulator_probe(struct i2c_client *client)
|
|
{
|
|
struct max77675_regulator *maxreg;
|
|
struct regulator_config config = {};
|
|
int i, ret;
|
|
|
|
maxreg = devm_kzalloc(&client->dev, sizeof(*maxreg), GFP_KERNEL);
|
|
if (!maxreg)
|
|
return -ENOMEM;
|
|
|
|
maxreg->dev = &client->dev;
|
|
|
|
maxreg->regmap = devm_regmap_init_i2c(client, &max77675_regmap_config);
|
|
if (IS_ERR(maxreg->regmap))
|
|
return dev_err_probe(maxreg->dev,
|
|
PTR_ERR(maxreg->regmap),
|
|
"Failed to init regmap\n");
|
|
|
|
ret = max77675_init_event(maxreg);
|
|
if (ret < 0)
|
|
return dev_err_probe(maxreg->dev, ret, "Failed to init event\n");
|
|
|
|
ret = max77675_parse_config(maxreg);
|
|
if (ret < 0)
|
|
return dev_err_probe(maxreg->dev, ret, "Failed to parse config\n");
|
|
|
|
ret = max77675_apply_config(maxreg);
|
|
if (ret < 0)
|
|
return dev_err_probe(maxreg->dev, ret, "Failed to apply config\n");
|
|
|
|
config.dev = &client->dev;
|
|
config.regmap = maxreg->regmap;
|
|
config.driver_data = maxreg;
|
|
|
|
struct device_node *regulators_np __free(device_node) =
|
|
of_get_child_by_name(client->dev.of_node, "regulators");
|
|
if (!regulators_np) {
|
|
dev_err(maxreg->dev, "No 'regulators' subnode found in DT\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
for (i = 0; i < MAX77675_ID_NUM_MAX; i++) {
|
|
const struct regulator_desc *desc = &max77675_regulators[i];
|
|
struct regulator_dev *rdev;
|
|
|
|
struct device_node *child_np __free(device_node) =
|
|
of_get_child_by_name(regulators_np, desc->name);
|
|
if (!child_np) {
|
|
dev_warn(maxreg->dev, "No DT node for regulator %s\n", desc->name);
|
|
continue;
|
|
}
|
|
|
|
config.of_node = child_np;
|
|
|
|
rdev = devm_regulator_register(&client->dev, desc, &config);
|
|
if (IS_ERR(rdev)) {
|
|
return dev_err_probe(maxreg->dev, PTR_ERR(rdev),
|
|
"Failed to register regulator %d (%s)\n",
|
|
i, desc->name);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct i2c_device_id max77675_i2c_id[] = {
|
|
{ "max77675", 0 },
|
|
{ }
|
|
};
|
|
MODULE_DEVICE_TABLE(i2c, max77675_i2c_id);
|
|
|
|
static const struct of_device_id __maybe_unused max77675_of_match[] = {
|
|
{ .compatible = "adi,max77675", },
|
|
{ }
|
|
};
|
|
MODULE_DEVICE_TABLE(of, max77675_of_match);
|
|
|
|
static struct i2c_driver max77675_regulator_driver = {
|
|
.driver = {
|
|
.name = "max77675",
|
|
.of_match_table = of_match_ptr(max77675_of_match),
|
|
},
|
|
.probe = max77675_regulator_probe,
|
|
.id_table = max77675_i2c_id,
|
|
};
|
|
|
|
module_i2c_driver(max77675_regulator_driver);
|
|
|
|
MODULE_DESCRIPTION("MAX77675 Regulator Driver");
|
|
MODULE_AUTHOR("Joan Na <joan.na@analog.com>");
|
|
MODULE_LICENSE("GPL");
|