diff options
author | 2023-10-10 14:33:42 +0000 | |
---|---|---|
committer | 2023-10-10 14:33:42 +0000 | |
commit | af1a266670d040d2f4083ff309d732d648afba2a (patch) | |
tree | 2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/u-boot/drivers/power/pmic | |
parent | e02cda008591317b1625707ff8e115a4841aa889 (diff) |
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/u-boot/drivers/power/pmic')
41 files changed, 4426 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/power/pmic/Kconfig b/roms/u-boot/drivers/power/pmic/Kconfig new file mode 100644 index 000000000..583fd3ddc --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/Kconfig @@ -0,0 +1,334 @@ +config DM_PMIC + bool "Enable Driver Model for PMIC drivers (UCLASS_PMIC)" + depends on DM + ---help--- + This config enables the driver-model PMIC support. + UCLASS_PMIC - designed to provide an I/O interface for PMIC devices. + For the multi-function PMIC devices, this can be used as parent I/O + device for each IC's interface. Then, each children uses its parent + for read/write. For detailed description, please refer to the files: + - 'drivers/power/pmic/pmic-uclass.c' + - 'include/power/pmic.h' + +config PMIC_CHILDREN + bool "Allow child devices for PMICs" + depends on DM_PMIC + default y + ---help--- + This allows PMICs to support child devices (such as regulators) in + SPL. This adds quite a bit of code so if you are not using this + feature you can turn it off. Most likely you should turn it on for + U-Boot proper. + +config SPL_PMIC_CHILDREN + bool "Allow child devices for PMICs in SPL" + depends on DM_PMIC + default y + ---help--- + This allows PMICs to support child devices (such as regulators) in + SPL. This adds quite a bit of code so if you are not using this + feature you can turn it off. In this case you may need a 'back door' + to call your regulator code (e.g. see rk8xx.c for direct functions + for use in SPL). + +config PMIC_ACT8846 + bool "Enable support for the active-semi 8846 PMIC" + depends on DM_PMIC && DM_I2C + ---help--- + This PMIC includes 4 DC/DC step-down buck regulators and 8 low-dropout + regulators (LDOs). It also provides some GPIO, reset and battery + functions. It uses an I2C interface and is designed for use with + tablets and smartphones. + +config DM_PMIC_DA9063 + bool "Enable Driver Model for the Dialog DA9063 PMIC" + depends on DM_PMIC + help + This config enables implementation of driver-model pmic uclass features + for PMIC DA9063. The driver implements read/write operations. + +config SPL_DM_PMIC_DA9063 + bool "Enable Driver Model for the Dialog DA9063 PMIC in SPL" + depends on DM_PMIC && SPL + help + This config enables implementation of driver-model pmic uclass features + for PMIC DA9063. The driver implements read/write operations. + +config PMIC_AS3722 + bool "Enable support for the Austria Micro Systems (AMS) AS7322 PMIC" + help + The AS3722 includes 7 DC/DC buck convertors, 11 low-noise LDOs, a + real-time clock, GPIOs, ADC and a few other features. It uses an I2C + interface and is designs to cover most of the power managementment + required for a tablets or laptop. + +config DM_PMIC_BD71837 + bool "Enable Driver Model for PMIC BD71837" + depends on DM_PMIC + help + This config enables implementation of driver-model pmic uclass features + for PMIC BD71837. The driver implements read/write operations. + +config SPL_DM_PMIC_BD71837 + bool "Enable Driver Model for PMIC BD71837 in SPL stage" + depends on DM_PMIC + help + This config enables implementation of driver-model pmic uclass + features for PMIC BD71837. The driver implements read/write + operations. + +config DM_PMIC_FAN53555 + bool "Enable support for OnSemi FAN53555" + depends on DM_PMIC && DM_REGULATOR && DM_I2C + select DM_REGULATOR_FAN53555 + help + This config enables implementation of driver-model PMIC + uclass features for the FAN53555 regulator. The FAN53555 is + a (family of) single-output regulators that supports + transitioning between two different output voltages based on + an voltage selection pin. + + The driver implements read/write operations for use with the FAN53555 + regulator driver and binds the regulator driver to its node. + +config DM_PMIC_MP5416 + bool "Enable Driver Model for PMIC MP5416" + depends on DM_PMIC + help + This config enables implementation of driver-model pmic uclass features + for PMIC MP5416. The driver implements read/write operations. + +config SPL_DM_PMIC_MP5416 + bool "Enable Driver Model for PMIC MP5416 in SPL stage" + depends on DM_PMIC + help + This config enables implementation of driver-model pmic uclass + features for PMIC MP5416. The driver implements read/write + operations. + +config DM_PMIC_PCA9450 + bool "Enable Driver Model for PMIC PCA9450" + depends on DM_PMIC + help + This config enables implementation of driver-model pmic uclass features + for PMIC PCA9450. The driver implements read/write operations. + +config SPL_DM_PMIC_PCA9450 + bool "Enable Driver Model for PMIC PCA9450" + depends on DM_PMIC + help + This config enables implementation of driver-model pmic uclass features + for PMIC PCA9450 in SPL. The driver implements read/write operations. + +config DM_PMIC_PFUZE100 + bool "Enable Driver Model for PMIC PFUZE100" + depends on DM_PMIC + ---help--- + This config enables implementation of driver-model pmic uclass features + for PMIC PFUZE100. The driver implements read/write operations. + +config SPL_DM_PMIC_PFUZE100 + bool "Enable Driver Model for PMIC PFUZE100 in SPL" + depends on DM_PMIC + ---help--- + This config enables implementation of driver-model pmic uclass features + for PMIC PFUZE100 in SPL. The driver implements read/write operations. + +config DM_PMIC_MAX77686 + bool "Enable Driver Model for PMIC MAX77686" + depends on DM_PMIC + ---help--- + This config enables implementation of driver-model pmic uclass features + for PMIC MAX77686. The driver implements read/write operations. + +config DM_PMIC_MAX8998 + bool "Enable Driver Model for PMIC MAX8998" + depends on DM_PMIC + ---help--- + This config enables implementation of driver-model pmic uclass features + for PMIC MAX8998. The driver implements read/write operations. + +config DM_PMIC_MC34708 + bool "Enable Driver Model for PMIC MC34708" + depends on DM_PMIC + help + This config enables implementation of driver-model pmic uclass features + for PMIC MC34708. The driver implements read/write operations. + +config PMIC_MAX8997 + bool "Enable Driver Model for PMIC MAX8997" + depends on DM_PMIC + ---help--- + This config enables implementation of driver-model pmic uclass features + for PMIC MAX8997. The driver implements read/write operations. + This is a Power Management IC with RTC, Fuel Gauge, MUIC control on Chip. + - 21x LDOs + - 12x GPIOs + - Haptic Motor driver + - RTC with two alarms + - Fueal Gauge and One backup battery charger + - MUIC + - Others + +config PMIC_PM8916 + bool "Enable Driver Model for Qualcomm PM8916 PMIC" + depends on DM_PMIC + ---help--- + The PM8916 is a PMIC connected to one (or several) processors + with SPMI bus. It has 2 slaves with several peripherals: + - 18x LDO + - 4x GPIO + - Power and Reset buttons + - Watchdog + - RTC + - Vibrator drivers + - Others + + Driver binding info: doc/device-tree-bindings/pmic/pm8916.txt + +config PMIC_RK8XX + bool "Enable support for Rockchip PMIC RK8XX" + depends on DM_PMIC + ---help--- + The Rockchip RK808 PMIC provides four buck DC-DC convertors, 8 LDOs, + an RTC and two low Rds (resistance (drain to source)) switches. It is + accessed via an I2C interface. The device is used with Rockchip SoCs. + This driver implements register read/write operations. + +config PMIC_S2MPS11 + bool "Enable Driver Model for PMIC Samsung S2MPS11" + depends on DM_PMIC + ---help--- + The Samsung S2MPS11 PMIC provides: + - 38 adjustable LDO regulators + - 9 High-Efficiency Buck Converters + - 1 BuckBoost Converter + - RTC with two alarms + - Backup battery charger + - I2C Configuration Interface + This driver provides access to I/O interface only. + Binding info: doc/device-tree-bindings/pmic/s2mps11.txt + +config DM_PMIC_SANDBOX + bool "Enable Driver Model for emulated Sandbox PMIC" + depends on DM_PMIC + ---help--- + Enable the driver for Sandbox PMIC emulation. The emulated PMIC device + depends on two drivers: + - sandbox PMIC I/O driver - implements dm pmic operations + - sandbox PMIC i2c emul driver - emulates the PMIC's I2C transmission + + A detailed information can be found in header: '<power/sandbox_pmic.h>' + + The Sandbox PMIC info: + * I/O interface: + - I2C chip address: 0x40 + - first register address: 0x0 + - register count: 0x10 + * Adjustable outputs: + - 2x LDO + - 2x BUCK + - Each, with a different operating conditions (header). + * Reset values: + - set by i2c emul driver's probe() (defaults in header) + + Driver binding info: doc/device-tree-bindings/pmic/sandbox.txt + +config PMIC_S5M8767 + bool "Enable Driver Model for the Samsung S5M8767 PMIC" + depends on DM_PMIC + ---help--- + The S5M8767 PMIC provides a large array of LDOs and BUCKs for use + as a SoC power controller. It also provides 32KHz clock outputs. This + driver provides basic register access and sets up the attached + regulators if regulator support is enabled. + +config PMIC_RN5T567 + bool "Enable driver for Ricoh RN5T567 PMIC" + depends on DM_PMIC + ---help--- + The RN5T567 is a PMIC with 4 step-down DC/DC converters, 5 LDO + regulators Real-Time Clock and 4 GPIOs. This driver provides + register access only. + +config PMIC_TPS65090 + bool "Enable driver for Texas Instruments TPS65090 PMIC" + depends on DM_PMIC + ---help--- + The TPS65090 is a PMIC containing several LDOs, DC to DC convertors, + FETs and a battery charger. This driver provides register access + only, and you can enable the regulator/charger drivers separately if + required. + +config PMIC_PALMAS + bool "Enable driver for Texas Instruments PALMAS PMIC" + depends on DM_PMIC + ---help--- + The PALMAS is a PMIC containing several LDOs, SMPS. + This driver binds the pmic children. + +config PMIC_LP873X + bool "Enable driver for Texas Instruments LP873X PMIC" + depends on DM_PMIC + ---help--- + The LP873X is a PMIC containing couple of LDOs and couple of SMPS. + This driver binds the pmic children. + +config PMIC_LP87565 + bool "Enable driver for Texas Instruments LP87565 PMIC" + depends on DM_PMIC + ---help--- + The LP87565 is a PMIC containing a bunch of SMPS. + This driver binds the pmic children. + +config POWER_MC34VR500 + bool "Enable driver for Freescale MC34VR500 PMIC" + ---help--- + The MC34VR500 is used in conjunction with the FSL T1 and LS1 series + SoC. It provides 4 buck DC-DC convertors and 5 LDOs, and it is accessed + via an I2C interface. + +config DM_PMIC_TPS65910 + bool "Enable driver for Texas Instruments TPS65910 PMIC" + depends on DM_PMIC + ---help--- + The TPS65910 is a PMIC containing 3 buck DC-DC converters, one boost + DC-DC converter, 8 LDOs and a RTC. This driver binds the SMPS and LDO + pmic children. + +config PMIC_STPMIC1 + bool "Enable support for STMicroelectronics STPMIC1 PMIC" + depends on DM_PMIC && DM_I2C + select SYSRESET_CMD_POWEROFF if CMD_POWEROFF && !ARM_PSCI_FW + ---help--- + The STPMIC1 PMIC provides 4 BUCKs, 6 LDOs, 1 VREF and 2 power switches. + It is accessed via an I2C interface. The device is used with STM32MP1 + SoCs. This driver implements register read/write operations. + +config SPL_PMIC_PALMAS + bool "Enable driver for Texas Instruments PALMAS PMIC" + depends on DM_PMIC + help + The PALMAS is a PMIC containing several LDOs, SMPS. + This driver binds the pmic children in SPL. + +config SPL_PMIC_LP873X + bool "Enable driver for Texas Instruments LP873X PMIC" + depends on DM_PMIC + help + The LP873X is a PMIC containing couple of LDOs and couple of SMPS. + This driver binds the pmic children in SPL. + +config SPL_PMIC_LP87565 + bool "Enable driver for Texas Instruments LP87565 PMIC" + depends on DM_PMIC + help + The LP87565 is a PMIC containing a bunch of SMPS. + This driver binds the pmic children in SPL. + +config PMIC_TPS65941 + bool "Enable driver for Texas Instruments TPS65941 PMIC" + depends on DM_PMIC + help + The TPS65941 is a PMIC containing a bunch of SMPS & LDOs. + This driver binds the pmic children. diff --git a/roms/u-boot/drivers/power/pmic/Makefile b/roms/u-boot/drivers/power/pmic/Makefile new file mode 100644 index 000000000..89099fde5 --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/Makefile @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (C) 2012 Samsung Electronics +# Lukasz Majewski <l.majewski@samsung.com> + +obj-$(CONFIG_DM_PMIC) += pmic-uclass.o +obj-$(CONFIG_DM_PMIC_FAN53555) += fan53555.o +obj-$(CONFIG_$(SPL_)DM_PMIC_DA9063) += da9063.o +obj-$(CONFIG_DM_PMIC_MAX77686) += max77686.o +obj-$(CONFIG_DM_PMIC_MAX8998) += max8998.o +obj-$(CONFIG_DM_PMIC_MC34708) += mc34708.o +obj-$(CONFIG_$(SPL_)DM_PMIC_BD71837) += bd71837.o +obj-$(CONFIG_$(SPL_)DM_PMIC_MP5416) += mp5416.o +obj-$(CONFIG_$(SPL_)DM_PMIC_PFUZE100) += pfuze100.o +obj-$(CONFIG_$(SPL_)DM_PMIC_PCA9450) += pca9450.o +obj-$(CONFIG_PMIC_S2MPS11) += s2mps11.o +obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o +obj-$(CONFIG_PMIC_ACT8846) += act8846.o +obj-$(CONFIG_PMIC_AS3722) += as3722.o as3722_gpio.o +obj-$(CONFIG_PMIC_MAX8997) += max8997.o +obj-$(CONFIG_PMIC_PM8916) += pm8916.o +obj-$(CONFIG_PMIC_RK8XX) += rk8xx.o +obj-$(CONFIG_PMIC_RN5T567) += rn5t567.o +obj-$(CONFIG_PMIC_TPS65090) += tps65090.o +obj-$(CONFIG_PMIC_S5M8767) += s5m8767.o +obj-$(CONFIG_DM_PMIC_TPS65910) += pmic_tps65910_dm.o +obj-$(CONFIG_$(SPL_)PMIC_PALMAS) += palmas.o +obj-$(CONFIG_$(SPL_)PMIC_LP873X) += lp873x.o +obj-$(CONFIG_$(SPL_)PMIC_LP87565) += lp87565.o +obj-$(CONFIG_PMIC_STPMIC1) += stpmic1.o + +obj-$(CONFIG_POWER_LTC3676) += pmic_ltc3676.o +obj-$(CONFIG_POWER_MUIC_MAX8997) += muic_max8997.o +obj-$(CONFIG_POWER_PCA9450) += pmic_pca9450.o +obj-$(CONFIG_POWER_PFUZE100) += pmic_pfuze100.o +obj-$(CONFIG_POWER_PFUZE3000) += pmic_pfuze3000.o +obj-$(CONFIG_POWER_TPS65217) += pmic_tps65217.o +obj-$(CONFIG_POWER_TPS65218) += pmic_tps62362.o +obj-$(CONFIG_POWER_TPS65218) += pmic_tps65218.o +obj-$(CONFIG_POWER_TPS65910) += pmic_tps65910.o +obj-$(CONFIG_POWER_HI6553) += pmic_hi6553.o +obj-$(CONFIG_POWER_MC34VR500) += pmic_mc34vr500.o +obj-$(CONFIG_PMIC_TPS65941) += tps65941.o diff --git a/roms/u-boot/drivers/power/pmic/act8846.c b/roms/u-boot/drivers/power/pmic/act8846.c new file mode 100644 index 000000000..8f0f5a6d9 --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/act8846.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2015 Google, Inc + * Written by Simon Glass <sjg@chromium.org> + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <log.h> +#include <linux/libfdt.h> +#include <power/act8846_pmic.h> +#include <power/pmic.h> + +static const struct pmic_child_info pmic_children_info[] = { + { .prefix = "REG", .driver = "act8846_reg"}, + { }, +}; + +static int act8846_reg_count(struct udevice *dev) +{ + return ACT8846_NUM_OF_REGS; +} + +static int act8846_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + if (dm_i2c_write(dev, reg, buff, len)) { + debug("write error to device: %p register: %#x!\n", dev, reg); + return -EIO; + } + + return 0; +} + +static int act8846_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + if (dm_i2c_read(dev, reg, buff, len)) { + debug("read error from device: %p register: %#x!\n", dev, reg); + return -EIO; + } + + return 0; +} + +static int act8846_bind(struct udevice *dev) +{ + ofnode regulators_node; + int children; + + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { + debug("%s: %s regulators subnode not found!\n", __func__, + dev->name); + return -ENXIO; + } + + debug("%s: '%s' - found regulators subnode\n", __func__, dev->name); + + children = pmic_bind_children(dev, regulators_node, pmic_children_info); + if (!children) + debug("%s: %s - no child found\n", __func__, dev->name); + + /* Always return success for this device */ + return 0; +} + +static struct dm_pmic_ops act8846_ops = { + .reg_count = act8846_reg_count, + .read = act8846_read, + .write = act8846_write, +}; + +static const struct udevice_id act8846_ids[] = { + { .compatible = "active-semi,act8846" }, + { } +}; + +U_BOOT_DRIVER(pmic_act8846) = { + .name = "act8846 pmic", + .id = UCLASS_PMIC, + .of_match = act8846_ids, + .bind = act8846_bind, + .ops = &act8846_ops, +}; diff --git a/roms/u-boot/drivers/power/pmic/as3722.c b/roms/u-boot/drivers/power/pmic/as3722.c new file mode 100644 index 000000000..3aa3cce94 --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/as3722.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2014 NVIDIA Corporation + */ + +#define pr_fmt(fmt) "as3722: " fmt + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <i2c.h> +#include <log.h> +#include <dm/lists.h> +#include <power/as3722.h> +#include <power/pmic.h> + +#define AS3722_NUM_OF_REGS 0x92 + +static int as3722_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + int ret; + + ret = dm_i2c_read(dev, reg, buff, len); + if (ret < 0) + return ret; + + return 0; +} + +static int as3722_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + int ret; + + ret = dm_i2c_write(dev, reg, buff, len); + if (ret < 0) + return ret; + + return 0; +} + +static int as3722_read_id(struct udevice *dev, uint *idp, uint *revisionp) +{ + int ret; + + ret = pmic_reg_read(dev, AS3722_ASIC_ID1); + if (ret < 0) { + pr_err("failed to read ID1 register: %d\n", ret); + return ret; + } + *idp = ret; + + ret = pmic_reg_read(dev, AS3722_ASIC_ID2); + if (ret < 0) { + pr_err("failed to read ID2 register: %d\n", ret); + return ret; + } + *revisionp = ret; + + return 0; +} + +/* TODO(treding@nvidia.com): Add proper regulator support to avoid this */ +int as3722_sd_set_voltage(struct udevice *dev, unsigned int sd, u8 value) +{ + int ret; + + if (sd > 6) + return -EINVAL; + + ret = pmic_reg_write(dev, AS3722_SD_VOLTAGE(sd), value); + if (ret < 0) { + pr_err("failed to write SD%u voltage register: %d\n", sd, ret); + return ret; + } + + return 0; +} + +int as3722_ldo_set_voltage(struct udevice *dev, unsigned int ldo, u8 value) +{ + int ret; + + if (ldo > 11) + return -EINVAL; + + ret = pmic_reg_write(dev, AS3722_LDO_VOLTAGE(ldo), value); + if (ret < 0) { + pr_err("failed to write LDO%u voltage register: %d\n", ldo, + ret); + return ret; + } + + return 0; +} + +static int as3722_probe(struct udevice *dev) +{ + uint id, revision; + int ret; + + ret = as3722_read_id(dev, &id, &revision); + if (ret < 0) { + pr_err("failed to read ID: %d\n", ret); + return ret; + } + + if (id != AS3722_DEVICE_ID) { + pr_err("unknown device\n"); + return -ENOENT; + } + + debug("AS3722 revision %#x found on I2C bus %s\n", revision, dev->name); + + return 0; +} + +#if CONFIG_IS_ENABLED(PMIC_CHILDREN) +static const struct pmic_child_info pmic_children_info[] = { + { .prefix = "sd", .driver = "as3722_stepdown"}, + { .prefix = "ldo", .driver = "as3722_ldo"}, + { }, +}; + +static int as3722_bind(struct udevice *dev) +{ + struct udevice *gpio_dev; + ofnode regulators_node; + int children; + int ret; + + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { + debug("%s: %s regulators subnode not found\n", __func__, + dev->name); + return -ENXIO; + } + + children = pmic_bind_children(dev, regulators_node, pmic_children_info); + if (!children) + debug("%s: %s - no child found\n", __func__, dev->name); + ret = device_bind_driver(dev, "gpio_as3722", "gpio_as3722", &gpio_dev); + if (ret) { + debug("%s: Cannot bind GPIOs (ret=%d)\n", __func__, ret); + return ret; + } + + return 0; +} +#endif + +static int as3722_reg_count(struct udevice *dev) +{ + return AS3722_NUM_OF_REGS; +} + +static struct dm_pmic_ops as3722_ops = { + .reg_count = as3722_reg_count, + .read = as3722_read, + .write = as3722_write, +}; + +static const struct udevice_id as3722_ids[] = { + { .compatible = "ams,as3722" }, + { } +}; + +U_BOOT_DRIVER(pmic_as3722) = { + .name = "as3722_pmic", + .id = UCLASS_PMIC, + .of_match = as3722_ids, +#if CONFIG_IS_ENABLED(PMIC_CHILDREN) + .bind = as3722_bind, +#endif + .probe = as3722_probe, + .ops = &as3722_ops, +}; diff --git a/roms/u-boot/drivers/power/pmic/as3722_gpio.c b/roms/u-boot/drivers/power/pmic/as3722_gpio.c new file mode 100644 index 000000000..96943bc1a --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/as3722_gpio.c @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2014 NVIDIA Corporation + */ + +#include <common.h> +#include <dm.h> +#include <asm/gpio.h> +#include <power/as3722.h> +#include <power/pmic.h> + +#define NUM_GPIOS 8 + +int as3722_gpio_configure(struct udevice *pmic, unsigned int gpio, + unsigned long flags) +{ + u8 value = 0; + int err; + + if (flags & AS3722_GPIO_OUTPUT_VDDH) + value |= AS3722_GPIO_CONTROL_MODE_OUTPUT_VDDH; + + if (flags & AS3722_GPIO_INVERT) + value |= AS3722_GPIO_CONTROL_INVERT; + + err = pmic_reg_write(pmic, AS3722_GPIO_CONTROL(gpio), value); + if (err) { + pr_err("failed to configure GPIO#%u: %d\n", gpio, err); + return err; + } + + return 0; +} + +static int as3722_gpio_set_value(struct udevice *dev, unsigned int gpio, + int level) +{ + struct udevice *pmic = dev_get_parent(dev); + const char *l; + u8 value; + int err; + + if (gpio >= NUM_GPIOS) + return -EINVAL; + + err = pmic_reg_read(pmic, AS3722_GPIO_SIGNAL_OUT); + if (err < 0) { + pr_err("failed to read GPIO signal out register: %d\n", err); + return err; + } + value = err; + + if (level == 0) { + value &= ~(1 << gpio); + l = "low"; + } else { + value |= 1 << gpio; + l = "high"; + } + + err = pmic_reg_write(pmic, AS3722_GPIO_SIGNAL_OUT, value); + if (err) { + pr_err("failed to set GPIO#%u %s: %d\n", gpio, l, err); + return err; + } + + return 0; +} + +int as3722_gpio_direction_output(struct udevice *dev, unsigned int gpio, + int value) +{ + struct udevice *pmic = dev_get_parent(dev); + int err; + + if (gpio > 7) + return -EINVAL; + + if (value == 0) + value = AS3722_GPIO_CONTROL_MODE_OUTPUT_VDDL; + else + value = AS3722_GPIO_CONTROL_MODE_OUTPUT_VDDH; + + err = pmic_reg_write(pmic, AS3722_GPIO_CONTROL(gpio), value); + if (err) { + pr_err("failed to configure GPIO#%u as output: %d\n", gpio, + err); + return err; + } + + err = as3722_gpio_set_value(pmic, gpio, value); + if (err < 0) { + pr_err("failed to set GPIO#%u high: %d\n", gpio, err); + return err; + } + + return 0; +} + +static int as3722_gpio_probe(struct udevice *dev) +{ + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + + uc_priv->gpio_count = NUM_GPIOS; + uc_priv->bank_name = "as3722_"; + + return 0; +} + +static const struct dm_gpio_ops gpio_as3722_ops = { + .direction_output = as3722_gpio_direction_output, + .set_value = as3722_gpio_set_value, +}; + +U_BOOT_DRIVER(gpio_as3722) = { + .name = "gpio_as3722", + .id = UCLASS_GPIO, + .ops = &gpio_as3722_ops, + .probe = as3722_gpio_probe, +}; diff --git a/roms/u-boot/drivers/power/pmic/bd71837.c b/roms/u-boot/drivers/power/pmic/bd71837.c new file mode 100644 index 000000000..cb9238972 --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/bd71837.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018 NXP + */ + +#include <common.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <log.h> +#include <asm/global_data.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/bd71837.h> + +DECLARE_GLOBAL_DATA_PTR; + +static const struct pmic_child_info pmic_children_info[] = { + /* buck */ + { .prefix = "b", .driver = BD718XX_REGULATOR_DRIVER}, + /* ldo */ + { .prefix = "l", .driver = BD718XX_REGULATOR_DRIVER}, + { }, +}; + +static int bd71837_reg_count(struct udevice *dev) +{ + return BD718XX_MAX_REGISTER - 1; +} + +static int bd71837_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + if (dm_i2c_write(dev, reg, buff, len)) { + pr_err("write error to device: %p register: %#x!", dev, reg); + return -EIO; + } + + return 0; +} + +static int bd71837_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + if (dm_i2c_read(dev, reg, buff, len)) { + pr_err("read error from device: %p register: %#x!", dev, reg); + return -EIO; + } + + return 0; +} + +static int bd71837_bind(struct udevice *dev) +{ + int children; + ofnode regulators_node; + + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { + debug("%s: %s regulators subnode not found!\n", __func__, + dev->name); + return -ENXIO; + } + + debug("%s: '%s' - found regulators subnode\n", __func__, dev->name); + + children = pmic_bind_children(dev, regulators_node, pmic_children_info); + if (!children) + debug("%s: %s - no child found\n", __func__, dev->name); + + /* Always return success for this device */ + return 0; +} + +static int bd718x7_probe(struct udevice *dev) +{ + int ret; + uint8_t mask = BD718XX_REGLOCK_PWRSEQ | BD718XX_REGLOCK_VREG; + + /* Unlock the PMIC regulator control before probing the children */ + ret = pmic_clrsetbits(dev, BD718XX_REGLOCK, mask, 0); + if (ret) { + debug("%s: %s Failed to unlock regulator control\n", __func__, + dev->name); + return ret; + } + debug("%s: '%s' - BD718x7 PMIC registers unlocked\n", __func__, + dev->name); + + return 0; +} + +static struct dm_pmic_ops bd71837_ops = { + .reg_count = bd71837_reg_count, + .read = bd71837_read, + .write = bd71837_write, +}; + +static const struct udevice_id bd71837_ids[] = { + { .compatible = "rohm,bd71837", .data = ROHM_CHIP_TYPE_BD71837, }, + { .compatible = "rohm,bd71847", .data = ROHM_CHIP_TYPE_BD71847, }, + { } +}; + +U_BOOT_DRIVER(pmic_bd71837) = { + .name = "bd71837 pmic", + .id = UCLASS_PMIC, + .of_match = bd71837_ids, + .bind = bd71837_bind, + .probe = bd718x7_probe, + .ops = &bd71837_ops, +}; diff --git a/roms/u-boot/drivers/power/pmic/da9063.c b/roms/u-boot/drivers/power/pmic/da9063.c new file mode 100644 index 000000000..25101d18f --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/da9063.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 Flowbird + * Martin Fuzzey <martin.fuzzey@flowbird.group> + */ + +#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <log.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/da9063_pmic.h> + +static const struct pmic_child_info pmic_children_info[] = { + { .prefix = "ldo", .driver = DA9063_LDO_DRIVER }, + { .prefix = "b", .driver = DA9063_BUCK_DRIVER }, + { }, +}; + +/* + * The register map is non contiguous and attempts to read in the holes fail. + * But "pmic dump" tries to dump the full register map. + * So define the holes here so we can fix that. + */ +struct da9063_reg_hole { + u16 first; + u16 last; +}; + +static const struct da9063_reg_hole da9063_reg_holes[] = { + DA9063_REG_HOLE_1, + DA9063_REG_HOLE_2, + DA9063_REG_HOLE_3, + /* These aren't readable. I can't see why from the datasheet but + * attempts to read fail and the kernel marks them unreadable too, + */ + {DA9063_REG_OTP_COUNT, DA9063_REG_OTP_DATA}, +}; + +static int da9063_reg_count(struct udevice *dev) +{ + return DA9063_NUM_OF_REGS; +} + +static bool da9063_reg_valid(uint reg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(da9063_reg_holes); i++) { + const struct da9063_reg_hole *hole = &da9063_reg_holes[i]; + + if (reg >= hole->first && reg <= hole->last) + return false; + } + + return true; +} + +static int da9063_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + if (dm_i2c_write(dev, reg, buff, len)) { + pr_err("write error to device: %p register: %#x!", dev, reg); + return -EIO; + } + + return 0; +} + +static int da9063_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + if (!da9063_reg_valid(reg)) + return -ENODATA; + + if (dm_i2c_read(dev, reg, buff, len)) { + pr_err("read error from device: %p register: %#x!", dev, reg); + return -EIO; + } + + return 0; +} + +static int da9063_bind(struct udevice *dev) +{ + ofnode regulators_node; + int children; + + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { + debug("%s: %s regulators subnode not found!", __func__, + dev->name); + return -ENXIO; + } + + debug("%s: '%s' - found regulators subnode\n", __func__, dev->name); + + children = pmic_bind_children(dev, regulators_node, pmic_children_info); + if (!children) + debug("%s: %s - no child found\n", __func__, dev->name); + + /* Always return success for this device */ + return 0; +} + +static int da9063_probe(struct udevice *dev) +{ + return i2c_set_chip_addr_offset_mask(dev, 0x1); +} + +static struct dm_pmic_ops da9063_ops = { + .reg_count = da9063_reg_count, + .read = da9063_read, + .write = da9063_write, +}; + +static const struct udevice_id da9063_ids[] = { + { .compatible = "dlg,da9063" }, + { } +}; + +U_BOOT_DRIVER(pmic_da9063) = { + .name = "da9063_pmic", + .id = UCLASS_PMIC, + .of_match = da9063_ids, + .bind = da9063_bind, + .probe = da9063_probe, + .ops = &da9063_ops, +}; diff --git a/roms/u-boot/drivers/power/pmic/fan53555.c b/roms/u-boot/drivers/power/pmic/fan53555.c new file mode 100644 index 000000000..4d1e686d2 --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/fan53555.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) 2018 Theobroma Systems Design und Consulting GmbH + */ + +#include <common.h> +#include <dm.h> +#include <log.h> +#include <dm/device-internal.h> +#include <dm/device_compat.h> +#include <dm/lists.h> +#include <i2c.h> +#include <power/fan53555.h> +#include <power/pmic.h> +#include <power/regulator.h> + +static int pmic_fan53555_reg_count(struct udevice *dev) +{ + return 1; +}; + +static int pmic_fan53555_read(struct udevice *dev, uint reg, + u8 *buff, int len) +{ + if (dm_i2c_read(dev, reg, buff, len)) { + pr_err("%s: read error for register: %#x!", dev->name, reg); + return -EIO; + } + + return 0; +} + +static int pmic_fan53555_write(struct udevice *dev, uint reg, + const u8 *buff, int len) +{ + if (dm_i2c_write(dev, reg, buff, len)) { + pr_err("%s: write error for register: %#x!", dev->name, reg); + return -EIO; + } + + return 0; +} + +static int pmic_fan53555_bind(struct udevice *dev) +{ + /* + * The FAN53555 has only a single regulator and therefore doesn't + * have a subnode. So we have to rebind a child device (the one + * regulator) here. + */ + + const char *regulator_driver_name = "fan53555_regulator"; + struct udevice *child; + struct driver *drv; + + debug("%s\n", __func__); + + drv = lists_driver_lookup_name(regulator_driver_name); + if (!drv) { + dev_err(dev, "no driver '%s'\n", regulator_driver_name); + return -ENOENT; + } + + return device_bind_with_driver_data(dev, drv, "SW", dev->driver_data, + dev_ofnode(dev), &child); +}; + +static struct dm_pmic_ops pmic_fan53555_ops = { + .reg_count = pmic_fan53555_reg_count, + .read = pmic_fan53555_read, + .write = pmic_fan53555_write, +}; + +static const struct udevice_id pmic_fan53555_match[] = { + { .compatible = "fcs,fan53555", .data = FAN53555_VENDOR_FAIRCHILD, }, + { .compatible = "silergy,syr827", .data = FAN53555_VENDOR_SILERGY, }, + { .compatible = "silergy,syr828", .data = FAN53555_VENDOR_SILERGY, }, + { }, +}; + +U_BOOT_DRIVER(pmic_fan53555) = { + .name = "pmic_fan53555", + .id = UCLASS_PMIC, + .of_match = pmic_fan53555_match, + .bind = pmic_fan53555_bind, + .ops = &pmic_fan53555_ops, +}; diff --git a/roms/u-boot/drivers/power/pmic/i2c_pmic_emul.c b/roms/u-boot/drivers/power/pmic/i2c_pmic_emul.c new file mode 100644 index 000000000..abe3a1051 --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/i2c_pmic_emul.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2015 Samsung Electronics + * Przemyslaw Marczak <p.marczak@samsung.com> + */ + +#include <common.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <log.h> +#include <malloc.h> +#include <power/pmic.h> +#include <power/sandbox_pmic.h> + +/** + * struct sandbox_i2c_pmic_plat_data - platform data for the PMIC + * + * @rw_reg: PMICs register of the chip I/O transaction + * @reg: PMICs registers array + */ +struct sandbox_i2c_pmic_plat_data { + u8 rw_reg, rw_idx; + u8 reg_count; + u8 trans_len; + u8 buf_size; + u8 *reg; +}; + +static int sandbox_i2c_pmic_read_data(struct udevice *emul, uchar chip, + uchar *buffer, int len) +{ + struct sandbox_i2c_pmic_plat_data *plat = dev_get_plat(emul); + + if (plat->rw_idx + len > plat->buf_size) { + pr_err("Request exceeds PMIC register range! Max register: %#x", + plat->reg_count); + return -EFAULT; + } + + debug("Read PMIC: %#x at register: %#x idx: %#x count: %d\n", + (unsigned int)chip & 0xff, plat->rw_reg, plat->rw_idx, len); + + memcpy(buffer, plat->reg + plat->rw_idx, len); + + return 0; +} + +static int sandbox_i2c_pmic_write_data(struct udevice *emul, uchar chip, + uchar *buffer, int len, + bool next_is_read) +{ + struct sandbox_i2c_pmic_plat_data *plat = dev_get_plat(emul); + + /* Probe only */ + if (!len) + return 0; + + /* Set PMIC register for I/O */ + plat->rw_reg = *buffer; + plat->rw_idx = plat->rw_reg * plat->trans_len; + + debug("Write PMIC: %#x at register: %#x idx: %#x count: %d\n", + (unsigned int)chip & 0xff, plat->rw_reg, plat->rw_idx, len); + + /* For read operation, set (write) only chip reg */ + if (next_is_read) + return 0; + + buffer++; + len--; + + if (plat->rw_idx + len > plat->buf_size) { + pr_err("Request exceeds PMIC register range! Max register: %#x", + plat->reg_count); + } + + memcpy(plat->reg + plat->rw_idx, buffer, len); + + return 0; +} + +static int sandbox_i2c_pmic_xfer(struct udevice *emul, struct i2c_msg *msg, + int nmsgs) +{ + int ret = 0; + + for (; nmsgs > 0; nmsgs--, msg++) { + bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD); + if (msg->flags & I2C_M_RD) { + ret = sandbox_i2c_pmic_read_data(emul, msg->addr, + msg->buf, msg->len); + } else { + ret = sandbox_i2c_pmic_write_data(emul, msg->addr, + msg->buf, msg->len, + next_is_read); + } + + if (ret) + break; + } + + return ret; +} + +static int sandbox_i2c_pmic_of_to_plat(struct udevice *emul) +{ + struct sandbox_i2c_pmic_plat_data *plat = dev_get_plat(emul); + struct udevice *pmic_dev = i2c_emul_get_device(emul); + + debug("%s:%d Setting PMIC default registers\n", __func__, __LINE__); + plat->reg_count = pmic_reg_count(pmic_dev); + + return 0; +} + +static int sandbox_i2c_pmic_probe(struct udevice *emul) +{ + struct sandbox_i2c_pmic_plat_data *plat = dev_get_plat(emul); + struct udevice *pmic_dev = i2c_emul_get_device(emul); + struct uc_pmic_priv *upriv = dev_get_uclass_priv(pmic_dev); + const u8 *reg_defaults; + + plat->trans_len = upriv->trans_len; + plat->buf_size = plat->reg_count * plat->trans_len; + + plat->reg = calloc(1, plat->buf_size); + if (!plat->reg) { + debug("Canot allocate memory (%d B) for PMIC I2C emulation!\n", + plat->buf_size); + return -ENOMEM; + } + + reg_defaults = dev_read_u8_array_ptr(emul, "reg-defaults", + plat->buf_size); + + if (!reg_defaults) { + pr_err("Property \"reg-defaults\" not found for device: %s!", + emul->name); + free(plat->reg); + return -EINVAL; + } + + memcpy(plat->reg, reg_defaults, plat->buf_size); + + return 0; +} + +struct dm_i2c_ops sandbox_i2c_pmic_emul_ops = { + .xfer = sandbox_i2c_pmic_xfer, +}; + +static const struct udevice_id sandbox_i2c_pmic_ids[] = { + { .compatible = "sandbox,i2c-pmic" }, + { } +}; + +U_BOOT_DRIVER(sandbox_i2c_pmic_emul) = { + .name = "sandbox_i2c_pmic_emul", + .id = UCLASS_I2C_EMUL, + .of_match = sandbox_i2c_pmic_ids, + .of_to_plat = sandbox_i2c_pmic_of_to_plat, + .probe = sandbox_i2c_pmic_probe, + .plat_auto = sizeof(struct sandbox_i2c_pmic_plat_data), + .ops = &sandbox_i2c_pmic_emul_ops, +}; diff --git a/roms/u-boot/drivers/power/pmic/lp873x.c b/roms/u-boot/drivers/power/pmic/lp873x.c new file mode 100644 index 000000000..2b1260ec6 --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/lp873x.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2016 Texas Instruments Incorporated, <www.ti.com> + * Keerthy <j-keerthy@ti.com> + */ + +#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <log.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/lp873x.h> +#include <dm/device.h> + +static const struct pmic_child_info pmic_children_info[] = { + { .prefix = "ldo", .driver = LP873X_LDO_DRIVER }, + { .prefix = "buck", .driver = LP873X_BUCK_DRIVER }, + { }, +}; + +static int lp873x_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + if (dm_i2c_write(dev, reg, buff, len)) { + pr_err("write error to device: %p register: %#x!\n", dev, reg); + return -EIO; + } + + return 0; +} + +static int lp873x_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + if (dm_i2c_read(dev, reg, buff, len)) { + pr_err("read error from device: %p register: %#x!\n", dev, reg); + return -EIO; + } + + return 0; +} + +static int lp873x_bind(struct udevice *dev) +{ + ofnode regulators_node; + int children; + + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { + debug("%s: %s regulators subnode not found!\n", __func__, + dev->name); + return -ENXIO; + } + + children = pmic_bind_children(dev, regulators_node, pmic_children_info); + if (!children) + printf("%s: %s - no child found\n", __func__, dev->name); + + /* Always return success for this device */ + return 0; +} + +static struct dm_pmic_ops lp873x_ops = { + .read = lp873x_read, + .write = lp873x_write, +}; + +static const struct udevice_id lp873x_ids[] = { + { .compatible = "ti,lp8732", .data = LP8732 }, + { .compatible = "ti,lp8733" , .data = LP8733 }, + { } +}; + +U_BOOT_DRIVER(pmic_lp873x) = { + .name = "lp873x_pmic", + .id = UCLASS_PMIC, + .of_match = lp873x_ids, + .bind = lp873x_bind, + .ops = &lp873x_ops, +}; diff --git a/roms/u-boot/drivers/power/pmic/lp87565.c b/roms/u-boot/drivers/power/pmic/lp87565.c new file mode 100644 index 000000000..f4a4bd03d --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/lp87565.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2017 Texas Instruments Incorporated, <www.ti.com> + * Keerthy <j-keerthy@ti.com> + */ + +#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <log.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/lp87565.h> +#include <dm/device.h> + +static const struct pmic_child_info pmic_children_info[] = { + { .prefix = "buck", .driver = LP87565_BUCK_DRIVER }, + { }, +}; + +static int lp87565_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + int ret; + + ret = dm_i2c_write(dev, reg, buff, len); + if (ret) + pr_err("write error to device: %p register: %#x!\n", dev, reg); + + return ret; +} + +static int lp87565_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + int ret; + + ret = dm_i2c_read(dev, reg, buff, len); + if (ret) + pr_err("read error from device: %p register: %#x!\n", dev, reg); + + return ret; +} + +static int lp87565_bind(struct udevice *dev) +{ + ofnode regulators_node; + int children; + + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { + debug("%s: %s regulators subnode not found!\n", __func__, + dev->name); + return -ENXIO; + } + + debug("%s: '%s' - found regulators subnode\n", __func__, dev->name); + + children = pmic_bind_children(dev, regulators_node, pmic_children_info); + if (!children) + printf("%s: %s - no child found\n", __func__, dev->name); + + /* Always return success for this device */ + return 0; +} + +static struct dm_pmic_ops lp87565_ops = { + .read = lp87565_read, + .write = lp87565_write, +}; + +static const struct udevice_id lp87565_ids[] = { + { .compatible = "ti,lp87565", .data = LP87565 }, + { .compatible = "ti,lp87565-q1", .data = LP87565_Q1 }, + { } +}; + +U_BOOT_DRIVER(pmic_lp87565) = { + .name = "lp87565_pmic", + .id = UCLASS_PMIC, + .of_match = lp87565_ids, + .bind = lp87565_bind, + .ops = &lp87565_ops, +}; diff --git a/roms/u-boot/drivers/power/pmic/max77686.c b/roms/u-boot/drivers/power/pmic/max77686.c new file mode 100644 index 000000000..9f02c0b6f --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/max77686.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2014-2015 Samsung Electronics + * Przemyslaw Marczak <p.marczak@samsung.com> + */ + +#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <log.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/max77686_pmic.h> + +static const struct pmic_child_info pmic_children_info[] = { + { .prefix = "LDO", .driver = MAX77686_LDO_DRIVER }, + { .prefix = "BUCK", .driver = MAX77686_BUCK_DRIVER }, + { }, +}; + +static int max77686_reg_count(struct udevice *dev) +{ + return MAX77686_NUM_OF_REGS; +} + +static int max77686_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + if (dm_i2c_write(dev, reg, buff, len)) { + pr_err("write error to device: %p register: %#x!\n", dev, reg); + return -EIO; + } + + return 0; +} + +static int max77686_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + if (dm_i2c_read(dev, reg, buff, len)) { + pr_err("read error from device: %p register: %#x!\n", dev, reg); + return -EIO; + } + + return 0; +} + +static int max77686_bind(struct udevice *dev) +{ + ofnode regulators_node; + int children; + + regulators_node = dev_read_subnode(dev, "voltage-regulators"); + if (!ofnode_valid(regulators_node)) { + debug("%s: %s regulators subnode not found!\n", __func__, + dev->name); + return -ENXIO; + } + + debug("%s: '%s' - found regulators subnode\n", __func__, dev->name); + + children = pmic_bind_children(dev, regulators_node, pmic_children_info); + if (!children) + debug("%s: %s - no child found\n", __func__, dev->name); + + /* Always return success for this device */ + return 0; +} + +static struct dm_pmic_ops max77686_ops = { + .reg_count = max77686_reg_count, + .read = max77686_read, + .write = max77686_write, +}; + +static const struct udevice_id max77686_ids[] = { + { .compatible = "maxim,max77686" }, + { } +}; + +U_BOOT_DRIVER(pmic_max77686) = { + .name = "max77686_pmic", + .id = UCLASS_PMIC, + .of_match = max77686_ids, + .bind = max77686_bind, + .ops = &max77686_ops, +}; diff --git a/roms/u-boot/drivers/power/pmic/max8997.c b/roms/u-boot/drivers/power/pmic/max8997.c new file mode 100644 index 000000000..dbae155fb --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/max8997.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Samsung Electronics + * Jaehoon Chung <jh80.chung@samsung.com> + */ + +#include <common.h> +#include <dm.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/max8997_pmic.h> +#include <errno.h> + +static int max8997_reg_count(struct udevice *dev) +{ + return PMIC_NUM_OF_REGS; +} + +static int max8997_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + int ret; + + ret = dm_i2c_write(dev, reg, buff, len); + if (ret) + pr_err("write error to device: %p register: %#x!\n", dev, reg); + + return ret; +} + +static int max8997_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + int ret; + + ret = dm_i2c_read(dev, reg, buff, len); + if (ret) + pr_err("read error from device: %p register: %#x!\n", dev, reg); + + return ret; +} + +static struct dm_pmic_ops max8997_ops = { + .reg_count = max8997_reg_count, + .read = max8997_read, + .write = max8997_write, +}; + +static const struct udevice_id max8997_ids[] = { + { .compatible = "maxim,max8997" }, + { }, +}; + +U_BOOT_DRIVER(pmic_max8997) = { + .name = "max8997_pmic", + .id = UCLASS_PMIC, + .of_match = max8997_ids, + .ops = &max8997_ops, +}; diff --git a/roms/u-boot/drivers/power/pmic/max8998.c b/roms/u-boot/drivers/power/pmic/max8998.c new file mode 100644 index 000000000..f58d9f2d7 --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/max8998.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Samsung Electronics + * Jaehoon Chung <jh80.chung@samsung.com> + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/max8998_pmic.h> + +static int max8998_reg_count(struct udevice *dev) +{ + return PMIC_NUM_OF_REGS; +} + +static int max8998_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + int ret; + + ret = dm_i2c_write(dev, reg, buff, len); + if (ret) + pr_err("write error to device: %p register: %#x!\n", dev, reg); + + return ret; +} + +static int max8998_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + int ret; + + ret = dm_i2c_read(dev, reg, buff, len); + if (ret) + pr_err("read error from device: %p register: %#x!\n", dev, reg); + + return ret; +} + +static struct dm_pmic_ops max8998_ops = { + .reg_count = max8998_reg_count, + .read = max8998_read, + .write = max8998_write, +}; + +static const struct udevice_id max8998_ids[] = { + { .compatible = "maxim,max8998" }, + { } +}; + +U_BOOT_DRIVER(pmic_max8998) = { + .name = "max8998_pmic", + .id = UCLASS_PMIC, + .of_match = max8998_ids, + .ops = &max8998_ops, +}; diff --git a/roms/u-boot/drivers/power/pmic/mc34708.c b/roms/u-boot/drivers/power/pmic/mc34708.c new file mode 100644 index 000000000..40d732224 --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/mc34708.c @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 + * Lukasz Majewski, DENX Software Engineering, lukma@denx.de + * + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <fsl_pmic.h> +#include <i2c.h> +#include <asm/global_data.h> +#include <power/pmic.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int mc34708_reg_count(struct udevice *dev) +{ + return PMIC_NUM_OF_REGS; +} + +static int mc34708_write(struct udevice *dev, uint reg, const u8 *buff, + int len) +{ + u8 buf[3] = { 0 }; + int ret; + + if (len != MC34708_TRANSFER_SIZE) + return -EINVAL; + + /* + * The MC34708 sends data with big endian format, hence we need to + * perform manual byte swap. + */ + buf[0] = buff[2]; + buf[1] = buff[1]; + buf[2] = buff[0]; + + ret = dm_i2c_write(dev, reg, buf, len); + if (ret) + printf("write error to device: %p register: %#x!\n", dev, reg); + + return ret; +} + +static int mc34708_read(struct udevice *dev, uint reg, u8 *buff, int len) +{ + u8 buf[3] = { 0 }; + int ret; + + if (len != MC34708_TRANSFER_SIZE) + return -EINVAL; + + ret = dm_i2c_read(dev, reg, buf, len); + if (ret) + printf("read error from device: %p register: %#x!\n", dev, reg); + + buff[0] = buf[2]; + buff[1] = buf[1]; + buff[2] = buf[0]; + + return ret; +} + +static int mc34708_probe(struct udevice *dev) +{ + struct uc_pmic_priv *priv = dev_get_uclass_priv(dev); + + priv->trans_len = MC34708_TRANSFER_SIZE; + + /* + * Handle PMIC Errata 37: APS mode not fully functional, + * use explicit PWM or PFM instead + */ + pmic_clrsetbits(dev, MC34708_REG_SW12_OPMODE, + MC34708_SW1AMODE_MASK | MC34708_SW2MODE_MASK, + SW_MODE_PWMPWM | (SW_MODE_PWMPWM << 14u)); + + pmic_clrsetbits(dev, MC34708_REG_SW345_OPMODE, + MC34708_SW3MODE_MASK | MC34708_SW4AMODE_MASK | + MC34708_SW4BMODE_MASK | MC34708_SW5MODE_MASK, + SW_MODE_PWMPWM | (SW_MODE_PWMPWM << 6u) | + (SW_MODE_PWMPWM << 12u) | (SW_MODE_PWMPWM << 18u)); + + return 0; +} + +static struct dm_pmic_ops mc34708_ops = { + .reg_count = mc34708_reg_count, + .read = mc34708_read, + .write = mc34708_write, +}; + +static const struct udevice_id mc34708_ids[] = { + { .compatible = "fsl,mc34708" }, + { } +}; + +U_BOOT_DRIVER(pmic_mc34708) = { + .name = "mc34708_pmic", + .id = UCLASS_PMIC, + .of_match = mc34708_ids, + .probe = mc34708_probe, + .ops = &mc34708_ops, +}; diff --git a/roms/u-boot/drivers/power/pmic/mp5416.c b/roms/u-boot/drivers/power/pmic/mp5416.c new file mode 100644 index 000000000..6180adf77 --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/mp5416.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 Gateworks Corporation + */ +#include <common.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <log.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/mp5416.h> +#include <asm/global_data.h> + +DECLARE_GLOBAL_DATA_PTR; + +static const struct pmic_child_info pmic_children_info[] = { + /* buck */ + { .prefix = "b", .driver = MP6416_REGULATOR_DRIVER }, + /* ldo */ + { .prefix = "l", .driver = MP6416_REGULATOR_DRIVER }, + { }, +}; + +static int mp5416_reg_count(struct udevice *dev) +{ + return MP5416_NUM_OF_REGS - 1; +} + +static int mp5416_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + if (dm_i2c_write(dev, reg, buff, len)) { + pr_err("write error to device: %p register: %#x!", dev, reg); + return -EIO; + } + + return 0; +} + +static int mp5416_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + if (dm_i2c_read(dev, reg, buff, len)) { + pr_err("read error from device: %p register: %#x!", dev, reg); + return -EIO; + } + + return 0; +} + +static int mp5416_bind(struct udevice *dev) +{ + int children; + ofnode regulators_node; + + debug("%s %s\n", __func__, dev->name); + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { + debug("%s: %s regulators subnode not found!\n", __func__, + dev->name); + return -ENXIO; + } + + debug("%s: '%s' - found regulators subnode\n", __func__, dev->name); + + children = pmic_bind_children(dev, regulators_node, pmic_children_info); + if (!children) + debug("%s: %s - no child found\n", __func__, dev->name); + + /* Always return success for this device */ + return 0; +} + +static int mp5416_probe(struct udevice *dev) +{ + debug("%s %s\n", __func__, dev->name); + + return 0; +} + +static struct dm_pmic_ops mp5416_ops = { + .reg_count = mp5416_reg_count, + .read = mp5416_read, + .write = mp5416_write, +}; + +static const struct udevice_id mp5416_ids[] = { + { .compatible = "mps,mp5416", }, + { } +}; + +U_BOOT_DRIVER(pmic_mp5416) = { + .name = "mp5416 pmic", + .id = UCLASS_PMIC, + .of_match = mp5416_ids, + .bind = mp5416_bind, + .probe = mp5416_probe, + .ops = &mp5416_ops, +}; diff --git a/roms/u-boot/drivers/power/pmic/muic_max8997.c b/roms/u-boot/drivers/power/pmic/muic_max8997.c new file mode 100644 index 000000000..969ce9023 --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/muic_max8997.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2012 Samsung Electronics + * Lukasz Majewski <l.majewski@samsung.com> + */ + +#include <common.h> +#include <log.h> +#include <power/pmic.h> +#include <power/power_chrg.h> +#include <power/max8997_muic.h> +#include <i2c.h> +#include <errno.h> + +static int power_chrg_get_type(struct pmic *p) +{ + unsigned int val; + unsigned char charge_type, charger; + + if (pmic_probe(p)) + return CHARGER_NO; + + pmic_reg_read(p, MAX8997_MUIC_STATUS2, &val); + charge_type = val & MAX8997_MUIC_CHG_MASK; + + switch (charge_type) { + case MAX8997_MUIC_CHG_NO: + charger = CHARGER_NO; + break; + case MAX8997_MUIC_CHG_USB: + case MAX8997_MUIC_CHG_USB_D: + charger = CHARGER_USB; + break; + case MAX8997_MUIC_CHG_TA: + case MAX8997_MUIC_CHG_TA_1A: + charger = CHARGER_TA; + break; + case MAX8997_MUIC_CHG_TA_500: + charger = CHARGER_TA_500; + break; + default: + charger = CHARGER_UNKNOWN; + break; + } + + return charger; +} + +static struct power_chrg power_chrg_muic_ops = { + .chrg_type = power_chrg_get_type, +}; + +int power_muic_init(unsigned int bus) +{ + static const char name[] = "MAX8997_MUIC"; + struct pmic *p = pmic_alloc(); + + if (!p) { + printf("%s: POWER allocation error!\n", __func__); + return -ENOMEM; + } + + debug("Board Micro USB Interface Controller init\n"); + + p->name = name; + p->interface = PMIC_I2C; + p->number_of_regs = MUIC_NUM_OF_REGS; + p->hw.i2c.addr = MAX8997_MUIC_I2C_ADDR; + p->hw.i2c.tx_num = 1; + p->bus = bus; + + p->chrg = &power_chrg_muic_ops; + return 0; +} diff --git a/roms/u-boot/drivers/power/pmic/palmas.c b/roms/u-boot/drivers/power/pmic/palmas.c new file mode 100644 index 000000000..6080cbff0 --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/palmas.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2016 Texas Instruments Incorporated, <www.ti.com> + * Keerthy <j-keerthy@ti.com> + */ + +#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <log.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/palmas.h> +#include <dm/device.h> + +static const struct pmic_child_info pmic_children_info[] = { + { .prefix = "ldo", .driver = PALMAS_LDO_DRIVER }, + { .prefix = "smps", .driver = PALMAS_SMPS_DRIVER }, + { }, +}; + +static int palmas_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + if (dm_i2c_write(dev, reg, buff, len)) { + pr_err("write error to device: %p register: %#x!\n", dev, reg); + return -EIO; + } + + return 0; +} + +static int palmas_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + if (dm_i2c_read(dev, reg, buff, len)) { + pr_err("read error from device: %p register: %#x!\n", dev, reg); + return -EIO; + } + + return 0; +} + +static int palmas_bind(struct udevice *dev) +{ + ofnode pmic_node = ofnode_null(), regulators_node; + ofnode subnode; + int children; + + dev_for_each_subnode(subnode, dev) { + const char *name; + char *temp; + + name = ofnode_get_name(subnode); + temp = strstr(name, "pmic"); + if (temp) { + pmic_node = subnode; + break; + } + } + + if (!ofnode_valid(pmic_node)) { + debug("%s: %s pmic subnode not found!\n", __func__, dev->name); + return -ENXIO; + } + + regulators_node = ofnode_find_subnode(pmic_node, "regulators"); + + if (!ofnode_valid(regulators_node)) { + debug("%s: %s reg subnode not found!\n", __func__, dev->name); + return -ENXIO; + } + + children = pmic_bind_children(dev, regulators_node, pmic_children_info); + if (!children) + debug("%s: %s - no child found\n", __func__, dev->name); + + /* Always return success for this device */ + return 0; +} + +static struct dm_pmic_ops palmas_ops = { + .read = palmas_read, + .write = palmas_write, +}; + +static const struct udevice_id palmas_ids[] = { + { .compatible = "ti,tps659038", .data = TPS659038 }, + { .compatible = "ti,tps65917" , .data = TPS65917 }, + { } +}; + +U_BOOT_DRIVER(pmic_palmas) = { + .name = "palmas_pmic", + .id = UCLASS_PMIC, + .of_match = palmas_ids, + .bind = palmas_bind, + .ops = &palmas_ops, +}; diff --git a/roms/u-boot/drivers/power/pmic/pca9450.c b/roms/u-boot/drivers/power/pmic/pca9450.c new file mode 100644 index 000000000..a886647f1 --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/pca9450.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 NXP + */ + +#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <log.h> +#include <asm/global_data.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/pca9450.h> + +DECLARE_GLOBAL_DATA_PTR; + +static const struct pmic_child_info pmic_children_info[] = { + /* buck */ + { .prefix = "b", .driver = PCA9450_REGULATOR_DRIVER}, + /* ldo */ + { .prefix = "l", .driver = PCA9450_REGULATOR_DRIVER}, + { }, +}; + +static int pca9450_reg_count(struct udevice *dev) +{ + return PCA9450_REG_NUM; +} + +static int pca9450_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + if (dm_i2c_write(dev, reg, buff, len)) { + pr_err("write error to device: %p register: %#x!", dev, reg); + return -EIO; + } + + return 0; +} + +static int pca9450_read(struct udevice *dev, uint reg, uint8_t *buff, + int len) +{ + if (dm_i2c_read(dev, reg, buff, len)) { + pr_err("read error from device: %p register: %#x!", dev, reg); + return -EIO; + } + + return 0; +} + +static int pca9450_bind(struct udevice *dev) +{ + int children; + ofnode regulators_node; + + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { + debug("%s: %s regulators subnode not found!", __func__, + dev->name); + return -ENXIO; + } + + debug("%s: '%s' - found regulators subnode\n", __func__, dev->name); + + children = pmic_bind_children(dev, regulators_node, + pmic_children_info); + if (!children) + debug("%s: %s - no child found\n", __func__, dev->name); + + /* Always return success for this device */ + return 0; +} + +static struct dm_pmic_ops pca9450_ops = { + .reg_count = pca9450_reg_count, + .read = pca9450_read, + .write = pca9450_write, +}; + +static const struct udevice_id pca9450_ids[] = { + { .compatible = "nxp,pca9450a", .data = 0x25, }, + { .compatible = "nxp,pca9450b", .data = 0x25, }, + { } +}; + +U_BOOT_DRIVER(pmic_pca9450) = { + .name = "pca9450 pmic", + .id = UCLASS_PMIC, + .of_match = pca9450_ids, + .bind = pca9450_bind, + .ops = &pca9450_ops, +}; diff --git a/roms/u-boot/drivers/power/pmic/pfuze100.c b/roms/u-boot/drivers/power/pmic/pfuze100.c new file mode 100644 index 000000000..65c445697 --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/pfuze100.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc + * Peng Fan <Peng.Fan@freescale.com> + */ + +#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <log.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/pfuze100_pmic.h> +#include <power/pfuze3000_pmic.h> + +static const struct pmic_child_info pmic_children_info[] = { + /* sw[x], swbst */ + { .prefix = "s", .driver = PFUZE100_REGULATOR_DRIVER }, + /* vgen[x], vsnvs, vcc, v33, vcc_sd */ + { .prefix = "v", .driver = PFUZE100_REGULATOR_DRIVER }, + { }, +}; + +static int pfuze100_reg_count(struct udevice *dev) +{ + return dev->driver_data == PFUZE3000 ? PFUZE3000_NUM_OF_REGS : PFUZE100_NUM_OF_REGS; +} + +static int pfuze100_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + if (dm_i2c_write(dev, reg, buff, len)) { + pr_err("write error to device: %p register: %#x!\n", dev, reg); + return -EIO; + } + + return 0; +} + +static int pfuze100_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + if (dm_i2c_read(dev, reg, buff, len)) { + debug("read error from device: %p register: %#x!\n", dev, reg); + return -EIO; + } + + return 0; +} + +static int pfuze100_bind(struct udevice *dev) +{ + ofnode regulators_node; + int children; + + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { + debug("%s: %s regulators subnode not found!\n", __func__, + dev->name); + return -ENXIO; + } + + debug("%s: '%s' - found regulators subnode\n", __func__, dev->name); + + children = pmic_bind_children(dev, regulators_node, pmic_children_info); + if (!children) + debug("%s: %s - no child found\n", __func__, dev->name); + + /* Always return success for this device */ + return 0; +} + +static struct dm_pmic_ops pfuze100_ops = { + .reg_count = pfuze100_reg_count, + .read = pfuze100_read, + .write = pfuze100_write, +}; + +static const struct udevice_id pfuze100_ids[] = { + { .compatible = "fsl,pfuze100", .data = PFUZE100, }, + { .compatible = "fsl,pfuze200", .data = PFUZE200, }, + { .compatible = "fsl,pfuze3000", .data = PFUZE3000, }, + { } +}; + +U_BOOT_DRIVER(pmic_pfuze100) = { + .name = "pfuze100 pmic", + .id = UCLASS_PMIC, + .of_match = pfuze100_ids, + .bind = pfuze100_bind, + .ops = &pfuze100_ops, +}; diff --git a/roms/u-boot/drivers/power/pmic/pm8916.c b/roms/u-boot/drivers/power/pmic/pm8916.c new file mode 100644 index 000000000..5f4386d4a --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/pm8916.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Qualcomm pm8916 pmic driver + * + * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com> + */ +#include <common.h> +#include <dm.h> +#include <power/pmic.h> +#include <spmi/spmi.h> + +#define PID_SHIFT 8 +#define PID_MASK (0xFF << PID_SHIFT) +#define REG_MASK 0xFF + +struct pm8916_priv { + uint32_t usid; /* Slave ID on SPMI bus */ +}; + +static int pm8916_reg_count(struct udevice *dev) +{ + return 0xFFFF; +} + +static int pm8916_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + struct pm8916_priv *priv = dev_get_priv(dev); + + if (len != 1) + return -EINVAL; + + return spmi_reg_write(dev->parent, priv->usid, + (reg & PID_MASK) >> PID_SHIFT, reg & REG_MASK, + *buff); +} + +static int pm8916_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + struct pm8916_priv *priv = dev_get_priv(dev); + int val; + + if (len != 1) + return -EINVAL; + + val = spmi_reg_read(dev->parent, priv->usid, + (reg & PID_MASK) >> PID_SHIFT, reg & REG_MASK); + + if (val < 0) + return val; + *buff = val; + return 0; +} + +static struct dm_pmic_ops pm8916_ops = { + .reg_count = pm8916_reg_count, + .read = pm8916_read, + .write = pm8916_write, +}; + +static const struct udevice_id pm8916_ids[] = { + { .compatible = "qcom,spmi-pmic" }, + { } +}; + +static int pm8916_probe(struct udevice *dev) +{ + struct pm8916_priv *priv = dev_get_priv(dev); + + priv->usid = dev_read_addr(dev); + + if (priv->usid == FDT_ADDR_T_NONE) + return -EINVAL; + + return 0; +} + +U_BOOT_DRIVER(pmic_pm8916) = { + .name = "pmic_pm8916", + .id = UCLASS_PMIC, + .of_match = pm8916_ids, + .bind = dm_scan_fdt_dev, + .probe = pm8916_probe, + .ops = &pm8916_ops, + .priv_auto = sizeof(struct pm8916_priv), +}; diff --git a/roms/u-boot/drivers/power/pmic/pmic-uclass.c b/roms/u-boot/drivers/power/pmic/pmic-uclass.c new file mode 100644 index 000000000..79166b8bb --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/pmic-uclass.c @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2014-2015 Samsung Electronics + * Przemyslaw Marczak <p.marczak@samsung.com> + */ + +#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <log.h> +#include <vsprintf.h> +#include <dm/lists.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h> +#include <power/pmic.h> +#include <linux/ctype.h> + +#if CONFIG_IS_ENABLED(PMIC_CHILDREN) +int pmic_bind_children(struct udevice *pmic, ofnode parent, + const struct pmic_child_info *child_info) +{ + const struct pmic_child_info *info; + struct driver *drv; + struct udevice *child; + const char *node_name; + const char *reg_name; + int bind_count = 0; + ofnode node; + int prefix_len; + int ret; + + debug("%s for '%s' at node offset: %d\n", __func__, pmic->name, + dev_of_offset(pmic)); + + ofnode_for_each_subnode(node, parent) { + node_name = ofnode_get_name(node); + + debug("* Found child node: '%s'\n", node_name); + + child = NULL; + for (info = child_info; info->prefix && info->driver; info++) { + debug(" - compatible prefix: '%s'\n", info->prefix); + + prefix_len = strlen(info->prefix); + if (strncmp(info->prefix, node_name, prefix_len)) { + reg_name = ofnode_read_string(node, + "regulator-name"); + if (!reg_name) + continue; + if (strncmp(info->prefix, reg_name, prefix_len)) + continue; + } + + drv = lists_driver_lookup_name(info->driver); + if (!drv) { + debug(" - driver: '%s' not found!\n", + info->driver); + continue; + } + + debug(" - found child driver: '%s'\n", drv->name); + + ret = device_bind_with_driver_data(pmic, drv, node_name, + 0, node, &child); + if (ret) { + debug(" - child binding error: %d\n", ret); + continue; + } + + debug(" - bound child device: '%s'\n", child->name); + + child->driver_data = trailing_strtol(node_name); + + debug(" - set 'child->driver_data': %lu\n", + child->driver_data); + break; + } + + if (child) + bind_count++; + else + debug(" - compatible prefix not found\n"); + } + + debug("Bound: %d children for PMIC: '%s'\n", bind_count, pmic->name); + return bind_count; +} +#endif + +int pmic_get(const char *name, struct udevice **devp) +{ + return uclass_get_device_by_name(UCLASS_PMIC, name, devp); +} + +int pmic_reg_count(struct udevice *dev) +{ + const struct dm_pmic_ops *ops = dev_get_driver_ops(dev); + + if (!ops || !ops->reg_count) + return -ENOSYS; + + return ops->reg_count(dev); +} + +int pmic_read(struct udevice *dev, uint reg, uint8_t *buffer, int len) +{ + const struct dm_pmic_ops *ops = dev_get_driver_ops(dev); + + if (!buffer) + return -EFAULT; + + if (!ops || !ops->read) + return -ENOSYS; + + return ops->read(dev, reg, buffer, len); +} + +int pmic_write(struct udevice *dev, uint reg, const uint8_t *buffer, int len) +{ + const struct dm_pmic_ops *ops = dev_get_driver_ops(dev); + + if (!buffer) + return -EFAULT; + + if (!ops || !ops->write) + return -ENOSYS; + + return ops->write(dev, reg, buffer, len); +} + +int pmic_reg_read(struct udevice *dev, uint reg) +{ + struct uc_pmic_priv *priv = dev_get_uclass_priv(dev); + u32 val = 0; + int ret; + + if (priv->trans_len < 1 || priv->trans_len > sizeof(val)) { + debug("Wrong transmission size [%d]\n", priv->trans_len); + return -EINVAL; + } + + debug("%s: reg=%x priv->trans_len:%d", __func__, reg, priv->trans_len); + ret = pmic_read(dev, reg, (uint8_t *)&val, priv->trans_len); + debug(", value=%x, ret=%d\n", val, ret); + + return ret ? ret : val; +} + +int pmic_reg_write(struct udevice *dev, uint reg, uint value) +{ + struct uc_pmic_priv *priv = dev_get_uclass_priv(dev); + int ret; + + if (priv->trans_len < 1 || priv->trans_len > sizeof(value)) { + debug("Wrong transmission size [%d]\n", priv->trans_len); + return -EINVAL; + } + + debug("%s: reg=%x, value=%x priv->trans_len:%d", __func__, reg, value, + priv->trans_len); + ret = pmic_write(dev, reg, (uint8_t *)&value, priv->trans_len); + debug(", ret=%d\n", ret); + + return ret; +} + +int pmic_clrsetbits(struct udevice *dev, uint reg, uint clr, uint set) +{ + struct uc_pmic_priv *priv = dev_get_uclass_priv(dev); + u32 val = 0; + int ret; + + if (priv->trans_len < 1 || priv->trans_len > sizeof(val)) { + debug("Wrong transmission size [%d]\n", priv->trans_len); + return -EINVAL; + } + + ret = pmic_read(dev, reg, (uint8_t *)&val, priv->trans_len); + if (ret < 0) + return ret; + + val = (val & ~clr) | set; + return pmic_write(dev, reg, (uint8_t *)&val, priv->trans_len); +} + +static int pmic_pre_probe(struct udevice *dev) +{ + struct uc_pmic_priv *pmic_priv = dev_get_uclass_priv(dev); + + pmic_priv->trans_len = 1; + return 0; +} + +UCLASS_DRIVER(pmic) = { + .id = UCLASS_PMIC, + .name = "pmic", + .pre_probe = pmic_pre_probe, + .per_device_auto = sizeof(struct uc_pmic_priv), +}; diff --git a/roms/u-boot/drivers/power/pmic/pmic_hi6553.c b/roms/u-boot/drivers/power/pmic/pmic_hi6553.c new file mode 100644 index 000000000..80b9078cf --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/pmic_hi6553.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2015 Linaro + * Peter Griffin <peter.griffin@linaro.org> + */ +#include <asm/io.h> +#include <common.h> +#include <linux/delay.h> +#include <power/pmic.h> +#include <power/max8997_muic.h> +#include <power/hi6553_pmic.h> +#include <errno.h> + +u8 *pmussi_base; + +uint8_t hi6553_readb(u32 offset) +{ + return readb(pmussi_base + (offset << 2)); +} + +void hi6553_writeb(u32 offset, uint8_t value) +{ + writeb(value, pmussi_base + (offset << 2)); +} + +int pmic_reg_write(struct pmic *p, u32 reg, u32 val) +{ + if (check_reg(p, reg)) + return -EINVAL; + + hi6553_writeb(reg, (uint8_t)val); + + return 0; +} + +int pmic_reg_read(struct pmic *p, u32 reg, u32 *val) +{ + if (check_reg(p, reg)) + return -EINVAL; + + *val = (u32)hi6553_readb(reg); + + return 0; +} + +static void hi6553_init(void) +{ + int data; + + hi6553_writeb(HI6553_PERI_EN_MARK, 0x1e); + hi6553_writeb(HI6553_NP_REG_ADJ1, 0); + data = HI6553_DISABLE6_XO_CLK_CONN | HI6553_DISABLE6_XO_CLK_NFC | + HI6553_DISABLE6_XO_CLK_RF1 | HI6553_DISABLE6_XO_CLK_RF2; + hi6553_writeb(HI6553_DISABLE6_XO_CLK, data); + + /* configure BUCK0 & BUCK1 */ + hi6553_writeb(HI6553_BUCK01_CTRL2, 0x5e); + hi6553_writeb(HI6553_BUCK0_CTRL7, 0x10); + hi6553_writeb(HI6553_BUCK1_CTRL7, 0x10); + hi6553_writeb(HI6553_BUCK0_CTRL5, 0x1e); + hi6553_writeb(HI6553_BUCK1_CTRL5, 0x1e); + hi6553_writeb(HI6553_BUCK0_CTRL1, 0xfc); + hi6553_writeb(HI6553_BUCK1_CTRL1, 0xfc); + + /* configure BUCK2 */ + hi6553_writeb(HI6553_BUCK2_REG1, 0x4f); + hi6553_writeb(HI6553_BUCK2_REG5, 0x99); + hi6553_writeb(HI6553_BUCK2_REG6, 0x45); + mdelay(1); + hi6553_writeb(HI6553_VSET_BUCK2_ADJ, 0x22); + mdelay(1); + + /* configure BUCK3 */ + hi6553_writeb(HI6553_BUCK3_REG3, 0x02); + hi6553_writeb(HI6553_BUCK3_REG5, 0x99); + hi6553_writeb(HI6553_BUCK3_REG6, 0x41); + hi6553_writeb(HI6553_VSET_BUCK3_ADJ, 0x02); + mdelay(1); + + /* configure BUCK4 */ + hi6553_writeb(HI6553_BUCK4_REG2, 0x9a); + hi6553_writeb(HI6553_BUCK4_REG5, 0x99); + hi6553_writeb(HI6553_BUCK4_REG6, 0x45); + + /* configure LDO20 */ + hi6553_writeb(HI6553_LDO20_REG_ADJ, 0x50); + + hi6553_writeb(HI6553_NP_REG_CHG, 0x0f); + hi6553_writeb(HI6553_CLK_TOP0, 0x06); + hi6553_writeb(HI6553_CLK_TOP3, 0xc0); + hi6553_writeb(HI6553_CLK_TOP4, 0x00); + + /* configure LDO7 & LDO10 for SD slot */ + data = hi6553_readb(HI6553_LDO7_REG_ADJ); + data = (data & 0xf8) | 0x2; + hi6553_writeb(HI6553_LDO7_REG_ADJ, data); + mdelay(5); + /* enable LDO7 */ + hi6553_writeb(HI6553_ENABLE2_LDO1_8, 1 << 6); + mdelay(5); + data = hi6553_readb(HI6553_LDO10_REG_ADJ); + data = (data & 0xf8) | 0x5; + hi6553_writeb(HI6553_LDO10_REG_ADJ, data); + mdelay(5); + /* enable LDO10 */ + hi6553_writeb(HI6553_ENABLE3_LDO9_16, 1 << 1); + mdelay(5); + + /* select 32.764KHz */ + hi6553_writeb(HI6553_CLK19M2_600_586_EN, 0x01); +} + +int power_hi6553_init(u8 *base) +{ + static const char name[] = "HI6553 PMIC"; + struct pmic *p = pmic_alloc(); + + if (!p) { + printf("%s: POWER allocation error!\n", __func__); + return -ENOMEM; + } + + p->name = name; + p->interface = PMIC_NONE; + p->number_of_regs = 44; + pmussi_base = base; + + hi6553_init(); + + puts("HI6553 PMIC init\n"); + + return 0; +} diff --git a/roms/u-boot/drivers/power/pmic/pmic_ltc3676.c b/roms/u-boot/drivers/power/pmic/pmic_ltc3676.c new file mode 100644 index 000000000..00c3e201c --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/pmic_ltc3676.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2014 Gateworks Corporation + * Tim Harvey <tharvey@gateworks.com> + */ + +#include <common.h> +#include <errno.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/ltc3676_pmic.h> + +int power_ltc3676_init(unsigned char bus) +{ + static const char name[] = "LTC3676_PMIC"; + struct pmic *p = pmic_alloc(); + + if (!p) { + printf("%s: POWER allocation error!\n", __func__); + return -ENOMEM; + } + + p->name = name; + p->interface = PMIC_I2C; + p->number_of_regs = LTC3676_NUM_OF_REGS; + p->hw.i2c.addr = CONFIG_POWER_LTC3676_I2C_ADDR; + p->hw.i2c.tx_num = 1; + p->bus = bus; + + return 0; +} diff --git a/roms/u-boot/drivers/power/pmic/pmic_mc34vr500.c b/roms/u-boot/drivers/power/pmic/pmic_mc34vr500.c new file mode 100644 index 000000000..9dd1c46ea --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/pmic_mc34vr500.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2016 Freescale Semiconductor, Inc. + * Hou Zhiqiang <Zhiqiang.Hou@freescale.com> + */ + +#include <common.h> +#include <errno.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/mc34vr500_pmic.h> + +int power_mc34vr500_init(unsigned char bus) +{ + static const char name[] = "MC34VR500"; + struct pmic *p = pmic_alloc(); + + if (!p) { + printf("%s: POWER allocation error!\n", __func__); + return -ENOMEM; + } + + p->name = name; + p->interface = PMIC_I2C; + p->number_of_regs = MC34VR500_NUM_OF_REGS; + p->hw.i2c.addr = MC34VR500_I2C_ADDR; + p->hw.i2c.tx_num = 1; + p->bus = bus; + + return 0; +} diff --git a/roms/u-boot/drivers/power/pmic/pmic_pca9450.c b/roms/u-boot/drivers/power/pmic/pmic_pca9450.c new file mode 100644 index 000000000..8c4d0a923 --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/pmic_pca9450.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 NXP + */ + +#include <common.h> +#include <errno.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/pca9450.h> + +static const char pca9450_name[] = "PCA9450"; + +int power_pca9450_init(unsigned char bus, unsigned char addr) +{ + struct pmic *p = pmic_alloc(); + + if (!p) { + printf("%s: POWER allocation error!\n", __func__); + return -ENOMEM; + } + + p->name = pca9450_name; + p->interface = PMIC_I2C; + p->number_of_regs = PCA9450_REG_NUM; + p->hw.i2c.addr = addr; + p->hw.i2c.tx_num = 1; + p->bus = bus; + + return 0; +} diff --git a/roms/u-boot/drivers/power/pmic/pmic_pfuze100.c b/roms/u-boot/drivers/power/pmic/pmic_pfuze100.c new file mode 100644 index 000000000..c646a0c31 --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/pmic_pfuze100.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2014 Gateworks Corporation + * Tim Harvey <tharvey@gateworks.com> + */ + +#include <common.h> +#include <errno.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/pfuze100_pmic.h> + +int power_pfuze100_init(unsigned char bus) +{ + static const char name[] = "PFUZE100"; + struct pmic *p = pmic_alloc(); + + if (!p) { + printf("%s: POWER allocation error!\n", __func__); + return -ENOMEM; + } + + p->name = name; + p->interface = PMIC_I2C; + p->number_of_regs = PFUZE100_NUM_OF_REGS; + p->hw.i2c.addr = CONFIG_POWER_PFUZE100_I2C_ADDR; + p->hw.i2c.tx_num = 1; + p->bus = bus; + + return 0; +} diff --git a/roms/u-boot/drivers/power/pmic/pmic_pfuze3000.c b/roms/u-boot/drivers/power/pmic/pmic_pfuze3000.c new file mode 100644 index 000000000..1077fa5e9 --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/pmic_pfuze3000.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * Peng Fan <Peng.Fan@freescale.com> + */ + +#include <common.h> +#include <errno.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/pfuze3000_pmic.h> + +int power_pfuze3000_init(unsigned char bus) +{ + static const char name[] = "PFUZE3000"; + struct pmic *p = pmic_alloc(); + + if (!p) { + printf("%s: POWER allocation error!\n", __func__); + return -ENOMEM; + } + + p->name = name; + p->interface = PMIC_I2C; + p->number_of_regs = PFUZE3000_NUM_OF_REGS; + p->hw.i2c.addr = CONFIG_POWER_PFUZE3000_I2C_ADDR; + p->hw.i2c.tx_num = 1; + p->bus = bus; + + return 0; +} diff --git a/roms/u-boot/drivers/power/pmic/pmic_tps62362.c b/roms/u-boot/drivers/power/pmic/pmic_tps62362.c new file mode 100644 index 000000000..59190d6f6 --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/pmic_tps62362.c @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2014 Texas Instruments Incorporated - http://www.ti.com + * Author: Felipe Balbi <balbi@ti.com> + */ + +#include <common.h> +#include <i2c.h> +#include <linux/errno.h> +#include <power/pmic.h> +#include <power/tps62362.h> + +#if CONFIG_IS_ENABLED(DM_I2C) +struct udevice *tps62362_dev __section(".data") = NULL; +#endif + +/** + * tps62362_voltage_update() - Function to change a voltage level, as this + * is a multi-step process. + * @reg: Register address to write to + * @volt_sel: Voltage register value to write + * @return: 0 on success, 1 on failure + */ +int tps62362_voltage_update(unsigned char reg, unsigned char volt_sel) +{ + if (reg > TPS62362_NUM_REGS) + return 1; + +#if !CONFIG_IS_ENABLED(DM_I2C) + return i2c_write(TPS62362_I2C_ADDR, reg, 1, &volt_sel, 1); +#else + if (!tps62362_dev) + return -ENODEV; + return dm_i2c_reg_write(tps62362_dev, reg, volt_sel); +#endif +} + +#if !CONFIG_IS_ENABLED(DM_I2C) +int power_tps62362_init(unsigned char bus) +{ + static const char name[] = "TPS62362"; + struct pmic *p = pmic_alloc(); + + if (!p) { + printf("%s: POWER allocation error!\n", __func__); + return -ENOMEM; + } + + p->name = name; + p->interface = PMIC_I2C; + p->number_of_regs = TPS62362_NUM_REGS; + p->hw.i2c.addr = TPS62362_I2C_ADDR; + p->hw.i2c.tx_num = 1; + p->bus = bus; + + return 0; +} +#else +int power_tps62362_init(unsigned char bus) +{ + struct udevice *dev = NULL; + int rc; + + rc = i2c_get_chip_for_busnum(bus, TPS62362_I2C_ADDR, 1, &dev); + if (rc) + return rc; + tps62362_dev = dev; + return 0; +} +#endif diff --git a/roms/u-boot/drivers/power/pmic/pmic_tps65217.c b/roms/u-boot/drivers/power/pmic/pmic_tps65217.c new file mode 100644 index 000000000..c7f532df4 --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/pmic_tps65217.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2011-2013 + * Texas Instruments, <www.ti.com> + */ + +#include <common.h> +#include <i2c.h> +#include <power/tps65217.h> + +struct udevice *tps65217_dev __section(".data") = NULL; + +/** + * tps65217_reg_read() - Generic function that can read a TPS65217 register + * @src_reg: Source register address + * @src_val: Address of destination variable + * @return: 0 for success, not 0 on failure. + */ +int tps65217_reg_read(uchar src_reg, uchar *src_val) +{ +#if !CONFIG_IS_ENABLED(DM_I2C) + return i2c_read(TPS65217_CHIP_PM, src_reg, 1, src_val, 1); +#else + return dm_i2c_read(tps65217_dev, src_reg, src_val, 1); +#endif +} + +/** + * tps65217_reg_write() - Generic function that can write a TPS65217 PMIC + * register or bit field regardless of protection + * level. + * + * @prot_level: Register password protection. Use + * TPS65217_PROT_LEVEL_NONE, + * TPS65217_PROT_LEVEL_1 or TPS65217_PROT_LEVEL_2 + * @dest_reg: Register address to write. + * @dest_val: Value to write. + * @mask: Bit mask (8 bits) to be applied. Function will only + * change bits that are set in the bit mask. + * + * @return: 0 for success, not 0 on failure, as per the i2c API + */ +int tps65217_reg_write(uchar prot_level, uchar dest_reg, uchar dest_val, + uchar mask) +{ + uchar read_val; + uchar xor_reg; + int ret; + + /* + * If we are affecting only a bit field, read dest_reg and apply the + * mask + */ + if (mask != TPS65217_MASK_ALL_BITS) { +#if !CONFIG_IS_ENABLED(DM_I2C) + ret = i2c_read(TPS65217_CHIP_PM, dest_reg, 1, &read_val, 1); +#else + ret = dm_i2c_read(tps65217_dev, dest_reg, &read_val, 1); +#endif + if (ret) + return ret; + + read_val &= (~mask); + read_val |= (dest_val & mask); + dest_val = read_val; + } + + if (prot_level > 0) { + xor_reg = dest_reg ^ TPS65217_PASSWORD_UNLOCK; +#if !CONFIG_IS_ENABLED(DM_I2C) + ret = i2c_write(TPS65217_CHIP_PM, TPS65217_PASSWORD, 1, + &xor_reg, 1); +#else + ret = dm_i2c_write(tps65217_dev, TPS65217_PASSWORD, + &xor_reg, 1); +#endif + if (ret) + return ret; + } +#if !CONFIG_IS_ENABLED(DM_I2C) + ret = i2c_write(TPS65217_CHIP_PM, dest_reg, 1, &dest_val, 1); +#else + ret = dm_i2c_write(tps65217_dev, dest_reg, &dest_val, 1); +#endif + if (ret) + return ret; + + if (prot_level == TPS65217_PROT_LEVEL_2) { +#if !CONFIG_IS_ENABLED(DM_I2C) + ret = i2c_write(TPS65217_CHIP_PM, TPS65217_PASSWORD, 1, + &xor_reg, 1); +#else + ret = dm_i2c_write(tps65217_dev, TPS65217_PASSWORD, + &xor_reg, 1); +#endif + if (ret) + return ret; + +#if !CONFIG_IS_ENABLED(DM_I2C) + ret = i2c_write(TPS65217_CHIP_PM, dest_reg, 1, &dest_val, 1); +#else + ret = dm_i2c_write(tps65217_dev, dest_reg, &dest_val, 1); +#endif + if (ret) + return ret; + } + + return 0; +} + +/** + * tps65217_voltage_update() - Function to change a voltage level, as this + * is a multi-step process. + * @dc_cntrl_reg: DC voltage control register to change. + * @volt_sel: New value for the voltage register + * @return: 0 for success, not 0 on failure. + */ +int tps65217_voltage_update(uchar dc_cntrl_reg, uchar volt_sel) +{ + if ((dc_cntrl_reg != TPS65217_DEFDCDC1) && + (dc_cntrl_reg != TPS65217_DEFDCDC2) && + (dc_cntrl_reg != TPS65217_DEFDCDC3)) + return 1; + + /* set voltage level */ + if (tps65217_reg_write(TPS65217_PROT_LEVEL_2, dc_cntrl_reg, volt_sel, + TPS65217_MASK_ALL_BITS)) + return 1; + + /* set GO bit to initiate voltage transition */ + if (tps65217_reg_write(TPS65217_PROT_LEVEL_2, TPS65217_DEFSLEW, + TPS65217_DCDC_GO, TPS65217_DCDC_GO)) + return 1; + + return 0; +} + +int power_tps65217_init(unsigned char bus) +{ +#if CONFIG_IS_ENABLED(DM_I2C) + struct udevice *dev = NULL; + int rc; + + rc = i2c_get_chip_for_busnum(bus, TPS65217_CHIP_PM, 1, &dev); + if (rc) + return rc; + tps65217_dev = dev; +#endif + return 0; +} diff --git a/roms/u-boot/drivers/power/pmic/pmic_tps65218.c b/roms/u-boot/drivers/power/pmic/pmic_tps65218.c new file mode 100644 index 000000000..671749018 --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/pmic_tps65218.c @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2011-2013 + * Texas Instruments, <www.ti.com> + */ + +#include <common.h> +#include <i2c.h> +#include <linux/errno.h> +#include <power/pmic.h> +#include <power/tps65218.h> + +#if !CONFIG_IS_ENABLED(DM_I2C) +int tps65218_reg_read(uchar dest_reg, uchar *dest_val) +{ + uchar read_val; + int ret; + + ret = i2c_read(TPS65218_CHIP_PM, dest_reg, 1, &read_val, 1); + if (ret) + return ret; + + *dest_val = read_val; + + return 0; +} + +/** + * tps65218_reg_write() - Generic function that can write a TPS65218 PMIC + * register or bit field regardless of protection + * level. + * + * @prot_level: Register password protection. Use + * TPS65218_PROT_LEVEL_NONE, + * TPS65218_PROT_LEVEL_1 or TPS65218_PROT_LEVEL_2 + * @dest_reg: Register address to write. + * @dest_val: Value to write. + * @mask: Bit mask (8 bits) to be applied. Function will only + * change bits that are set in the bit mask. + * + * @return: 0 for success, not 0 on failure, as per the i2c API + */ +int tps65218_reg_write(uchar prot_level, uchar dest_reg, uchar dest_val, + uchar mask) +{ + uchar read_val; + uchar xor_reg; + int ret; + + /* + * If we are affecting only a bit field, read dest_reg and apply the + * mask + */ + if (mask != TPS65218_MASK_ALL_BITS) { + ret = i2c_read(TPS65218_CHIP_PM, dest_reg, 1, &read_val, 1); + if (ret) + return ret; + read_val &= (~mask); + read_val |= (dest_val & mask); + dest_val = read_val; + } + + if (prot_level > 0) { + xor_reg = dest_reg ^ TPS65218_PASSWORD_UNLOCK; + ret = i2c_write(TPS65218_CHIP_PM, TPS65218_PASSWORD, 1, + &xor_reg, 1); + if (ret) + return ret; + } + + ret = i2c_write(TPS65218_CHIP_PM, dest_reg, 1, &dest_val, 1); + if (ret) + return ret; + + if (prot_level == TPS65218_PROT_LEVEL_2) { + ret = i2c_write(TPS65218_CHIP_PM, TPS65218_PASSWORD, 1, + &xor_reg, 1); + if (ret) + return ret; + + ret = i2c_write(TPS65218_CHIP_PM, dest_reg, 1, &dest_val, 1); + if (ret) + return ret; + } + + return 0; +} +#else +struct udevice *tps65218_dev __section(".data") = NULL; + +int tps65218_reg_read(uchar dest_reg, uchar *dest_val) +{ + uchar read_val; + int ret; + + if (!tps65218_dev) + return -ENODEV; + + ret = dm_i2c_read(tps65218_dev, dest_reg, &read_val, 1); + if (ret) + return ret; + + *dest_val = read_val; + + return 0; +} + +int tps65218_reg_write(uchar prot_level, uchar dest_reg, uchar dest_val, + uchar mask) +{ + uchar read_val; + uchar xor_reg; + int ret; + + if (!tps65218_dev) + return -ENODEV; + + /* + * If we are affecting only a bit field, read dest_reg and apply the + * mask + */ + if (mask != TPS65218_MASK_ALL_BITS) { + ret = dm_i2c_read(tps65218_dev, dest_reg, &read_val, 1); + if (ret) + return ret; + + read_val &= (~mask); + read_val |= (dest_val & mask); + dest_val = read_val; + } + + if (prot_level > 0) { + xor_reg = dest_reg ^ TPS65218_PASSWORD_UNLOCK; + ret = dm_i2c_write(tps65218_dev, TPS65218_PASSWORD, &xor_reg, + 1); + if (ret) + return ret; + } + + ret = dm_i2c_write(tps65218_dev, dest_reg, &dest_val, 1); + if (ret) + return ret; + + if (prot_level == TPS65218_PROT_LEVEL_2) { + ret = dm_i2c_write(tps65218_dev, TPS65218_PASSWORD, &xor_reg, + 1); + if (ret) + return ret; + + ret = dm_i2c_write(tps65218_dev, dest_reg, &dest_val, 1); + if (ret) + return ret; + } + + return 0; +} +#endif + +/** + * tps65218_voltage_update() - Function to change a voltage level, as this + * is a multi-step process. + * @dc_cntrl_reg: DC voltage control register to change. + * @volt_sel: New value for the voltage register + * @return: 0 for success, not 0 on failure. + */ +int tps65218_voltage_update(uchar dc_cntrl_reg, uchar volt_sel) +{ + if ((dc_cntrl_reg != TPS65218_DCDC1) && + (dc_cntrl_reg != TPS65218_DCDC2) && + (dc_cntrl_reg != TPS65218_DCDC3)) + return 1; + + /* set voltage level */ + if (tps65218_reg_write(TPS65218_PROT_LEVEL_2, dc_cntrl_reg, volt_sel, + TPS65218_DCDC_VSEL_MASK)) + return 1; + + /* set GO bit to initiate voltage transition */ + if (tps65218_reg_write(TPS65218_PROT_LEVEL_2, TPS65218_SLEW, + TPS65218_DCDC_GO, TPS65218_DCDC_GO)) + return 1; + + return 0; +} + +/** + * tps65218_toggle_fseal() - Perform the sequence that toggles the FSEAL bit. + * + * @return: 0 on success, -EBADE if the sequence was broken + */ +int tps65218_toggle_fseal(void) +{ + if (tps65218_reg_write(TPS65218_PROT_LEVEL_NONE, TPS65218_PASSWORD, + 0xb1, TPS65218_MASK_ALL_BITS)) + return -EBADE; + + if (tps65218_reg_write(TPS65218_PROT_LEVEL_NONE, TPS65218_PASSWORD, + 0xfe, TPS65218_MASK_ALL_BITS)) + return -EBADE; + + if (tps65218_reg_write(TPS65218_PROT_LEVEL_NONE, TPS65218_PASSWORD, + 0xa3, TPS65218_MASK_ALL_BITS)) + return -EBADE; + + return 0; +} + +/** + * tps65218_lock_fseal() - Perform the sequence that locks the FSEAL bit to 1. + * + * The FSEAL bit prevents the PMIC from turning off DCDC5 and DCDC6. It can be + * toggled at most 3 times: 0->1, 1->0, and finally 0->1. After the third switch + * its value is locked and can only be reset by powering off the PMIC entirely. + * + * @return: 0 on success, -EBADE if the sequence was broken + */ +int tps65218_lock_fseal(void) +{ + int i; + + for (i = 0; i < 3; i++) + if (tps65218_toggle_fseal()) + return -EBADE; + + return 0; +} + +#if !CONFIG_IS_ENABLED(DM_I2C) +int power_tps65218_init(unsigned char bus) +{ + static const char name[] = "TPS65218_PMIC"; + struct pmic *p = pmic_alloc(); + + if (!p) { + printf("%s: POWER allocation error!\n", __func__); + return -ENOMEM; + } + + p->name = name; + p->interface = PMIC_I2C; + p->number_of_regs = TPS65218_PMIC_NUM_OF_REGS; + p->hw.i2c.addr = TPS65218_CHIP_PM; + p->hw.i2c.tx_num = 1; + p->bus = bus; + + return 0; +} +#else +int power_tps65218_init(unsigned char bus) +{ + struct udevice *dev = NULL; + int rc; + + rc = i2c_get_chip_for_busnum(bus, TPS65218_CHIP_PM, 1, &dev); + if (rc) + return rc; + tps65218_dev = dev; + return 0; +} +#endif diff --git a/roms/u-boot/drivers/power/pmic/pmic_tps65910.c b/roms/u-boot/drivers/power/pmic/pmic_tps65910.c new file mode 100644 index 000000000..fcd0a654a --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/pmic_tps65910.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2011-2013 + * Texas Instruments, <www.ti.com> + */ + +#include <common.h> +#include <i2c.h> +#include <power/tps65910.h> + +struct udevice *tps65910_dev __section(".data") = NULL; + +static inline int tps65910_read_reg(int addr, uchar *buf) +{ +#if !CONFIG_IS_ENABLED(DM_I2C) + return i2c_read(TPS65910_CTRL_I2C_ADDR, addr, 1, buf, 1); +#else + int rc; + + rc = dm_i2c_reg_read(tps65910_dev, addr); + if (rc < 0) + return rc; + *buf = (uchar)rc; + return 0; +#endif +} + +static inline int tps65910_write_reg(int addr, uchar *buf) +{ +#if !CONFIG_IS_ENABLED(DM_I2C) + return i2c_write(TPS65910_CTRL_I2C_ADDR, addr, 1, buf, 1); +#else + return dm_i2c_reg_write(tps65910_dev, addr, *buf); +#endif +} + +int power_tps65910_init(unsigned char bus) +{ +#if CONFIG_IS_ENABLED(DM_I2C) + struct udevice *dev = NULL; + int rc; + + rc = i2c_get_chip_for_busnum(bus, TPS65910_CTRL_I2C_ADDR, 1, &dev); + + if (rc) + return rc; + tps65910_dev = dev; +#endif + return 0; +} + +/* + * tps65910_set_i2c_control() - Set the TPS65910 to be controlled via the I2C + * interface. + * @return: 0 on success, not 0 on failure + */ +int tps65910_set_i2c_control(void) +{ + int ret; + uchar buf; + + /* VDD1/2 voltage selection register access by control i/f */ + ret = tps65910_read_reg(TPS65910_DEVCTRL_REG, &buf); + + if (ret) + return ret; + + buf |= TPS65910_DEVCTRL_REG_SR_CTL_I2C_SEL_CTL_I2C; + + return tps65910_write_reg(TPS65910_DEVCTRL_REG, &buf); +} + +/* + * tps65910_voltage_update() - Voltage switching for MPU frequency switching. + * @module: mpu - 0, core - 1 + * @vddx_op_vol_sel: vdd voltage to set + * @return: 0 on success, not 0 on failure + */ +int tps65910_voltage_update(unsigned int module, unsigned char vddx_op_vol_sel) +{ + uchar buf; + unsigned int reg_offset; + int ret; + + if (module == MPU) + reg_offset = TPS65910_VDD1_OP_REG; + else + reg_offset = TPS65910_VDD2_OP_REG; + + /* Select VDDx OP */ + ret = tps65910_read_reg(reg_offset, &buf); + if (ret) + return ret; + + buf &= ~TPS65910_OP_REG_CMD_MASK; + + ret = tps65910_write_reg(reg_offset, &buf); + if (ret) + return ret; + + /* Configure VDDx OP Voltage */ + ret = tps65910_read_reg(reg_offset, &buf); + if (ret) + return ret; + + buf &= ~TPS65910_OP_REG_SEL_MASK; + buf |= vddx_op_vol_sel; + + ret = tps65910_write_reg(reg_offset, &buf); + if (ret) + return ret; + + ret = tps65910_read_reg(reg_offset, &buf); + if (ret) + return ret; + + if ((buf & TPS65910_OP_REG_SEL_MASK) != vddx_op_vol_sel) + return 1; + + return 0; +} diff --git a/roms/u-boot/drivers/power/pmic/pmic_tps65910_dm.c b/roms/u-boot/drivers/power/pmic/pmic_tps65910_dm.c new file mode 100644 index 000000000..e03ddc98d --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/pmic_tps65910_dm.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) EETS GmbH, 2017, Felix Brack <f.brack@eets.ch> + */ + +#include <common.h> +#include <dm.h> +#include <i2c.h> +#include <log.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/tps65910_pmic.h> + +static const struct pmic_child_info pmic_children_info[] = { + { .prefix = "ldo_", .driver = TPS65910_LDO_DRIVER }, + { .prefix = "buck_", .driver = TPS65910_BUCK_DRIVER }, + { .prefix = "boost_", .driver = TPS65910_BOOST_DRIVER }, + { }, +}; + +static int pmic_tps65910_reg_count(struct udevice *dev) +{ + return TPS65910_NUM_REGS; +} + +static int pmic_tps65910_write(struct udevice *dev, uint reg, const u8 *buffer, + int len) +{ + int ret; + + ret = dm_i2c_write(dev, reg, buffer, len); + if (ret) + pr_err("%s write error on register %02x\n", dev->name, reg); + + return ret; +} + +static int pmic_tps65910_read(struct udevice *dev, uint reg, u8 *buffer, + int len) +{ + int ret; + + ret = dm_i2c_read(dev, reg, buffer, len); + if (ret) + pr_err("%s read error on register %02x\n", dev->name, reg); + + return ret; +} + +static int pmic_tps65910_bind(struct udevice *dev) +{ + ofnode regulators_node; + int children; + + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { + debug("%s regulators subnode not found\n", dev->name); + return -EINVAL; + } + + children = pmic_bind_children(dev, regulators_node, pmic_children_info); + if (!children) + debug("%s has no children (regulators)\n", dev->name); + + return 0; +} + +static int pmic_tps65910_probe(struct udevice *dev) +{ + /* use I2C control interface instead of I2C smartreflex interface to + * access smartrefelex registers VDD1_OP_REG, VDD1_SR_REG, VDD2_OP_REG + * and VDD2_SR_REG + */ + return pmic_clrsetbits(dev, TPS65910_REG_DEVICE_CTRL, 0, + TPS65910_I2C_SEL_MASK); +} + +static struct dm_pmic_ops pmic_tps65910_ops = { + .reg_count = pmic_tps65910_reg_count, + .read = pmic_tps65910_read, + .write = pmic_tps65910_write, +}; + +static const struct udevice_id pmic_tps65910_match[] = { + { .compatible = "ti,tps65910" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(pmic_tps65910) = { + .name = "pmic_tps65910", + .id = UCLASS_PMIC, + .of_match = pmic_tps65910_match, + .bind = pmic_tps65910_bind, + .probe = pmic_tps65910_probe, + .ops = &pmic_tps65910_ops, +}; diff --git a/roms/u-boot/drivers/power/pmic/rk8xx.c b/roms/u-boot/drivers/power/pmic/rk8xx.c new file mode 100644 index 000000000..5f442fea6 --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/rk8xx.c @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2015 Google, Inc + * Written by Simon Glass <sjg@chromium.org> + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <log.h> +#include <power/rk8xx_pmic.h> +#include <power/pmic.h> + +static struct reg_data rk817_init_reg[] = { +/* enable the under-voltage protection, + * the under-voltage protection will shutdown the LDO3 and reset the PMIC + */ + { RK817_BUCK4_CMIN, 0x60, 0x60}, +}; + +static const struct pmic_child_info pmic_children_info[] = { + { .prefix = "DCDC_REG", .driver = "rk8xx_buck"}, + { .prefix = "LDO_REG", .driver = "rk8xx_ldo"}, + { .prefix = "SWITCH_REG", .driver = "rk8xx_switch"}, + { }, +}; + +static int rk8xx_reg_count(struct udevice *dev) +{ + return RK808_NUM_OF_REGS; +} + +static int rk8xx_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + int ret; + + ret = dm_i2c_write(dev, reg, buff, len); + if (ret) { + debug("write error to device: %p register: %#x!\n", dev, reg); + return ret; + } + + return 0; +} + +static int rk8xx_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + int ret; + + ret = dm_i2c_read(dev, reg, buff, len); + if (ret) { + debug("read error from device: %p register: %#x!\n", dev, reg); + return ret; + } + + return 0; +} + +#if CONFIG_IS_ENABLED(PMIC_CHILDREN) +static int rk8xx_bind(struct udevice *dev) +{ + ofnode regulators_node; + int children; + + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { + debug("%s: %s regulators subnode not found!\n", __func__, + dev->name); + return -ENXIO; + } + + debug("%s: '%s' - found regulators subnode\n", __func__, dev->name); + + children = pmic_bind_children(dev, regulators_node, pmic_children_info); + if (!children) + debug("%s: %s - no child found\n", __func__, dev->name); + + /* Always return success for this device */ + return 0; +} +#endif + +static int rk8xx_probe(struct udevice *dev) +{ + struct rk8xx_priv *priv = dev_get_priv(dev); + struct reg_data *init_data = NULL; + int init_data_num = 0; + int ret = 0, i, show_variant; + u8 msb, lsb, id_msb, id_lsb; + u8 on_source = 0, off_source = 0; + u8 power_en0, power_en1, power_en2, power_en3; + u8 value; + + /* read Chip variant */ + if (device_is_compatible(dev, "rockchip,rk817") || + device_is_compatible(dev, "rockchip,rk809")) { + id_msb = RK817_ID_MSB; + id_lsb = RK817_ID_LSB; + } else { + id_msb = ID_MSB; + id_lsb = ID_LSB; + } + + ret = rk8xx_read(dev, id_msb, &msb, 1); + if (ret) + return ret; + ret = rk8xx_read(dev, id_lsb, &lsb, 1); + if (ret) + return ret; + + priv->variant = ((msb << 8) | lsb) & RK8XX_ID_MSK; + show_variant = priv->variant; + switch (priv->variant) { + case RK808_ID: + show_variant = 0x808; /* RK808 hardware ID is 0 */ + break; + case RK805_ID: + case RK816_ID: + case RK818_ID: + on_source = RK8XX_ON_SOURCE; + off_source = RK8XX_OFF_SOURCE; + break; + case RK809_ID: + case RK817_ID: + on_source = RK817_ON_SOURCE; + off_source = RK817_OFF_SOURCE; + init_data = rk817_init_reg; + init_data_num = ARRAY_SIZE(rk817_init_reg); + power_en0 = pmic_reg_read(dev, RK817_POWER_EN0); + power_en1 = pmic_reg_read(dev, RK817_POWER_EN1); + power_en2 = pmic_reg_read(dev, RK817_POWER_EN2); + power_en3 = pmic_reg_read(dev, RK817_POWER_EN3); + + value = (power_en0 & 0x0f) | ((power_en1 & 0x0f) << 4); + pmic_reg_write(dev, RK817_POWER_EN_SAVE0, value); + value = (power_en2 & 0x0f) | ((power_en3 & 0x0f) << 4); + pmic_reg_write(dev, RK817_POWER_EN_SAVE1, value); + break; + default: + printf("Unknown PMIC: RK%x!!\n", priv->variant); + return -EINVAL; + } + + for (i = 0; i < init_data_num; i++) { + ret = pmic_clrsetbits(dev, + init_data[i].reg, + init_data[i].mask, + init_data[i].val); + if (ret < 0) { + printf("%s: i2c set reg 0x%x failed, ret=%d\n", + __func__, init_data[i].reg, ret); + } + + debug("%s: reg[0x%x] = 0x%x\n", __func__, init_data[i].reg, + pmic_reg_read(dev, init_data[i].reg)); + } + + printf("PMIC: RK%x ", show_variant); + + if (on_source && off_source) + printf("(on=0x%02x, off=0x%02x)", + pmic_reg_read(dev, on_source), + pmic_reg_read(dev, off_source)); + printf("\n"); + + return 0; +} + +static struct dm_pmic_ops rk8xx_ops = { + .reg_count = rk8xx_reg_count, + .read = rk8xx_read, + .write = rk8xx_write, +}; + +static const struct udevice_id rk8xx_ids[] = { + { .compatible = "rockchip,rk805" }, + { .compatible = "rockchip,rk808" }, + { .compatible = "rockchip,rk809" }, + { .compatible = "rockchip,rk816" }, + { .compatible = "rockchip,rk817" }, + { .compatible = "rockchip,rk818" }, + { } +}; + +U_BOOT_DRIVER(rockchip_rk805) = { + .name = "rockchip_rk805", + .id = UCLASS_PMIC, + .of_match = rk8xx_ids, +#if CONFIG_IS_ENABLED(PMIC_CHILDREN) + .bind = rk8xx_bind, +#endif + .priv_auto = sizeof(struct rk8xx_priv), + .probe = rk8xx_probe, + .ops = &rk8xx_ops, +}; + +DM_DRIVER_ALIAS(rockchip_rk805, rockchip_rk808) diff --git a/roms/u-boot/drivers/power/pmic/rn5t567.c b/roms/u-boot/drivers/power/pmic/rn5t567.c new file mode 100644 index 000000000..d9a8298eb --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/rn5t567.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Toradex AG + * Stefan Agner <stefan.agner@toradex.com> + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <log.h> +#include <linux/libfdt.h> +#include <power/rn5t567_pmic.h> +#include <power/pmic.h> + +static int rn5t567_reg_count(struct udevice *dev) +{ + return RN5T567_NUM_OF_REGS; +} + +static int rn5t567_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + int ret; + + ret = dm_i2c_write(dev, reg, buff, len); + if (ret) { + debug("write error to device: %p register: %#x!\n", dev, reg); + return ret; + } + + return 0; +} + +static int rn5t567_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + int ret; + + ret = dm_i2c_read(dev, reg, buff, len); + if (ret) { + debug("read error from device: %p register: %#x!\n", dev, reg); + return ret; + } + + return 0; +} + +static struct dm_pmic_ops rn5t567_ops = { + .reg_count = rn5t567_reg_count, + .read = rn5t567_read, + .write = rn5t567_write, +}; + +static const struct udevice_id rn5t567_ids[] = { + { .compatible = "ricoh,rn5t567" }, + { } +}; + +U_BOOT_DRIVER(pmic_rn5t567) = { + .name = "rn5t567 pmic", + .id = UCLASS_PMIC, + .of_match = rn5t567_ids, + .ops = &rn5t567_ops, +}; diff --git a/roms/u-boot/drivers/power/pmic/s2mps11.c b/roms/u-boot/drivers/power/pmic/s2mps11.c new file mode 100644 index 000000000..1ba1640a8 --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/s2mps11.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2015 Samsung Electronics + * Przemyslaw Marczak <p.marczak@samsung.com> + */ + +#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <log.h> +#include <power/pmic.h> +#include <power/s2mps11.h> + +static const struct pmic_child_info pmic_children_info[] = { + { .prefix = S2MPS11_OF_LDO_PREFIX, .driver = S2MPS11_LDO_DRIVER }, + { .prefix = S2MPS11_OF_BUCK_PREFIX, .driver = S2MPS11_BUCK_DRIVER }, + { }, +}; + +static int s2mps11_reg_count(struct udevice *dev) +{ + return S2MPS11_REG_COUNT; +} + +static int s2mps11_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + int ret; + + ret = dm_i2c_write(dev, reg, buff, len); + if (ret) + pr_err("write error to device: %p register: %#x!\n", dev, reg); + + return ret; +} + +static int s2mps11_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + int ret; + + ret = dm_i2c_read(dev, reg, buff, len); + if (ret) + pr_err("read error from device: %p register: %#x!\n", dev, reg); + + return ret; +} + +static int s2mps11_probe(struct udevice *dev) +{ + ofnode regulators_node; + int children; + + regulators_node = dev_read_subnode(dev, "voltage-regulators"); + if (!ofnode_valid(regulators_node)) { + debug("%s: %s regulators subnode not found!\n", __func__, + dev->name); + return -ENXIO; + } + + debug("%s: '%s' - found regulators subnode\n", __func__, dev->name); + + children = pmic_bind_children(dev, regulators_node, pmic_children_info); + if (!children) + debug("%s: %s - no child found\n", __func__, dev->name); + + return 0; +} + +static struct dm_pmic_ops s2mps11_ops = { + .reg_count = s2mps11_reg_count, + .read = s2mps11_read, + .write = s2mps11_write, +}; + +static const struct udevice_id s2mps11_ids[] = { + { .compatible = "samsung,s2mps11-pmic" }, + { } +}; + +U_BOOT_DRIVER(pmic_s2mps11) = { + .name = "s2mps11_pmic", + .id = UCLASS_PMIC, + .of_match = s2mps11_ids, + .ops = &s2mps11_ops, + .probe = s2mps11_probe, +}; diff --git a/roms/u-boot/drivers/power/pmic/s5m8767.c b/roms/u-boot/drivers/power/pmic/s5m8767.c new file mode 100644 index 000000000..db6d0357e --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/s5m8767.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2015 Google, Inc + */ + +#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <log.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/s5m8767.h> + +static const struct pmic_child_info pmic_children_info[] = { + { .prefix = "LDO", .driver = S5M8767_LDO_DRIVER }, + { .prefix = "BUCK", .driver = S5M8767_BUCK_DRIVER }, + { }, +}; + +static int s5m8767_reg_count(struct udevice *dev) +{ + return S5M8767_NUM_OF_REGS; +} + +static int s5m8767_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + if (dm_i2c_write(dev, reg, buff, len)) { + pr_err("write error to device: %p register: %#x!\n", dev, reg); + return -EIO; + } + + return 0; +} + +static int s5m8767_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + if (dm_i2c_read(dev, reg, buff, len)) { + pr_err("read error from device: %p register: %#x!\n", dev, reg); + return -EIO; + } + + return 0; +} + +int s5m8767_enable_32khz_cp(struct udevice *dev) +{ + return pmic_clrsetbits(dev, S5M8767_EN32KHZ_CP, 0, 1 << 1); +} + +static int s5m8767_bind(struct udevice *dev) +{ + int children; + ofnode node; + + node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(node)) { + debug("%s: %s regulators subnode not found!\n", __func__, + dev->name); + return -ENXIO; + } + + debug("%s: '%s' - found regulators subnode\n", __func__, dev->name); + + children = pmic_bind_children(dev, node, pmic_children_info); + if (!children) + debug("%s: %s - no child found\n", __func__, dev->name); + + /* Always return success for this device */ + return 0; +} + +static struct dm_pmic_ops s5m8767_ops = { + .reg_count = s5m8767_reg_count, + .read = s5m8767_read, + .write = s5m8767_write, +}; + +static const struct udevice_id s5m8767_ids[] = { + { .compatible = "samsung,s5m8767-pmic" }, + { } +}; + +U_BOOT_DRIVER(pmic_s5m8767) = { + .name = "s5m8767_pmic", + .id = UCLASS_PMIC, + .of_match = s5m8767_ids, + .bind = s5m8767_bind, + .ops = &s5m8767_ops, +}; diff --git a/roms/u-boot/drivers/power/pmic/sandbox.c b/roms/u-boot/drivers/power/pmic/sandbox.c new file mode 100644 index 000000000..d7870915d --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/sandbox.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2015 Samsung Electronics + * Przemyslaw Marczak <p.marczak@samsung.com> + */ + +#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/sandbox_pmic.h> + +static const struct pmic_child_info pmic_children_info[] = { + { .prefix = SANDBOX_OF_LDO_PREFIX, .driver = SANDBOX_LDO_DRIVER }, + { .prefix = SANDBOX_OF_BUCK_PREFIX, .driver = SANDBOX_BUCK_DRIVER }, + { }, +}; + +static int sandbox_pmic_reg_count(struct udevice *dev) +{ + return SANDBOX_PMIC_REG_COUNT; +} + +static int sandbox_pmic_write(struct udevice *dev, uint reg, + const uint8_t *buff, int len) +{ + if (dm_i2c_write(dev, reg, buff, len)) { + pr_err("write error to device: %p register: %#x!\n", dev, reg); + return -EIO; + } + + return 0; +} + +static int sandbox_pmic_read(struct udevice *dev, uint reg, + uint8_t *buff, int len) +{ + if (dm_i2c_read(dev, reg, buff, len)) { + pr_err("read error from device: %p register: %#x!\n", dev, reg); + return -EIO; + } + + return 0; +} + +static int sandbox_pmic_bind(struct udevice *dev) +{ + if (!pmic_bind_children(dev, dev_ofnode(dev), pmic_children_info)) + pr_err("%s:%d PMIC: %s - no child found!", __func__, __LINE__, + dev->name); + + /* Always return success for this device - allows for PMIC I/O */ + return 0; +} + +static struct dm_pmic_ops sandbox_pmic_ops = { + .reg_count = sandbox_pmic_reg_count, + .read = sandbox_pmic_read, + .write = sandbox_pmic_write, +}; + +static const struct udevice_id sandbox_pmic_ids[] = { + { .compatible = "sandbox,pmic" }, + { } +}; + +U_BOOT_DRIVER(sandbox_pmic) = { + .name = "sandbox_pmic", + .id = UCLASS_PMIC, + .of_match = sandbox_pmic_ids, + .bind = sandbox_pmic_bind, + .ops = &sandbox_pmic_ops, +}; diff --git a/roms/u-boot/drivers/power/pmic/stpmic1.c b/roms/u-boot/drivers/power/pmic/stpmic1.c new file mode 100644 index 000000000..2c85410b1 --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/stpmic1.c @@ -0,0 +1,269 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <i2c.h> +#include <misc.h> +#include <sysreset.h> +#include <time.h> +#include <dm/device.h> +#include <dm/device_compat.h> +#include <dm/lists.h> +#include <power/pmic.h> +#include <power/stpmic1.h> + +#define STPMIC1_NUM_OF_REGS 0x100 + +#define STPMIC1_NVM_SIZE 8 +#define STPMIC1_NVM_POLL_TIMEOUT 100000 +#define STPMIC1_NVM_START_ADDRESS 0xf8 + +enum pmic_nvm_op { + SHADOW_READ, + SHADOW_WRITE, + NVM_READ, + NVM_WRITE, +}; + +#if CONFIG_IS_ENABLED(DM_REGULATOR) +static const struct pmic_child_info stpmic1_children_info[] = { + { .prefix = "ldo", .driver = "stpmic1_ldo" }, + { .prefix = "buck", .driver = "stpmic1_buck" }, + { .prefix = "vref_ddr", .driver = "stpmic1_vref_ddr" }, + { .prefix = "pwr_sw", .driver = "stpmic1_pwr_sw" }, + { .prefix = "boost", .driver = "stpmic1_boost" }, + { }, +}; +#endif /* DM_REGULATOR */ + +static int stpmic1_reg_count(struct udevice *dev) +{ + return STPMIC1_NUM_OF_REGS; +} + +static int stpmic1_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + int ret; + + ret = dm_i2c_write(dev, reg, buff, len); + if (ret) + dev_err(dev, "%s: failed to write register %#x :%d", + __func__, reg, ret); + + return ret; +} + +static int stpmic1_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + int ret; + + ret = dm_i2c_read(dev, reg, buff, len); + if (ret) + dev_err(dev, "%s: failed to read register %#x : %d", + __func__, reg, ret); + + return ret; +} + +static int stpmic1_bind(struct udevice *dev) +{ + int ret; +#if CONFIG_IS_ENABLED(DM_REGULATOR) + ofnode regulators_node; + int children; + + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { + dev_dbg(dev, "regulators subnode not found!"); + return -ENXIO; + } + dev_dbg(dev, "found regulators subnode\n"); + + children = pmic_bind_children(dev, regulators_node, + stpmic1_children_info); + if (!children) + dev_dbg(dev, "no child found\n"); +#endif /* DM_REGULATOR */ + + if (!IS_ENABLED(CONFIG_SPL_BUILD)) { + ret = device_bind_driver(dev, "stpmic1-nvm", + "stpmic1-nvm", NULL); + if (ret) + return ret; + } + + if (CONFIG_IS_ENABLED(SYSRESET)) + return device_bind_driver(dev, "stpmic1-sysreset", + "stpmic1-sysreset", NULL); + + return 0; +} + +static struct dm_pmic_ops stpmic1_ops = { + .reg_count = stpmic1_reg_count, + .read = stpmic1_read, + .write = stpmic1_write, +}; + +static const struct udevice_id stpmic1_ids[] = { + { .compatible = "st,stpmic1" }, + { } +}; + +U_BOOT_DRIVER(pmic_stpmic1) = { + .name = "stpmic1_pmic", + .id = UCLASS_PMIC, + .of_match = stpmic1_ids, + .bind = stpmic1_bind, + .ops = &stpmic1_ops, +}; + +#ifndef CONFIG_SPL_BUILD +static int stpmic1_nvm_rw(struct udevice *dev, u8 addr, u8 *buf, int buf_len, + enum pmic_nvm_op op) +{ + unsigned long timeout; + u8 cmd = STPMIC1_NVM_CMD_READ; + int ret, len = buf_len; + + if (addr < STPMIC1_NVM_START_ADDRESS) + return -EACCES; + if (addr + buf_len > STPMIC1_NVM_START_ADDRESS + STPMIC1_NVM_SIZE) + len = STPMIC1_NVM_START_ADDRESS + STPMIC1_NVM_SIZE - addr; + + if (op == SHADOW_READ) { + ret = pmic_read(dev, addr, buf, len); + if (ret < 0) + return ret; + else + return len; + } + + if (op == SHADOW_WRITE) { + ret = pmic_write(dev, addr, buf, len); + if (ret < 0) + return ret; + else + return len; + } + + if (op == NVM_WRITE) { + cmd = STPMIC1_NVM_CMD_PROGRAM; + + ret = pmic_write(dev, addr, buf, len); + if (ret < 0) + return ret; + } + + ret = pmic_reg_read(dev, STPMIC1_NVM_CR); + if (ret < 0) + return ret; + + ret = pmic_reg_write(dev, STPMIC1_NVM_CR, ret | cmd); + if (ret < 0) + return ret; + + timeout = timer_get_us() + STPMIC1_NVM_POLL_TIMEOUT; + for (;;) { + ret = pmic_reg_read(dev, STPMIC1_NVM_SR); + if (ret < 0) + return ret; + + if (!(ret & STPMIC1_NVM_BUSY)) + break; + + if (time_after(timer_get_us(), timeout)) + break; + } + + if (ret & STPMIC1_NVM_BUSY) + return -ETIMEDOUT; + + if (op == NVM_READ) { + ret = pmic_read(dev, addr, buf, len); + if (ret < 0) + return ret; + } + + return len; +} + +static int stpmic1_nvm_read(struct udevice *dev, int offset, + void *buf, int size) +{ + enum pmic_nvm_op op = NVM_READ; + + if (offset < 0) { + op = SHADOW_READ; + offset = -offset; + } + + return stpmic1_nvm_rw(dev->parent, offset, buf, size, op); +} + +static int stpmic1_nvm_write(struct udevice *dev, int offset, + const void *buf, int size) +{ + enum pmic_nvm_op op = NVM_WRITE; + + if (offset < 0) { + op = SHADOW_WRITE; + offset = -offset; + } + + return stpmic1_nvm_rw(dev->parent, offset, (void *)buf, size, op); +} + +static const struct misc_ops stpmic1_nvm_ops = { + .read = stpmic1_nvm_read, + .write = stpmic1_nvm_write, +}; + +U_BOOT_DRIVER(stpmic1_nvm) = { + .name = "stpmic1-nvm", + .id = UCLASS_MISC, + .ops = &stpmic1_nvm_ops, +}; +#endif /* CONFIG_SPL_BUILD */ + +#ifdef CONFIG_SYSRESET +static int stpmic1_sysreset_request(struct udevice *dev, enum sysreset_t type) +{ + struct udevice *pmic_dev = dev->parent; + int ret; + + if (type != SYSRESET_POWER && type != SYSRESET_POWER_OFF) + return -EPROTONOSUPPORT; + + ret = pmic_reg_read(pmic_dev, STPMIC1_MAIN_CR); + if (ret < 0) + return ret; + + ret |= STPMIC1_SWOFF; + ret &= ~STPMIC1_RREQ_EN; + /* request Power Cycle */ + if (type == SYSRESET_POWER) + ret |= STPMIC1_RREQ_EN; + + ret = pmic_reg_write(pmic_dev, STPMIC1_MAIN_CR, ret); + if (ret < 0) + return ret; + + return -EINPROGRESS; +} + +static struct sysreset_ops stpmic1_sysreset_ops = { + .request = stpmic1_sysreset_request, +}; + +U_BOOT_DRIVER(stpmic1_sysreset) = { + .name = "stpmic1-sysreset", + .id = UCLASS_SYSRESET, + .ops = &stpmic1_sysreset_ops, +}; +#endif diff --git a/roms/u-boot/drivers/power/pmic/tps65090.c b/roms/u-boot/drivers/power/pmic/tps65090.c new file mode 100644 index 000000000..b81df0dff --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/tps65090.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2015 Google, Inc + * Written by Simon Glass <sjg@chromium.org> + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <i2c.h> +#include <log.h> +#include <power/pmic.h> +#include <power/tps65090.h> + +static const struct pmic_child_info pmic_children_info[] = { + { .prefix = "fet", .driver = TPS65090_FET_DRIVER }, + { }, +}; + +static int tps65090_reg_count(struct udevice *dev) +{ + return TPS65090_NUM_REGS; +} + +static int tps65090_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + if (dm_i2c_write(dev, reg, buff, len)) { + pr_err("write error to device: %p register: %#x!\n", dev, reg); + return -EIO; + } + + return 0; +} + +static int tps65090_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + int ret; + + ret = dm_i2c_read(dev, reg, buff, len); + if (ret) { + pr_err("read error %d from device: %p register: %#x!\n", ret, + dev, reg); + return -EIO; + } + + return 0; +} + +static int tps65090_bind(struct udevice *dev) +{ + ofnode regulators_node; + int children; + + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { + debug("%s: %s regulators subnode not found!\n", __func__, + dev->name); + return -ENXIO; + } + + debug("%s: '%s' - found regulators subnode\n", __func__, dev->name); + + children = pmic_bind_children(dev, regulators_node, pmic_children_info); + if (!children) + debug("%s: %s - no child found\n", __func__, dev->name); + + /* Always return success for this device */ + return 0; +} + +static struct dm_pmic_ops tps65090_ops = { + .reg_count = tps65090_reg_count, + .read = tps65090_read, + .write = tps65090_write, +}; + +static const struct udevice_id tps65090_ids[] = { + { .compatible = "ti,tps65090" }, + { } +}; + +U_BOOT_DRIVER(pmic_tps65090) = { + .name = "tps65090 pmic", + .id = UCLASS_PMIC, + .of_match = tps65090_ids, + .bind = tps65090_bind, + .ops = &tps65090_ops, +}; diff --git a/roms/u-boot/drivers/power/pmic/tps65941.c b/roms/u-boot/drivers/power/pmic/tps65941.c new file mode 100644 index 000000000..3dfc1918d --- /dev/null +++ b/roms/u-boot/drivers/power/pmic/tps65941.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2019 Texas Instruments Incorporated, <www.ti.com> + * Keerthy <j-keerthy@ti.com> + */ + +#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <log.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/tps65941.h> +#include <dm/device.h> + +static const struct pmic_child_info pmic_children_info[] = { + { .prefix = "ldo", .driver = TPS65941_LDO_DRIVER }, + { .prefix = "buck", .driver = TPS65941_BUCK_DRIVER }, + { }, +}; + +static int tps65941_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + if (dm_i2c_write(dev, reg, buff, len)) { + pr_err("write error to device: %p register: %#x!\n", dev, reg); + return -EIO; + } + + return 0; +} + +static int tps65941_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + if (dm_i2c_read(dev, reg, buff, len)) { + pr_err("read error from device: %p register: %#x!\n", dev, reg); + return -EIO; + } + + return 0; +} + +static int tps65941_bind(struct udevice *dev) +{ + ofnode regulators_node; + int children; + + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { + debug("%s: %s regulators subnode not found!\n", __func__, + dev->name); + return -ENXIO; + } + + debug("%s: '%s' - found regulators subnode\n", __func__, dev->name); + + children = pmic_bind_children(dev, regulators_node, pmic_children_info); + if (!children) + printf("%s: %s - no child found\n", __func__, dev->name); + + /* Probe all the child devices */ + return dm_scan_fdt_dev(dev); +} + +static struct dm_pmic_ops tps65941_ops = { + .read = tps65941_read, + .write = tps65941_write, +}; + +static const struct udevice_id tps65941_ids[] = { + { .compatible = "ti,tps659411", .data = TPS659411 }, + { .compatible = "ti,tps659413", .data = TPS659413 }, + { } +}; + +U_BOOT_DRIVER(pmic_tps65941) = { + .name = "tps65941_pmic", + .id = UCLASS_PMIC, + .of_match = tps65941_ids, + .bind = tps65941_bind, + .ops = &tps65941_ops, +}; |