// SPDX-License-Identifier: GPL-2.0 // // MCP16502 PMIC driver // // Copyright (C) 2018 Microchip Technology Inc. and its subsidiaries // // Author: Andrei Stefanescu <[email protected]> // // Inspired from tps65086-regulator.c #include <linux/i2c.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> #include <linux/regmap.h> #include <linux/regulator/driver.h> #include <linux/suspend.h> #include <linux/gpio/consumer.h> #define VDD_LOW_SEL … #define VDD_HIGH_SEL … #define MCP16502_FLT … #define MCP16502_DVSR … #define MCP16502_ENS … /* * The PMIC has four sets of registers corresponding to four power modes: * Performance, Active, Low-power, Hibernate. * * Registers: * Each regulator has a register for each power mode. To access a register * for a specific regulator and mode BASE_* and OFFSET_* need to be added. * * Operating modes: * In order for the PMIC to transition to operating modes it has to be * controlled via GPIO lines called LPM and HPM. * * The registers are fully configurable such that you can put all regulators in * a low-power state while the PMIC is in Active mode. They are supposed to be * configured at startup and then simply transition to/from a global low-power * state by setting the GPIO lpm pin high/low. * * This driver keeps the PMIC in Active mode, Low-power state is set for the * regulators by enabling/disabling operating mode (FPWM or Auto PFM). * * The PMIC's Low-power and Hibernate modes are used during standby/suspend. * To enter standby/suspend the PMIC will go to Low-power mode. From there, it * will transition to Hibernate when the PWRHLD line is set to low by the MPU. */ /* * This function is useful for iterating over all regulators and accessing their * registers in a generic way or accessing a regulator device by its id. */ #define MCP16502_REG_BASE(i, r) … #define MCP16502_STAT_BASE(i) … #define MCP16502_OPMODE_ACTIVE … #define MCP16502_OPMODE_LPM … #define MCP16502_OPMODE_HIB … #define MCP16502_MODE_AUTO_PFM … #define MCP16502_MODE_FPWM … #define MCP16502_VSEL … #define MCP16502_EN … #define MCP16502_MODE … #define MCP16502_MIN_REG … #define MCP16502_MAX_REG … /** * enum mcp16502_reg - MCP16502 regulators's registers * @MCP16502_REG_A: active state register * @MCP16502_REG_LPM: low power mode state register * @MCP16502_REG_HIB: hibernate state register * @MCP16502_REG_HPM: high-performance mode register * @MCP16502_REG_SEQ: startup sequence register * @MCP16502_REG_CFG: configuration register */ enum mcp16502_reg { … }; /* Ramp delay (uV/us) for buck1, ldo1, ldo2. */ static const unsigned int mcp16502_ramp_b1l12[] = …; /* Ramp delay (uV/us) for buck2, buck3, buck4. */ static const unsigned int mcp16502_ramp_b234[] = …; static unsigned int mcp16502_of_map_mode(unsigned int mode) { … } #define MCP16502_REGULATOR(_name, _id, _ranges, _ops, _ramp_table) … enum { … }; /* * struct mcp16502 - PMIC representation * @lpm: LPM GPIO descriptor */ struct mcp16502 { … }; /* * mcp16502_gpio_set_mode() - set the GPIO corresponding value * * Used to prepare transitioning into hibernate or resuming from it. */ static void mcp16502_gpio_set_mode(struct mcp16502 *mcp, int mode) { … } /* * mcp16502_get_reg() - get the PMIC's state configuration register for opmode * * @rdev: the regulator whose register we are searching * @opmode: the PMIC's operating mode ACTIVE, Low-power, Hibernate */ static int mcp16502_get_state_reg(struct regulator_dev *rdev, int opmode) { … } /* * mcp16502_get_mode() - return the current operating mode of a regulator * * Note: all functions that are not part of entering/exiting standby/suspend * use the Active mode registers. * * Note: this is different from the PMIC's operatig mode, it is the * MODE bit from the regulator's register. */ static unsigned int mcp16502_get_mode(struct regulator_dev *rdev) { … } /* * _mcp16502_set_mode() - helper for set_mode and set_suspend_mode * * @rdev: the regulator for which we are setting the mode * @mode: the regulator's mode (the one from MODE bit) * @opmode: the PMIC's operating mode: Active/Low-power/Hibernate */ static int _mcp16502_set_mode(struct regulator_dev *rdev, unsigned int mode, unsigned int op_mode) { … } /* * mcp16502_set_mode() - regulator_ops set_mode */ static int mcp16502_set_mode(struct regulator_dev *rdev, unsigned int mode) { … } /* * mcp16502_get_status() - regulator_ops get_status */ static int mcp16502_get_status(struct regulator_dev *rdev) { … } static int mcp16502_set_voltage_time_sel(struct regulator_dev *rdev, unsigned int old_sel, unsigned int new_sel) { … } #ifdef CONFIG_SUSPEND /* * mcp16502_suspend_get_target_reg() - get the reg of the target suspend PMIC * mode */ static int mcp16502_suspend_get_target_reg(struct regulator_dev *rdev) { … } /* * mcp16502_set_suspend_voltage() - regulator_ops set_suspend_voltage */ static int mcp16502_set_suspend_voltage(struct regulator_dev *rdev, int uV) { … } /* * mcp16502_set_suspend_mode() - regulator_ops set_suspend_mode */ static int mcp16502_set_suspend_mode(struct regulator_dev *rdev, unsigned int mode) { … } /* * mcp16502_set_suspend_enable() - regulator_ops set_suspend_enable */ static int mcp16502_set_suspend_enable(struct regulator_dev *rdev) { … } /* * mcp16502_set_suspend_disable() - regulator_ops set_suspend_disable */ static int mcp16502_set_suspend_disable(struct regulator_dev *rdev) { … } #endif /* CONFIG_SUSPEND */ static const struct regulator_ops mcp16502_buck_ops = …; /* * LDOs cannot change operating modes. */ static const struct regulator_ops mcp16502_ldo_ops = …; static const struct of_device_id mcp16502_ids[] = …; MODULE_DEVICE_TABLE(of, mcp16502_ids); static const struct linear_range b1l12_ranges[] = …; static const struct linear_range b234_ranges[] = …; static const struct regulator_desc mcp16502_desc[] = …; static const struct regmap_range mcp16502_ranges[] = …; static const struct regmap_access_table mcp16502_yes_reg_table = …; static const struct regmap_config mcp16502_regmap_config = …; static int mcp16502_probe(struct i2c_client *client) { … } #ifdef CONFIG_PM_SLEEP static int mcp16502_suspend_noirq(struct device *dev) { … } static int mcp16502_resume_noirq(struct device *dev) { … } #endif #ifdef CONFIG_PM static const struct dev_pm_ops mcp16502_pm_ops = …; #endif static const struct i2c_device_id mcp16502_i2c_id[] = …; MODULE_DEVICE_TABLE(i2c, mcp16502_i2c_id); static struct i2c_driver mcp16502_drv = …; module_i2c_driver(…) …; MODULE_LICENSE(…) …; MODULE_DESCRIPTION(…) …; MODULE_AUTHOR(…) …;