| /* |
| * Copyright (c) 2023 TOKITA Hiroshi <tokita.hiroshi@fujitsu.com> |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #define DT_DRV_COMPAT raspberrypi_core_supply_regulator |
| |
| #include <zephyr/devicetree.h> |
| #include <zephyr/drivers/regulator.h> |
| #include <zephyr/dt-bindings/regulator/rpi_pico.h> |
| #include <zephyr/sys/linear_range.h> |
| #include <zephyr/toolchain.h> |
| #include <hardware/regs/vreg_and_chip_reset.h> |
| #include <hardware/structs/vreg_and_chip_reset.h> |
| |
| static const struct linear_range core_ranges[] = { |
| LINEAR_RANGE_INIT(800000u, 0u, 0u, 5u), |
| LINEAR_RANGE_INIT(850000u, 50000u, 6u, 15u), |
| }; |
| |
| static const size_t num_core_ranges = ARRAY_SIZE(core_ranges); |
| |
| struct regulator_rpi_pico_config { |
| struct regulator_common_config common; |
| vreg_and_chip_reset_hw_t * const reg; |
| const bool brown_out_detection; |
| const uint32_t brown_out_threshold; |
| }; |
| |
| struct regulator_rpi_pico_data { |
| struct regulator_common_data data; |
| }; |
| |
| /* |
| * APIs |
| */ |
| |
| static unsigned int regulator_rpi_pico_count_voltages(const struct device *dev) |
| { |
| return linear_range_group_values_count(core_ranges, num_core_ranges); |
| } |
| |
| static int regulator_rpi_pico_list_voltage(const struct device *dev, unsigned int idx, |
| int32_t *volt_uv) |
| { |
| return linear_range_group_get_value(core_ranges, num_core_ranges, idx, volt_uv); |
| } |
| |
| static int regulator_rpi_pico_set_voltage(const struct device *dev, int32_t min_uv, int32_t max_uv) |
| { |
| const struct regulator_rpi_pico_config *config = dev->config; |
| uint16_t idx; |
| int ret; |
| |
| ret = linear_range_group_get_win_index(core_ranges, num_core_ranges, min_uv, max_uv, &idx); |
| if (ret < 0) { |
| return ret; |
| } |
| |
| config->reg->vreg = ((config->reg->vreg & ~VREG_AND_CHIP_RESET_VREG_VSEL_BITS) | |
| (idx << VREG_AND_CHIP_RESET_VREG_VSEL_LSB)); |
| |
| return 0; |
| } |
| |
| static int regulator_rpi_pico_get_voltage(const struct device *dev, int32_t *volt_uv) |
| { |
| const struct regulator_rpi_pico_config *config = dev->config; |
| |
| return linear_range_group_get_value( |
| core_ranges, num_core_ranges, |
| ((config->reg->vreg & VREG_AND_CHIP_RESET_VREG_VSEL_BITS) >> |
| VREG_AND_CHIP_RESET_VREG_VSEL_LSB), |
| volt_uv); |
| } |
| |
| static int regulator_rpi_pico_enable(const struct device *dev) |
| { |
| const struct regulator_rpi_pico_config *config = dev->config; |
| |
| config->reg->vreg |= BIT(VREG_AND_CHIP_RESET_VREG_EN_LSB); |
| |
| return 0; |
| } |
| |
| static int regulator_rpi_pico_disable(const struct device *dev) |
| { |
| const struct regulator_rpi_pico_config *config = dev->config; |
| |
| config->reg->vreg &= ~BIT(VREG_AND_CHIP_RESET_VREG_EN_LSB); |
| |
| return 0; |
| } |
| |
| static int regulator_rpi_pico_set_mode(const struct device *dev, regulator_mode_t mode) |
| { |
| const struct regulator_rpi_pico_config *config = dev->config; |
| |
| if (mode & REGULATOR_RPI_PICO_MODE_HI_Z) { |
| config->reg->vreg |= REGULATOR_RPI_PICO_MODE_HI_Z; |
| } else { |
| config->reg->vreg &= (~REGULATOR_RPI_PICO_MODE_HI_Z); |
| } |
| |
| return 0; |
| } |
| |
| static int regulator_rpi_pico_get_mode(const struct device *dev, regulator_mode_t *mode) |
| { |
| const struct regulator_rpi_pico_config *config = dev->config; |
| |
| *mode = (config->reg->vreg & REGULATOR_RPI_PICO_MODE_HI_Z); |
| |
| return 0; |
| } |
| |
| static int regulator_rpi_pico_init(const struct device *dev) |
| { |
| const struct regulator_rpi_pico_config *config = dev->config; |
| |
| if (config->brown_out_detection) { |
| config->reg->bod = |
| (BIT(VREG_AND_CHIP_RESET_BOD_EN_LSB) | |
| (config->brown_out_threshold << VREG_AND_CHIP_RESET_BOD_VSEL_LSB)); |
| } else { |
| config->reg->bod &= ~BIT(VREG_AND_CHIP_RESET_BOD_EN_LSB); |
| } |
| |
| regulator_common_data_init(dev); |
| |
| return regulator_common_init(dev, true); |
| } |
| |
| static const struct regulator_driver_api api = { |
| .enable = regulator_rpi_pico_enable, |
| .disable = regulator_rpi_pico_disable, |
| .count_voltages = regulator_rpi_pico_count_voltages, |
| .list_voltage = regulator_rpi_pico_list_voltage, |
| .set_voltage = regulator_rpi_pico_set_voltage, |
| .get_voltage = regulator_rpi_pico_get_voltage, |
| .set_mode = regulator_rpi_pico_set_mode, |
| .get_mode = regulator_rpi_pico_get_mode, |
| }; |
| |
| #define REGULATOR_RPI_PICO_DEFINE_ALL(inst) \ |
| static struct regulator_rpi_pico_data data_##inst; \ |
| \ |
| static const struct regulator_rpi_pico_config config_##inst = { \ |
| .common = REGULATOR_DT_COMMON_CONFIG_INIT(inst), \ |
| .reg = (vreg_and_chip_reset_hw_t * const)DT_INST_REG_ADDR(inst), \ |
| .brown_out_detection = DT_INST_PROP(inst, raspberrypi_brown_out_detection), \ |
| .brown_out_threshold = DT_INST_ENUM_IDX(inst, raspberrypi_brown_out_threshold), \ |
| }; \ |
| \ |
| DEVICE_DT_INST_DEFINE(inst, regulator_rpi_pico_init, NULL, &data_##inst, &config_##inst, \ |
| POST_KERNEL, CONFIG_REGULATOR_RPI_PICO_INIT_PRIORITY, &api); |
| |
| DT_INST_FOREACH_STATUS_OKAY(REGULATOR_RPI_PICO_DEFINE_ALL) |