From 281ca88fab7f6b66a18d494c05a1f1fa39f11075 Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Tue, 13 Sep 2016 14:44:48 -0700 Subject: cros_ec: Add function to read back flash parameters Add support for reading back flash parameters as reported by the ec. Signed-off-by: Moritz Fischer Cc: Simon Glass Cc: u-boot@lists.denx.de Acked-by: Simon Glass --- drivers/misc/cros_ec.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index 5225cdb1c0..bb6e8fe91d 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -790,6 +790,27 @@ static int cros_ec_data_is_erased(const uint32_t *data, int size) return 1; } +/** + * Read back flash parameters + * + * This function reads back parameters of the flash as reported by the EC + * + * @param dev Pointer to device + * @param info Pointer to output flash info struct + */ +int cros_ec_read_flashinfo(struct cros_ec_dev *dev, + struct ec_response_flash_info *info) +{ + int ret; + + ret = ec_command(dev, EC_CMD_FLASH_INFO, 0, + NULL, 0, info, sizeof(*info)); + if (ret < 0) + return ret; + + return ret < sizeof(*info) ? -1 : 0; +} + int cros_ec_flash_write(struct cros_ec_dev *dev, const uint8_t *data, uint32_t offset, uint32_t size) { -- cgit v1.2.3 From 7a71e4891d6fab9f9d54cee72e6012727ef45d82 Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Tue, 13 Sep 2016 14:44:49 -0700 Subject: cros_ec: Add crosec flashinfo command Add command to print out the flash info as reported by the ec. The data read back includes size, write block size, erase block size. Signed-off-by: Moritz Fischer Cc: Simon Glass Cc: u-boot@lists.denx.de Acked-by: Simon Glass --- drivers/misc/cros_ec.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index bb6e8fe91d..05f1f600bd 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -1364,6 +1364,15 @@ static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) printf("Offset: %x\n", offset); printf("Size: %x\n", size); } + } else if (0 == strcmp("flashinfo", cmd)) { + struct ec_response_flash_info p; + + ret = cros_ec_read_flashinfo(dev, &p); + if (!ret) { + printf("Flash size: %u\n", p.flash_size); + printf("Write block size: %u\n", p.write_block_size); + printf("Erase block size: %u\n", p.erase_block_size); + } } else if (0 == strcmp("vbnvcontext", cmd)) { uint8_t block[EC_VBNV_BLOCK_SIZE]; char buf[3]; @@ -1483,6 +1492,7 @@ U_BOOT_CMD( "crosec events Read CROS-EC host events\n" "crosec clrevents [mask] Clear CROS-EC host events\n" "crosec regioninfo Read image info\n" + "crosec flashinfo Read flash info\n" "crosec erase Erase EC image\n" "crosec read [] Read EC image\n" "crosec write [] Write EC image\n" -- cgit v1.2.3 From bae5b97e8ec0fedb50350a14e76648714bc51c99 Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Mon, 12 Sep 2016 12:57:52 -0700 Subject: cros_ec: Fix issue with cros_ec_flash_write command This commit fixes an issue where data is written to an invalid memory location. The issue has been introduced in commit (88364387 cros: add cros_ec_driver) Cc: Simon Glass Cc: u-boot@lists.denx.de Signed-off-by: Moritz Fischer Reviewed-by: Simon Glass --- drivers/misc/cros_ec.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index 05f1f600bd..1e5bcb0c56 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -750,15 +750,24 @@ int cros_ec_flash_erase(struct cros_ec_dev *dev, uint32_t offset, uint32_t size) static int cros_ec_flash_write_block(struct cros_ec_dev *dev, const uint8_t *data, uint32_t offset, uint32_t size) { - struct ec_params_flash_write p; + struct ec_params_flash_write *p; + int ret; - p.offset = offset; - p.size = size; - assert(data && p.size <= EC_FLASH_WRITE_VER0_SIZE); - memcpy(&p + 1, data, p.size); + p = malloc(sizeof(*p) + size); + if (!p) + return -ENOMEM; + + p->offset = offset; + p->size = size; + assert(data && p->size <= EC_FLASH_WRITE_VER0_SIZE); + memcpy(p + 1, data, p->size); - return ec_command_inptr(dev, EC_CMD_FLASH_WRITE, 0, - &p, sizeof(p), NULL, 0) >= 0 ? 0 : -1; + ret = ec_command_inptr(dev, EC_CMD_FLASH_WRITE, 0, + p, sizeof(*p) + size, NULL, 0) >= 0 ? 0 : -1; + + free(p); + + return ret; } /** -- cgit v1.2.3 From 561e624c350ee5c281da46d23aee70b0523d4d39 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 1 Oct 2016 14:43:17 -0600 Subject: dm: mmc: Support erase At present erase is not suported with CONFIG_DM_OPS. Add it so that MMC devices can be erased. Signed-off-by: Simon Glass --- drivers/mmc/mmc-uclass.c | 1 + drivers/mmc/mmc_private.h | 4 ++-- drivers/mmc/mmc_write.c | 10 ++++++++-- 3 files changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index 425abb1b9e..77424cdcea 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -262,6 +262,7 @@ static const struct blk_ops mmc_blk_ops = { .read = mmc_bread, #ifndef CONFIG_SPL_BUILD .write = mmc_bwrite, + .erase = mmc_berase, #endif .select_hwpart = mmc_select_hwpart, }; diff --git a/drivers/mmc/mmc_private.h b/drivers/mmc/mmc_private.h index d8b399e364..03bf24d5fe 100644 --- a/drivers/mmc/mmc_private.h +++ b/drivers/mmc/mmc_private.h @@ -29,15 +29,15 @@ ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, #endif #if !(defined(CONFIG_SPL_BUILD) && !defined(CONFIG_SPL_SAVEENV)) -unsigned long mmc_berase(struct blk_desc *block_dev, lbaint_t start, - lbaint_t blkcnt); #ifdef CONFIG_BLK ulong mmc_bwrite(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, const void *src); +ulong mmc_berase(struct udevice *dev, lbaint_t start, lbaint_t blkcnt); #else ulong mmc_bwrite(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, const void *src); +ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt); #endif #else /* CONFIG_SPL_BUILD and CONFIG_SPL_SAVEENV is not defined */ diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c index 2289640375..54acbf7336 100644 --- a/drivers/mmc/mmc_write.c +++ b/drivers/mmc/mmc_write.c @@ -66,9 +66,15 @@ err_out: return err; } -unsigned long mmc_berase(struct blk_desc *block_dev, lbaint_t start, - lbaint_t blkcnt) +#ifdef CONFIG_BLK +ulong mmc_berase(struct udevice *dev, lbaint_t start, lbaint_t blkcnt) +#else +ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt) +#endif { +#ifdef CONFIG_BLK + struct blk_desc *block_dev = dev_get_uclass_platdata(dev); +#endif int dev_num = block_dev->devnum; int err = 0; u32 start_rem, blkcnt_rem; -- cgit v1.2.3 From 896a74f615d6ffcbbcbec1505b19ed3280fe7873 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 1 Oct 2016 14:43:18 -0600 Subject: dm: blk: Enable CONFIG_BLK if DM_MMC is enabled To speed up conversion to CONFIG_BLK, enable it by default when DM_MMC is enabled. Signed-off-by: Simon Glass --- drivers/block/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 80eea84dc2..fe5aa07f92 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -1,6 +1,7 @@ config BLK bool "Support block devices" depends on DM + default y if DM_MMC help Enable support for block devices, such as SCSI, MMC and USB flash sticks. These provide a block-level interface which permits -- cgit v1.2.3 From 252788b4eda852e0195e1903e55480b4bf4fea9d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 1 Oct 2016 14:43:19 -0600 Subject: dm: mmc: Enable DM_MMC_OPS by default with DM_MMC These two options go together and it is best to do the conversion in one step. So enable DM_MMC_OPS by default if DM_MMC is enabled. Signed-off-by: Simon Glass --- drivers/mmc/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index ba9a7237b4..24f4b285a9 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -19,6 +19,7 @@ config DM_MMC config DM_MMC_OPS bool "Support MMC controller operations using Driver Model" depends on DM_MMC + default y if DM_MMC help Driver model provides a means of supporting device operations. This option moves MMC operations under the control of driver model. The -- cgit v1.2.3 From 477dfe2ffc45720462ff0baca82076d704b785df Mon Sep 17 00:00:00 2001 From: Keerthy Date: Thu, 15 Sep 2016 17:04:06 +0530 Subject: power: regulator: Add support for gpio regulators Add support for gpio regulators. As of now this driver caters to gpio regulators with one gpio. Supports setting voltage values to gpio regulators and retrieving the values. Signed-off-by: Keerthy Reviewed-by: Simon Glass --- drivers/power/regulator/Kconfig | 8 ++ drivers/power/regulator/Makefile | 1 + drivers/power/regulator/gpio-regulator.c | 137 +++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+) create mode 100644 drivers/power/regulator/gpio-regulator.c (limited to 'drivers') diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index c7e88c0081..255eccf4d7 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -68,6 +68,14 @@ config DM_REGULATOR_FIXED features for fixed value regulators. The driver implements get/set api for enable and get only for voltage value. +config DM_REGULATOR_GPIO + bool "Enable Driver Model for GPIO REGULATOR" + depends on DM_REGULATOR + ---help--- + This config enables implementation of driver-model regulator uclass + features for gpio regulators. The driver implements get/set for + voltage value. + config REGULATOR_RK808 bool "Enable driver for RK808 regulators" depends on DM_REGULATOR && PMIC_RK808 diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile index ab461ec3ef..e9ae22e266 100644 --- a/drivers/power/regulator/Makefile +++ b/drivers/power/regulator/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o obj-$(CONFIG_DM_REGULATOR_PFUZE100) += pfuze100.o obj-$(CONFIG_REGULATOR_PWM) += pwm_regulator.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_FIXED) += fixed.o +obj-$(CONFIG_$(SPL_)DM_REGULATOR_GPIO) += gpio-regulator.o obj-$(CONFIG_REGULATOR_RK808) += rk808.o obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o obj-$(CONFIG_DM_REGULATOR_SANDBOX) += sandbox.o diff --git a/drivers/power/regulator/gpio-regulator.c b/drivers/power/regulator/gpio-regulator.c new file mode 100644 index 0000000000..0a60a9cfc6 --- /dev/null +++ b/drivers/power/regulator/gpio-regulator.c @@ -0,0 +1,137 @@ +/* + * (C) Copyright 2016 Texas Instruments Incorporated, + * Keerthy + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define GPIO_REGULATOR_MAX_STATES 2 + +DECLARE_GLOBAL_DATA_PTR; + +struct gpio_regulator_platdata { + struct gpio_desc gpio; /* GPIO for regulator voltage control */ + int states[GPIO_REGULATOR_MAX_STATES]; + int voltages[GPIO_REGULATOR_MAX_STATES]; +}; + +static int gpio_regulator_ofdata_to_platdata(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + struct gpio_regulator_platdata *dev_pdata; + struct gpio_desc *gpio; + const void *blob = gd->fdt_blob; + int node = dev->of_offset; + int ret, count, i, j; + u32 states_array[8]; + + dev_pdata = dev_get_platdata(dev); + uc_pdata = dev_get_uclass_platdata(dev); + if (!uc_pdata) + return -ENXIO; + + /* Set type to gpio */ + uc_pdata->type = REGULATOR_TYPE_GPIO; + + /* + * Get gpio regulator gpio desc + * Assuming one GPIO per regulator. + * Can be extended later to multiple GPIOs + * per gpio-regulator. As of now no instance with multiple + * gpios is presnt + */ + gpio = &dev_pdata->gpio; + ret = gpio_request_by_name(dev, "gpios", 0, gpio, GPIOD_IS_OUT); + if (ret) + debug("regulator gpio - not found! Error: %d", ret); + + count = fdtdec_get_int_array_count(blob, node, "states", + states_array, 8); + + if (!count) + return -EINVAL; + + for (i = 0, j = 0; i < count; i += 2) { + dev_pdata->voltages[j] = states_array[i]; + dev_pdata->states[j] = states_array[i + 1]; + j++; + } + + return 0; +} + +static int gpio_regulator_get_value(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + struct gpio_regulator_platdata *dev_pdata = dev_get_platdata(dev); + int enable; + + if (!dev_pdata->gpio.dev) + return -ENOSYS; + + uc_pdata = dev_get_uclass_platdata(dev); + if (uc_pdata->min_uV > uc_pdata->max_uV) { + debug("Invalid constraints for: %s\n", uc_pdata->name); + return -EINVAL; + } + + enable = dm_gpio_get_value(&dev_pdata->gpio); + if (enable == dev_pdata->states[0]) + return dev_pdata->voltages[0]; + else + return dev_pdata->voltages[1]; +} + +static int gpio_regulator_set_value(struct udevice *dev, int uV) +{ + struct gpio_regulator_platdata *dev_pdata = dev_get_platdata(dev); + int ret; + bool enable; + + if (!dev_pdata->gpio.dev) + return -ENOSYS; + + if (uV == dev_pdata->voltages[0]) + enable = dev_pdata->states[0]; + else if (uV == dev_pdata->voltages[1]) + enable = dev_pdata->states[1]; + else + return -EINVAL; + + ret = dm_gpio_set_value(&dev_pdata->gpio, enable); + if (ret) { + error("Can't set regulator : %s gpio to: %d\n", dev->name, + enable); + return ret; + } + + return 0; +} + +static const struct dm_regulator_ops gpio_regulator_ops = { + .get_value = gpio_regulator_get_value, + .set_value = gpio_regulator_set_value, +}; + +static const struct udevice_id gpio_regulator_ids[] = { + { .compatible = "regulator-gpio" }, + { }, +}; + +U_BOOT_DRIVER(gpio_regulator) = { + .name = "gpio regulator", + .id = UCLASS_REGULATOR, + .ops = &gpio_regulator_ops, + .of_match = gpio_regulator_ids, + .ofdata_to_platdata = gpio_regulator_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct gpio_regulator_platdata), +}; -- cgit v1.2.3 From 33621d247e771168ebaab2218d02e625371d144a Mon Sep 17 00:00:00 2001 From: Keerthy Date: Fri, 30 Sep 2016 09:20:43 +0530 Subject: power: pmic: Palmas: Add the base pmic support Add support to bind the regulators/child nodes with the pmic. Also adds the pmic i2c based read/write funtions to access pmic registers. Signed-off-by: Keerthy Reviewed-by: Simon Glass Reviewed-by: Tom Rini --- drivers/power/pmic/Kconfig | 7 +++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/palmas.c | 104 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 drivers/power/pmic/palmas.c (limited to 'drivers') diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index 13d293a93d..1a85566ff2 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -143,3 +143,10 @@ config PMIC_TPS65090 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. diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 37d9eb5599..6710673a5f 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_PMIC_RK808) += rk808.o obj-$(CONFIG_PMIC_RN5T567) += rn5t567.o obj-$(CONFIG_PMIC_TPS65090) += tps65090.o obj-$(CONFIG_PMIC_S5M8767) += s5m8767.o +obj-$(CONFIG_$(SPL_)PMIC_PALMAS) += palmas.o obj-$(CONFIG_POWER_LTC3676) += pmic_ltc3676.o obj-$(CONFIG_POWER_MAX77696) += pmic_max77696.o diff --git a/drivers/power/pmic/palmas.c b/drivers/power/pmic/palmas.c new file mode 100644 index 0000000000..6c79a93d1b --- /dev/null +++ b/drivers/power/pmic/palmas.c @@ -0,0 +1,104 @@ +/* + * (C) Copyright 2016 Texas Instruments Incorporated, + * Keerthy + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +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)) { + error("write error to device: %p register: %#x!", 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)) { + error("read error from device: %p register: %#x!", dev, reg); + return -EIO; + } + + return 0; +} + +static int palmas_bind(struct udevice *dev) +{ + int pmic_node = -1, regulators_node; + const void *blob = gd->fdt_blob; + int children; + int node = dev->of_offset; + int subnode, len; + + fdt_for_each_subnode(blob, subnode, node) { + const char *name; + char *temp; + + name = fdt_get_name(blob, subnode, &len); + temp = strstr(name, "pmic"); + if (temp) { + pmic_node = subnode; + break; + } + } + + if (pmic_node <= 0) { + debug("%s: %s pmic subnode not found!", __func__, dev->name); + return -ENXIO; + } + + regulators_node = fdt_subnode_offset(blob, pmic_node, "regulators"); + + if (regulators_node <= 0) { + debug("%s: %s reg subnode not found!", __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, +}; -- cgit v1.2.3 From 884d88bc8bf83d15f806350b2a1b86ff73de47f0 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Fri, 30 Sep 2016 09:20:44 +0530 Subject: power: regulator: palmas: Add regulator support The driver provides regulator set/get voltage enable/disable functions for palmas family of PMICs. Signed-off-by: Keerthy Reviewed-by: Simon Glass Reviewed-by: Tom Rini --- drivers/power/regulator/Kconfig | 8 + drivers/power/regulator/Makefile | 1 + drivers/power/regulator/palmas_regulator.c | 453 +++++++++++++++++++++++++++++ 3 files changed, 462 insertions(+) create mode 100644 drivers/power/regulator/palmas_regulator.c (limited to 'drivers') diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index 255eccf4d7..461891c97e 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -133,3 +133,11 @@ config REGULATOR_TPS65090 regulators, one for each FET. The standard regulator interface is supported, but it is only possible to turn the regulators on or off. There is no voltage/current control. + +config DM_REGULATOR_PALMAS + bool "Enable driver for PALMAS PMIC regulators" + depends on PMIC_PALMAS + ---help--- + This enables implementation of driver-model regulator uclass + features for REGULATOR PALMAS and the family of PALMAS PMICs. + The driver implements get/set api for: value and enable. diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile index e9ae22e266..c979b51b59 100644 --- a/drivers/power/regulator/Makefile +++ b/drivers/power/regulator/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_REGULATOR_RK808) += rk808.o obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o obj-$(CONFIG_DM_REGULATOR_SANDBOX) += sandbox.o obj-$(CONFIG_REGULATOR_TPS65090) += tps65090_regulator.o +obj-$(CONFIG_$(SPL_)DM_REGULATOR_PALMAS) += palmas_regulator.o diff --git a/drivers/power/regulator/palmas_regulator.c b/drivers/power/regulator/palmas_regulator.c new file mode 100644 index 0000000000..cce7cd2fc2 --- /dev/null +++ b/drivers/power/regulator/palmas_regulator.c @@ -0,0 +1,453 @@ +/* + * (C) Copyright 2016 + * Texas Instruments Incorporated, + * + * Keerthy + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#define REGULATOR_ON 0x1 +#define REGULATOR_OFF 0x0 + +#define SMPS_MODE_MASK 0x3 +#define SMPS_MODE_SHIFT 0x0 +#define LDO_MODE_MASK 0x1 +#define LDO_MODE_SHIFT 0x0 + +static const char palmas_smps_ctrl[][PALMAS_SMPS_NUM] = { + {0x20, 0x24, 0x28, 0x2c, 0x30, 0x34, 0x38, 0x3c}, + {0x20, 0x24, 0x28, 0x2c, 0x30, 0x34, 0x38}, + {0x20, 0x24, 0x2c, 0x30, 0x38}, +}; + +static const char palmas_smps_volt[][PALMAS_SMPS_NUM] = { + {0x23, 0x27, 0x2b, 0x2f, 0x33, 0x37, 0x3b, 0x3c}, + {0x23, 0x27, 0x2b, 0x2f, 0x33, 0x37, 0x3b}, + {0x23, 0x27, 0x2f, 0x33, 0x3B} +}; + +static const char palmas_ldo_ctrl[][PALMAS_LDO_NUM] = { + {0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x62, 0x64}, + {0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x62, 0x64}, + {0x50, 0x52, 0x54, 0x5e, 0x62} +}; + +static const char palmas_ldo_volt[][PALMAS_LDO_NUM] = { + {0x51, 0x53, 0x55, 0x57, 0x59, 0x5b, 0x5d, 0x5f, 0x61, 0x63, 0x65}, + {0x51, 0x53, 0x55, 0x57, 0x59, 0x5b, 0x5d, 0x5f, 0x61, 0x63, 0x65}, + {0x51, 0x53, 0x55, 0x5f, 0x63} +}; + +static int palmas_smps_enable(struct udevice *dev, int op, bool *enable) +{ + int ret; + unsigned int adr; + struct dm_regulator_uclass_platdata *uc_pdata; + + uc_pdata = dev_get_uclass_platdata(dev); + adr = uc_pdata->ctrl_reg; + + ret = pmic_reg_read(dev->parent, adr); + if (ret < 0) + return ret; + + if (op == PMIC_OP_GET) { + ret &= PALMAS_SMPS_STATUS_MASK; + + if (ret) + *enable = true; + else + *enable = false; + + return 0; + } else if (op == PMIC_OP_SET) { + if (*enable) + ret |= PALMAS_SMPS_MODE_MASK; + else + ret &= ~(PALMAS_SMPS_MODE_MASK); + + ret = pmic_reg_write(dev->parent, adr, ret); + if (ret) + return ret; + } + + return 0; +} + +static int palmas_smps_volt2hex(int uV) +{ + if (uV > PALMAS_LDO_VOLT_MAX) + return -EINVAL; + + if (uV > 1650000) + return (uV - 1000000) / 20000 + 0x6; + + if (uV == 500000) + return 0x6; + else + return 0x6 + ((uV - 500000) / 10000); +} + +static int palmas_smps_hex2volt(int hex, bool range) +{ + unsigned int uV = 0; + + if (hex > PALMAS_SMPS_VOLT_MAX_HEX) + return -EINVAL; + + if (hex < 0x7) + uV = 500000; + else + uV = 500000 + (hex - 0x6) * 10000; + + if (range) + uV *= 2; + + return uV; +} + +static int palmas_smps_val(struct udevice *dev, int op, int *uV) +{ + unsigned int hex, adr; + int ret; + bool range; + struct dm_regulator_uclass_platdata *uc_pdata; + + uc_pdata = dev_get_uclass_platdata(dev); + + if (op == PMIC_OP_GET) + *uV = 0; + + adr = uc_pdata->volt_reg; + + ret = pmic_reg_read(dev->parent, adr); + if (ret < 0) + return ret; + + if (op == PMIC_OP_GET) { + if (ret & PALMAS_SMPS_RANGE_MASK) + range = true; + else + range = false; + + ret &= PALMAS_SMPS_VOLT_MASK; + ret = palmas_smps_hex2volt(ret, range); + if (ret < 0) + return ret; + *uV = ret; + + return 0; + } + + hex = palmas_smps_volt2hex(*uV); + if (hex < 0) + return hex; + + ret &= ~PALMAS_SMPS_VOLT_MASK; + ret |= hex; + if (*uV > 1650000) + ret |= PALMAS_SMPS_RANGE_MASK; + + return pmic_reg_write(dev->parent, adr, ret); +} + +static int palmas_ldo_enable(struct udevice *dev, int op, bool *enable) +{ + int ret; + unsigned int adr; + struct dm_regulator_uclass_platdata *uc_pdata; + + uc_pdata = dev_get_uclass_platdata(dev); + adr = uc_pdata->ctrl_reg; + + ret = pmic_reg_read(dev->parent, adr); + if (ret < 0) + return ret; + + if (op == PMIC_OP_GET) { + ret &= PALMAS_LDO_STATUS_MASK; + + if (ret) + *enable = true; + else + *enable = false; + + return 0; + } else if (op == PMIC_OP_SET) { + if (*enable) + ret |= PALMAS_LDO_MODE_MASK; + else + ret &= ~(PALMAS_LDO_MODE_MASK); + + ret = pmic_reg_write(dev->parent, adr, ret); + if (ret) + return ret; + } + + return 0; +} + +static int palmas_ldo_volt2hex(int uV) +{ + if (uV > PALMAS_LDO_VOLT_MAX) + return -EINVAL; + + return (uV - 850000) / 50000; +} + +static int palmas_ldo_hex2volt(int hex) +{ + if (hex > PALMAS_LDO_VOLT_MAX_HEX) + return -EINVAL; + + if (!hex) + return 0; + + return (hex * 50000) + 850000; +} + +static int palmas_ldo_val(struct udevice *dev, int op, int *uV) +{ + unsigned int hex, adr; + int ret; + + struct dm_regulator_uclass_platdata *uc_pdata; + + if (op == PMIC_OP_GET) + *uV = 0; + + uc_pdata = dev_get_uclass_platdata(dev); + + adr = uc_pdata->volt_reg; + + ret = pmic_reg_read(dev->parent, adr); + if (ret < 0) + return ret; + + if (op == PMIC_OP_GET) { + ret &= PALMAS_LDO_VOLT_MASK; + ret = palmas_ldo_hex2volt(ret); + if (ret < 0) + return ret; + *uV = ret; + return 0; + } + + hex = palmas_ldo_volt2hex(*uV); + if (hex < 0) + return hex; + + ret &= ~PALMAS_LDO_VOLT_MASK; + ret |= hex; + if (*uV > 1650000) + ret |= 0x80; + + return pmic_reg_write(dev->parent, adr, ret); +} + +static int palmas_ldo_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + struct udevice *parent; + + uc_pdata = dev_get_uclass_platdata(dev); + + parent = dev_get_parent(dev); + int type = dev_get_driver_data(parent); + + uc_pdata->type = REGULATOR_TYPE_LDO; + + if (dev->driver_data) { + u8 idx = dev->driver_data - 1; + uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][idx]; + uc_pdata->volt_reg = palmas_ldo_volt[type][idx]; + } else { + /* check for ldoln and ldousb cases */ + if (!strcmp("ldoln", dev->name)) { + uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][9]; + uc_pdata->volt_reg = palmas_ldo_volt[type][9]; + } else if (!strcmp("ldousb", dev->name)) { + uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][10]; + uc_pdata->volt_reg = palmas_ldo_volt[type][10]; + } + } + + return 0; +} + +static int ldo_get_value(struct udevice *dev) +{ + int uV; + int ret; + + ret = palmas_ldo_val(dev, PMIC_OP_GET, &uV); + if (ret) + return ret; + + return uV; +} + +static int ldo_set_value(struct udevice *dev, int uV) +{ + return palmas_ldo_val(dev, PMIC_OP_SET, &uV); +} + +static bool ldo_get_enable(struct udevice *dev) +{ + bool enable = false; + int ret; + + ret = palmas_ldo_enable(dev, PMIC_OP_GET, &enable); + if (ret) + return ret; + + return enable; +} + +static int ldo_set_enable(struct udevice *dev, bool enable) +{ + return palmas_ldo_enable(dev, PMIC_OP_SET, &enable); +} + +static int palmas_smps_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + struct udevice *parent; + int idx; + + uc_pdata = dev_get_uclass_platdata(dev); + + parent = dev_get_parent(dev); + int type = dev_get_driver_data(parent); + + uc_pdata->type = REGULATOR_TYPE_BUCK; + + switch (type) { + case PALMAS: + case TPS659038: + switch (dev->driver_data) { + case 123: + case 12: + uc_pdata->ctrl_reg = palmas_smps_ctrl[type][0]; + uc_pdata->volt_reg = palmas_smps_volt[type][0]; + break; + case 3: + uc_pdata->ctrl_reg = palmas_smps_ctrl[type][1]; + uc_pdata->volt_reg = palmas_smps_volt[type][1]; + break; + case 45: + uc_pdata->ctrl_reg = palmas_smps_ctrl[type][2]; + uc_pdata->volt_reg = palmas_smps_volt[type][2]; + break; + case 6: + case 7: + case 8: + case 9: + case 10: + idx = dev->driver_data - 4; + uc_pdata->ctrl_reg = palmas_smps_ctrl[type][idx]; + uc_pdata->volt_reg = palmas_smps_volt[type][idx]; + break; + + default: + printf("Wrong ID for regulator\n"); + } + break; + + case TPS65917: + switch (dev->driver_data) { + case 1: + case 2: + case 3: + case 4: + case 5: + idx = dev->driver_data - 1; + uc_pdata->ctrl_reg = palmas_smps_ctrl[type][idx]; + uc_pdata->volt_reg = palmas_smps_volt[type][idx]; + break; + + default: + printf("Wrong ID for regulator\n"); + } + break; + + default: + printf("Invalid PMIC ID\n"); + } + + return 0; +} + +static int smps_get_value(struct udevice *dev) +{ + int uV; + int ret; + + ret = palmas_smps_val(dev, PMIC_OP_GET, &uV); + if (ret) + return ret; + + return uV; +} + +static int smps_set_value(struct udevice *dev, int uV) +{ + return palmas_smps_val(dev, PMIC_OP_SET, &uV); +} + +static bool smps_get_enable(struct udevice *dev) +{ + bool enable = false; + int ret; + + ret = palmas_smps_enable(dev, PMIC_OP_GET, &enable); + if (ret) + return ret; + + return enable; +} + +static int smps_set_enable(struct udevice *dev, bool enable) +{ + return palmas_smps_enable(dev, PMIC_OP_SET, &enable); +} + +static const struct dm_regulator_ops palmas_ldo_ops = { + .get_value = ldo_get_value, + .set_value = ldo_set_value, + .get_enable = ldo_get_enable, + .set_enable = ldo_set_enable, +}; + +U_BOOT_DRIVER(palmas_ldo) = { + .name = PALMAS_LDO_DRIVER, + .id = UCLASS_REGULATOR, + .ops = &palmas_ldo_ops, + .probe = palmas_ldo_probe, +}; + +static const struct dm_regulator_ops palmas_smps_ops = { + .get_value = smps_get_value, + .set_value = smps_set_value, + .get_enable = smps_get_enable, + .set_enable = smps_set_enable, +}; + +U_BOOT_DRIVER(palmas_smps) = { + .name = PALMAS_SMPS_DRIVER, + .id = UCLASS_REGULATOR, + .ops = &palmas_smps_ops, + .probe = palmas_smps_probe, +}; -- cgit v1.2.3 From ca1de0b5456e630522c0afe5a556e6851b8afe1e Mon Sep 17 00:00:00 2001 From: Keerthy Date: Fri, 30 Sep 2016 09:34:02 +0530 Subject: power: pmic: lp873x: Add the base pmic support Add support to bind the regulators/child nodes with the pmic. Signed-off-by: Keerthy Reviewed-by: Simon Glass --- drivers/power/pmic/Kconfig | 7 ++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/lp873x.c | 86 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 drivers/power/pmic/lp873x.c (limited to 'drivers') diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index 1a85566ff2..ce204b36ca 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -150,3 +150,10 @@ config PMIC_PALMAS ---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. diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 6710673a5f..cd1c6945cd 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_PMIC_RN5T567) += rn5t567.o obj-$(CONFIG_PMIC_TPS65090) += tps65090.o obj-$(CONFIG_PMIC_S5M8767) += s5m8767.o obj-$(CONFIG_$(SPL_)PMIC_PALMAS) += palmas.o +obj-$(CONFIG_$(SPL_)PMIC_LP873X) += lp873x.o obj-$(CONFIG_POWER_LTC3676) += pmic_ltc3676.o obj-$(CONFIG_POWER_MAX77696) += pmic_max77696.o diff --git a/drivers/power/pmic/lp873x.c b/drivers/power/pmic/lp873x.c new file mode 100644 index 0000000000..307f96bad1 --- /dev/null +++ b/drivers/power/pmic/lp873x.c @@ -0,0 +1,86 @@ +/* + * (C) Copyright 2016 Texas Instruments Incorporated, + * Keerthy + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +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)) { + error("write error to device: %p register: %#x!", 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)) { + error("read error from device: %p register: %#x!", dev, reg); + return -EIO; + } + + return 0; +} + +static int lp873x_bind(struct udevice *dev) +{ + int regulators_node; + const void *blob = gd->fdt_blob; + int children; + int node = dev->of_offset; + + regulators_node = fdt_subnode_offset(blob, node, "regulators"); + + if (regulators_node <= 0) { + printf("%s: %s reg subnode not found!", __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, +}; -- cgit v1.2.3 From 99785de83e8198b5d5468453d49a8735b048983d Mon Sep 17 00:00:00 2001 From: Keerthy Date: Fri, 30 Sep 2016 09:34:03 +0530 Subject: power: regulator: lp873x: Add regulator support The driver provides regulator set/get voltage enable/disable functions for lp873x family of PMICs. Signed-off-by: Keerthy Reviewed-by: Simon Glass --- drivers/power/regulator/Kconfig | 8 + drivers/power/regulator/Makefile | 1 + drivers/power/regulator/lp873x_regulator.c | 357 +++++++++++++++++++++++++++++ 3 files changed, 366 insertions(+) create mode 100644 drivers/power/regulator/lp873x_regulator.c (limited to 'drivers') diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index 461891c97e..f870e8bcc9 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -141,3 +141,11 @@ config DM_REGULATOR_PALMAS This enables implementation of driver-model regulator uclass features for REGULATOR PALMAS and the family of PALMAS PMICs. The driver implements get/set api for: value and enable. + +config DM_REGULATOR_LP873X + bool "Enable driver for LP873X PMIC regulators" + depends on PMIC_LP873X + ---help--- + This enables implementation of driver-model regulator uclass + features for REGULATOR LP873X and the family of LP873X PMICs. + The driver implements get/set api for: value and enable. diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile index c979b51b59..6002c88a6c 100644 --- a/drivers/power/regulator/Makefile +++ b/drivers/power/regulator/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o obj-$(CONFIG_DM_REGULATOR_SANDBOX) += sandbox.o obj-$(CONFIG_REGULATOR_TPS65090) += tps65090_regulator.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_PALMAS) += palmas_regulator.o +obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP873X) += lp873x_regulator.o diff --git a/drivers/power/regulator/lp873x_regulator.c b/drivers/power/regulator/lp873x_regulator.c new file mode 100644 index 0000000000..dcb19ff25c --- /dev/null +++ b/drivers/power/regulator/lp873x_regulator.c @@ -0,0 +1,357 @@ +/* + * (C) Copyright 2016 + * Texas Instruments Incorporated, + * + * Keerthy + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +static const char lp873x_buck_ctrl[LP873X_BUCK_NUM] = {0x2, 0x4}; +static const char lp873x_buck_volt[LP873X_BUCK_NUM] = {0x6, 0x7}; +static const char lp873x_ldo_ctrl[LP873X_LDO_NUM] = {0x8, 0x9}; +static const char lp873x_ldo_volt[LP873X_LDO_NUM] = {0xA, 0xB}; + +static int lp873x_buck_enable(struct udevice *dev, int op, bool *enable) +{ + int ret; + unsigned int adr; + struct dm_regulator_uclass_platdata *uc_pdata; + + uc_pdata = dev_get_uclass_platdata(dev); + adr = uc_pdata->ctrl_reg; + + ret = pmic_reg_read(dev->parent, adr); + if (ret < 0) + return ret; + + if (op == PMIC_OP_GET) { + ret &= LP873X_BUCK_MODE_MASK; + + if (ret) + *enable = true; + else + *enable = false; + + return 0; + } else if (op == PMIC_OP_SET) { + if (*enable) + ret |= LP873X_BUCK_MODE_MASK; + else + ret &= ~(LP873X_BUCK_MODE_MASK); + ret = pmic_reg_write(dev->parent, adr, ret); + if (ret) + return ret; + } + + return 0; +} + +static int lp873x_buck_volt2hex(int uV) +{ + if (uV > LP873X_BUCK_VOLT_MAX) + return -EINVAL; + else if (uV > 1400000) + return (uV - 1420000) / 20000 + 0x9E; + else if (uV > 730000) + return (uV - 735000) / 5000 + 0x18; + else if (uV >= 700000) + return (uV - 700000) / 10000 + 0x1; + else + return -EINVAL; +} + +static int lp873x_buck_hex2volt(int hex) +{ + if (hex > LP873X_BUCK_VOLT_MAX_HEX) + return -EINVAL; + else if (hex > 0x9D) + return 1400000 + (hex - 0x9D) * 20000; + else if (hex > 0x17) + return 730000 + (hex - 0x17) * 5000; + else if (hex >= 0x14) + return 700000 + (hex - 0x14) * 10000; + else + return -EINVAL; +} + +static int lp873x_buck_val(struct udevice *dev, int op, int *uV) +{ + unsigned int hex, adr; + int ret; + struct dm_regulator_uclass_platdata *uc_pdata; + + uc_pdata = dev_get_uclass_platdata(dev); + + if (op == PMIC_OP_GET) + *uV = 0; + + adr = uc_pdata->volt_reg; + + ret = pmic_reg_read(dev->parent, adr); + if (ret < 0) + return ret; + + if (op == PMIC_OP_GET) { + ret &= LP873X_BUCK_VOLT_MASK; + ret = lp873x_buck_hex2volt(ret); + if (ret < 0) + return ret; + *uV = ret; + + return 0; + } + + hex = lp873x_buck_volt2hex(*uV); + if (hex < 0) + return hex; + + ret &= 0x0; + ret |= hex; + + ret = pmic_reg_write(dev->parent, adr, ret); + + return ret; +} + +static int lp873x_ldo_enable(struct udevice *dev, int op, bool *enable) +{ + int ret; + unsigned int adr; + struct dm_regulator_uclass_platdata *uc_pdata; + + uc_pdata = dev_get_uclass_platdata(dev); + adr = uc_pdata->ctrl_reg; + + ret = pmic_reg_read(dev->parent, adr); + if (ret < 0) + return ret; + + if (op == PMIC_OP_GET) { + ret &= LP873X_LDO_MODE_MASK; + + if (ret) + *enable = true; + else + *enable = false; + + return 0; + } else if (op == PMIC_OP_SET) { + if (*enable) + ret |= LP873X_LDO_MODE_MASK; + else + ret &= ~(LP873X_LDO_MODE_MASK); + + ret = pmic_reg_write(dev->parent, adr, ret); + if (ret) + return ret; + } + + return 0; +} + +static int lp873x_ldo_volt2hex(int uV) +{ + if (uV > LP873X_LDO_VOLT_MAX) + return -EINVAL; + + return (uV - 800000) / 100000; +} + +static int lp873x_ldo_hex2volt(int hex) +{ + if (hex > LP873X_LDO_VOLT_MAX_HEX) + return -EINVAL; + + if (!hex) + return 0; + + return (hex * 100000) + 800000; +} + +static int lp873x_ldo_val(struct udevice *dev, int op, int *uV) +{ + unsigned int hex, adr; + int ret; + + struct dm_regulator_uclass_platdata *uc_pdata; + + if (op == PMIC_OP_GET) + *uV = 0; + + uc_pdata = dev_get_uclass_platdata(dev); + + adr = uc_pdata->volt_reg; + + ret = pmic_reg_read(dev->parent, adr); + if (ret < 0) + return ret; + + if (op == PMIC_OP_GET) { + ret &= LP873X_LDO_VOLT_MASK; + ret = lp873x_ldo_hex2volt(ret); + if (ret < 0) + return ret; + *uV = ret; + return 0; + } + + hex = lp873x_ldo_volt2hex(*uV); + if (hex < 0) + return hex; + + ret &= ~LP873X_LDO_VOLT_MASK; + ret |= hex; + if (*uV > 1650000) + ret |= 0x80; + ret = pmic_reg_write(dev->parent, adr, ret); + + return ret; +} + +static int lp873x_ldo_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + + uc_pdata = dev_get_uclass_platdata(dev); + uc_pdata->type = REGULATOR_TYPE_LDO; + + int idx = dev->driver_data; + if (idx >= LP873X_LDO_NUM) { + printf("Wrong ID for regulator\n"); + return -1; + } + + uc_pdata->ctrl_reg = lp873x_ldo_ctrl[idx]; + uc_pdata->volt_reg = lp873x_ldo_volt[idx]; + + return 0; +} + +static int ldo_get_value(struct udevice *dev) +{ + int uV; + int ret; + + ret = lp873x_ldo_val(dev, PMIC_OP_GET, &uV); + if (ret) + return ret; + + return uV; +} + +static int ldo_set_value(struct udevice *dev, int uV) +{ + return lp873x_ldo_val(dev, PMIC_OP_SET, &uV); +} + +static bool ldo_get_enable(struct udevice *dev) +{ + bool enable = false; + int ret; + + ret = lp873x_ldo_enable(dev, PMIC_OP_GET, &enable); + if (ret) + return ret; + + return enable; +} + +static int ldo_set_enable(struct udevice *dev, bool enable) +{ + return lp873x_ldo_enable(dev, PMIC_OP_SET, &enable); +} + +static int lp873x_buck_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + int idx; + + uc_pdata = dev_get_uclass_platdata(dev); + uc_pdata->type = REGULATOR_TYPE_BUCK; + + idx = dev->driver_data; + if (idx >= LP873X_BUCK_NUM) { + printf("Wrong ID for regulator\n"); + return -1; + } + + uc_pdata->ctrl_reg = lp873x_buck_ctrl[idx]; + uc_pdata->volt_reg = lp873x_buck_volt[idx]; + + return 0; +} + +static int buck_get_value(struct udevice *dev) +{ + int uV; + int ret; + + ret = lp873x_buck_val(dev, PMIC_OP_GET, &uV); + if (ret) + return ret; + + return uV; +} + +static int buck_set_value(struct udevice *dev, int uV) +{ + return lp873x_buck_val(dev, PMIC_OP_SET, &uV); +} + +static bool buck_get_enable(struct udevice *dev) +{ + bool enable = false; + int ret; + + + ret = lp873x_buck_enable(dev, PMIC_OP_GET, &enable); + if (ret) + return ret; + + return enable; +} + +static int buck_set_enable(struct udevice *dev, bool enable) +{ + return lp873x_buck_enable(dev, PMIC_OP_SET, &enable); +} + +static const struct dm_regulator_ops lp873x_ldo_ops = { + .get_value = ldo_get_value, + .set_value = ldo_set_value, + .get_enable = ldo_get_enable, + .set_enable = ldo_set_enable, +}; + +U_BOOT_DRIVER(lp873x_ldo) = { + .name = LP873X_LDO_DRIVER, + .id = UCLASS_REGULATOR, + .ops = &lp873x_ldo_ops, + .probe = lp873x_ldo_probe, +}; + +static const struct dm_regulator_ops lp873x_buck_ops = { + .get_value = buck_get_value, + .set_value = buck_set_value, + .get_enable = buck_get_enable, + .set_enable = buck_set_enable, +}; + +U_BOOT_DRIVER(lp873x_buck) = { + .name = LP873X_BUCK_DRIVER, + .id = UCLASS_REGULATOR, + .ops = &lp873x_buck_ops, + .probe = lp873x_buck_probe, +}; -- cgit v1.2.3 From bfeba0173aa45c24bbdba45149716c83258d25f6 Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Tue, 4 Oct 2016 17:08:08 -0700 Subject: cmd: cros_ec: Move crosec commands to cmd subdirectory Move crosec commands from drivers/misc/cros_ec.c to cmd/cros_ec.c Acked-by: Simon Glass Signed-off-by: Moritz Fischer Cc: Simon Glass Cc: Heiko Schocher Cc: Bin Meng Cc: Miao Yan Cc: Masahiro Yamada Cc: Stefan Roese Cc: Przemyslaw Marczak Cc: Maxime Ripard Cc: Nishanth Menon Cc: u-boot@lists.denx.de --- drivers/misc/cros_ec.c | 351 ------------------------------------------------- 1 file changed, 351 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index 1e5bcb0c56..807373053c 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -43,9 +43,6 @@ enum { DECLARE_GLOBAL_DATA_PTR; -/* Note: depends on enum ec_current_image */ -static const char * const ec_current_image_name[] = {"unknown", "RO", "RW"}; - void cros_ec_dump_data(const char *name, int cmd, const uint8_t *data, int len) { #ifdef DEBUG @@ -1164,354 +1161,6 @@ int cros_ec_i2c_tunnel(struct udevice *dev, int port, struct i2c_msg *in, return 0; } -#ifdef CONFIG_CMD_CROS_EC - -/** - * Perform a flash read or write command - * - * @param dev CROS-EC device to read/write - * @param is_write 1 do to a write, 0 to do a read - * @param argc Number of arguments - * @param argv Arguments (2 is region, 3 is address) - * @return 0 for ok, 1 for a usage error or -ve for ec command error - * (negative EC_RES_...) - */ -static int do_read_write(struct cros_ec_dev *dev, int is_write, int argc, - char * const argv[]) -{ - uint32_t offset, size = -1U, region_size; - unsigned long addr; - char *endp; - int region; - int ret; - - region = cros_ec_decode_region(argc - 2, argv + 2); - if (region == -1) - return 1; - if (argc < 4) - return 1; - addr = simple_strtoul(argv[3], &endp, 16); - if (*argv[3] == 0 || *endp != 0) - return 1; - if (argc > 4) { - size = simple_strtoul(argv[4], &endp, 16); - if (*argv[4] == 0 || *endp != 0) - return 1; - } - - ret = cros_ec_flash_offset(dev, region, &offset, ®ion_size); - if (ret) { - debug("%s: Could not read region info\n", __func__); - return ret; - } - if (size == -1U) - size = region_size; - - ret = is_write ? - cros_ec_flash_write(dev, (uint8_t *)addr, offset, size) : - cros_ec_flash_read(dev, (uint8_t *)addr, offset, size); - if (ret) { - debug("%s: Could not %s region\n", __func__, - is_write ? "write" : "read"); - return ret; - } - - return 0; -} - -static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) -{ - struct cros_ec_dev *dev; - struct udevice *udev; - const char *cmd; - int ret = 0; - - if (argc < 2) - return CMD_RET_USAGE; - - cmd = argv[1]; - if (0 == strcmp("init", cmd)) { - /* Remove any existing device */ - ret = uclass_find_device(UCLASS_CROS_EC, 0, &udev); - if (!ret) - device_remove(udev); - ret = uclass_get_device(UCLASS_CROS_EC, 0, &udev); - if (ret) { - printf("Could not init cros_ec device (err %d)\n", ret); - return 1; - } - return 0; - } - - ret = uclass_get_device(UCLASS_CROS_EC, 0, &udev); - if (ret) { - printf("Cannot get cros-ec device (err=%d)\n", ret); - return 1; - } - dev = dev_get_uclass_priv(udev); - if (0 == strcmp("id", cmd)) { - char id[MSG_BYTES]; - - if (cros_ec_read_id(dev, id, sizeof(id))) { - debug("%s: Could not read KBC ID\n", __func__); - return 1; - } - printf("%s\n", id); - } else if (0 == strcmp("info", cmd)) { - struct ec_response_mkbp_info info; - - if (cros_ec_info(dev, &info)) { - debug("%s: Could not read KBC info\n", __func__); - return 1; - } - printf("rows = %u\n", info.rows); - printf("cols = %u\n", info.cols); - printf("switches = %#x\n", info.switches); - } else if (0 == strcmp("curimage", cmd)) { - enum ec_current_image image; - - if (cros_ec_read_current_image(dev, &image)) { - debug("%s: Could not read KBC image\n", __func__); - return 1; - } - printf("%d\n", image); - } else if (0 == strcmp("hash", cmd)) { - struct ec_response_vboot_hash hash; - int i; - - if (cros_ec_read_hash(dev, &hash)) { - debug("%s: Could not read KBC hash\n", __func__); - return 1; - } - - if (hash.hash_type == EC_VBOOT_HASH_TYPE_SHA256) - printf("type: SHA-256\n"); - else - printf("type: %d\n", hash.hash_type); - - printf("offset: 0x%08x\n", hash.offset); - printf("size: 0x%08x\n", hash.size); - - printf("digest: "); - for (i = 0; i < hash.digest_size; i++) - printf("%02x", hash.hash_digest[i]); - printf("\n"); - } else if (0 == strcmp("reboot", cmd)) { - int region; - enum ec_reboot_cmd cmd; - - if (argc >= 3 && !strcmp(argv[2], "cold")) - cmd = EC_REBOOT_COLD; - else { - region = cros_ec_decode_region(argc - 2, argv + 2); - if (region == EC_FLASH_REGION_RO) - cmd = EC_REBOOT_JUMP_RO; - else if (region == EC_FLASH_REGION_RW) - cmd = EC_REBOOT_JUMP_RW; - else - return CMD_RET_USAGE; - } - - if (cros_ec_reboot(dev, cmd, 0)) { - debug("%s: Could not reboot KBC\n", __func__); - return 1; - } - } else if (0 == strcmp("events", cmd)) { - uint32_t events; - - if (cros_ec_get_host_events(dev, &events)) { - debug("%s: Could not read host events\n", __func__); - return 1; - } - printf("0x%08x\n", events); - } else if (0 == strcmp("clrevents", cmd)) { - uint32_t events = 0x7fffffff; - - if (argc >= 3) - events = simple_strtol(argv[2], NULL, 0); - - if (cros_ec_clear_host_events(dev, events)) { - debug("%s: Could not clear host events\n", __func__); - return 1; - } - } else if (0 == strcmp("read", cmd)) { - ret = do_read_write(dev, 0, argc, argv); - if (ret > 0) - return CMD_RET_USAGE; - } else if (0 == strcmp("write", cmd)) { - ret = do_read_write(dev, 1, argc, argv); - if (ret > 0) - return CMD_RET_USAGE; - } else if (0 == strcmp("erase", cmd)) { - int region = cros_ec_decode_region(argc - 2, argv + 2); - uint32_t offset, size; - - if (region == -1) - return CMD_RET_USAGE; - if (cros_ec_flash_offset(dev, region, &offset, &size)) { - debug("%s: Could not read region info\n", __func__); - ret = -1; - } else { - ret = cros_ec_flash_erase(dev, offset, size); - if (ret) { - debug("%s: Could not erase region\n", - __func__); - } - } - } else if (0 == strcmp("regioninfo", cmd)) { - int region = cros_ec_decode_region(argc - 2, argv + 2); - uint32_t offset, size; - - if (region == -1) - return CMD_RET_USAGE; - ret = cros_ec_flash_offset(dev, region, &offset, &size); - if (ret) { - debug("%s: Could not read region info\n", __func__); - } else { - printf("Region: %s\n", region == EC_FLASH_REGION_RO ? - "RO" : "RW"); - printf("Offset: %x\n", offset); - printf("Size: %x\n", size); - } - } else if (0 == strcmp("flashinfo", cmd)) { - struct ec_response_flash_info p; - - ret = cros_ec_read_flashinfo(dev, &p); - if (!ret) { - printf("Flash size: %u\n", p.flash_size); - printf("Write block size: %u\n", p.write_block_size); - printf("Erase block size: %u\n", p.erase_block_size); - } - } else if (0 == strcmp("vbnvcontext", cmd)) { - uint8_t block[EC_VBNV_BLOCK_SIZE]; - char buf[3]; - int i, len; - unsigned long result; - - if (argc <= 2) { - ret = cros_ec_read_vbnvcontext(dev, block); - if (!ret) { - printf("vbnv_block: "); - for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++) - printf("%02x", block[i]); - putc('\n'); - } - } else { - /* - * TODO(clchiou): Move this to a utility function as - * cmd_spi might want to call it. - */ - memset(block, 0, EC_VBNV_BLOCK_SIZE); - len = strlen(argv[2]); - buf[2] = '\0'; - for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++) { - if (i * 2 >= len) - break; - buf[0] = argv[2][i * 2]; - if (i * 2 + 1 >= len) - buf[1] = '0'; - else - buf[1] = argv[2][i * 2 + 1]; - strict_strtoul(buf, 16, &result); - block[i] = result; - } - ret = cros_ec_write_vbnvcontext(dev, block); - } - if (ret) { - debug("%s: Could not %s VbNvContext\n", __func__, - argc <= 2 ? "read" : "write"); - } - } else if (0 == strcmp("test", cmd)) { - int result = cros_ec_test(dev); - - if (result) - printf("Test failed with error %d\n", result); - else - puts("Test passed\n"); - } else if (0 == strcmp("version", cmd)) { - struct ec_response_get_version *p; - char *build_string; - - ret = cros_ec_read_version(dev, &p); - if (!ret) { - /* Print versions */ - printf("RO version: %1.*s\n", - (int)sizeof(p->version_string_ro), - p->version_string_ro); - printf("RW version: %1.*s\n", - (int)sizeof(p->version_string_rw), - p->version_string_rw); - printf("Firmware copy: %s\n", - (p->current_image < - ARRAY_SIZE(ec_current_image_name) ? - ec_current_image_name[p->current_image] : - "?")); - ret = cros_ec_read_build_info(dev, &build_string); - if (!ret) - printf("Build info: %s\n", build_string); - } - } else if (0 == strcmp("ldo", cmd)) { - uint8_t index, state; - char *endp; - - if (argc < 3) - return CMD_RET_USAGE; - index = simple_strtoul(argv[2], &endp, 10); - if (*argv[2] == 0 || *endp != 0) - return CMD_RET_USAGE; - if (argc > 3) { - state = simple_strtoul(argv[3], &endp, 10); - if (*argv[3] == 0 || *endp != 0) - return CMD_RET_USAGE; - ret = cros_ec_set_ldo(udev, index, state); - } else { - ret = cros_ec_get_ldo(udev, index, &state); - if (!ret) { - printf("LDO%d: %s\n", index, - state == EC_LDO_STATE_ON ? - "on" : "off"); - } - } - - if (ret) { - debug("%s: Could not access LDO%d\n", __func__, index); - return ret; - } - } else { - return CMD_RET_USAGE; - } - - if (ret < 0) { - printf("Error: CROS-EC command failed (error %d)\n", ret); - ret = 1; - } - - return ret; -} - -U_BOOT_CMD( - crosec, 6, 1, do_cros_ec, - "CROS-EC utility command", - "init Re-init CROS-EC (done on startup automatically)\n" - "crosec id Read CROS-EC ID\n" - "crosec info Read CROS-EC info\n" - "crosec curimage Read CROS-EC current image\n" - "crosec hash Read CROS-EC hash\n" - "crosec reboot [rw | ro | cold] Reboot CROS-EC\n" - "crosec events Read CROS-EC host events\n" - "crosec clrevents [mask] Clear CROS-EC host events\n" - "crosec regioninfo Read image info\n" - "crosec flashinfo Read flash info\n" - "crosec erase Erase EC image\n" - "crosec read [] Read EC image\n" - "crosec write [] Write EC image\n" - "crosec vbnvcontext [hexstring] Read [write] VbNvContext from EC\n" - "crosec ldo [] Switch/Read LDO state\n" - "crosec test run tests on cros_ec\n" - "crosec version Read CROS-EC version" -); -#endif - UCLASS_DRIVER(cros_ec) = { .id = UCLASS_CROS_EC, .name = "cros_ec", -- cgit v1.2.3