Hi, On 20 October 2014 09:44, Przemyslaw Marczak <p.marc...@samsung.com> wrote: > Hello Simon, > > I missed some of your comments. > > > On 10/11/2014 01:18 AM, Simon Glass wrote: >> >> Hi, >> >> On 10 October 2014 07:32, Przemyslaw Marczak <p.marc...@samsung.com> >> wrote: >>> >>> Hello Simon, >>> >>> >>> On 10/10/2014 05:17 AM, Simon Glass wrote: >>>> >>>> >>>> Hi, >>>> >>>> On 8 October 2014 14:48, Przemyslaw Marczak <p.marc...@samsung.com> >>>> wrote: >>>>> >>>>> >>>>> This is an introduction to driver-model multi class PMIC support. >>>>> It starts with UCLASS_PMIC - a common PMIC class type for I/O, which >>>>> doesn't need to implement any specific operations and features beside >>>>> the platform data, which is the 'struct pmic_platdata' defined in file: >>>>> - 'include/power/pmic.h' >>>>> >>>>> New files: >>>>> - pmic-uclass.c - provides a common code for UCLASS_PMIC drivers >>>>> - pmic_i2c.c - provides dm interface for i2c pmic drivers >>>>> - pmic_spi.c - provides dm interface for spi pmic drivers >>>>> >>>>> Those files are based on a current PMIC framework files and code. >>>>> The new files are introduced to keep code readability and allow to >>>>> make an easy drivers migration. The old pmic framework is still kept >>>>> and full independent. >>>>> >>>>> Changes: >>>>> - new uclass-id: UCLASS_PMIC, >>>>> - new configs: CONFIG_DM_PMIC; CONFIG_DM_PMIC_SPI; CONFIG_DM_PMIC_I2C, >>>>> >>>>> New pmic api is documented in: doc/README.power-framework-dm >>>>> >>>>> Signed-off-by: Przemyslaw Marczak <p.marc...@samsung.com> >>>>> --- >>>>> drivers/power/Makefile | 3 + >>>>> drivers/power/pmic-uclass.c | 255 >>>>> ++++++++++++++++++++++++++++++++++++++++++++ >>>>> drivers/power/pmic_i2c.c | 136 +++++++++++++++++++++++ >>>>> drivers/power/pmic_spi.c | 137 ++++++++++++++++++++++++ >>>>> include/dm/uclass-id.h | 3 + >>>>> include/power/pmic.h | 64 +++++++++++ >>>>> 6 files changed, 598 insertions(+) >>>>> create mode 100644 drivers/power/pmic-uclass.c >>>>> create mode 100644 drivers/power/pmic_i2c.c >>>>> create mode 100644 drivers/power/pmic_spi.c >>>>> >>>>> diff --git a/drivers/power/Makefile b/drivers/power/Makefile >>>>> index dc64e4d..8def501 100644 >>>>> --- a/drivers/power/Makefile >>>>> +++ b/drivers/power/Makefile >>>>> @@ -19,3 +19,6 @@ obj-$(CONFIG_DIALOG_POWER) += power_dialog.o >>>>> obj-$(CONFIG_POWER_FSL) += power_fsl.o >>>>> obj-$(CONFIG_POWER_I2C) += power_i2c.o >>>>> obj-$(CONFIG_POWER_SPI) += power_spi.o >>>>> +obj-$(CONFIG_DM_PMIC_SPI) += pmic_spi.o >>>>> +obj-$(CONFIG_DM_PMIC_I2C) += pmic_i2c.o >>>>> +obj-$(CONFIG_DM_PMIC) += pmic-uclass.o >>>>> diff --git a/drivers/power/pmic-uclass.c b/drivers/power/pmic-uclass.c >>>>> new file mode 100644 >>>>> index 0000000..5e8494b >>>>> --- /dev/null >>>>> +++ b/drivers/power/pmic-uclass.c >>>>> @@ -0,0 +1,255 @@ >>>>> +/* >>>>> + * Copyright (C) 2014 Samsung Electronics >>>>> + * Przemyslaw Marczak <p.marc...@samsung.com> >>>>> + * >>>>> + * SPDX-License-Identifier: GPL-2.0+ >>>>> + */ >>>>> +#include <common.h> >>>>> +#include <linux/types.h> >>>>> +#include <fdtdec.h> >>>>> +#include <power/pmic.h> >>>>> +#include <dm/device-internal.h> >>>>> +#include <dm/uclass-internal.h> >>>>> +#include <dm/root.h> >>>>> +#include <dm/lists.h> >>>>> +#include <i2c.h> >>>>> +#include <compiler.h> >>>>> +#include <errno.h> >>>>> + >>>>> +DECLARE_GLOBAL_DATA_PTR; >>>>> + >>>>> +int pmic_check_reg(struct pmic_platdata *p, unsigned reg) >>>>> +{ >>>>> + if (!p) >>>>> + return -ENODEV; >>>>> + >>>>> + if (reg >= p->regs_num) { >>>>> + error("<reg num> = %d is invalid. Should be less than >>>>> %d", >>>>> + reg, p->regs_num); >>>>> + return -EINVAL; >>>>> + } >>>>> + >>>>> + return 0; >>>>> +} >>>>> + >>>>> +int pmic_reg_write(struct udevice *dev, unsigned reg, unsigned val) >>>>> +{ >>>>> + struct pmic_platdata *p; >>>>> + >>>>> + p = dev_get_platdata(dev); >>>>> + if (!p) >>>>> + return -EPERM; >>>>> + >>>>> + switch (p->interface) { >>>>> + case PMIC_I2C: >>>>> +#ifdef CONFIG_DM_PMIC_I2C >>>>> + return pmic_i2c_reg_write(dev, reg, val); >>>>> +#else >>>>> + return -ENOSYS; >>>>> +#endif >>>>> + case PMIC_SPI: >>>>> +#ifdef CONFIG_DM_PMIC_SPI >>>>> + return pmic_spi_reg_write(dev, reg, val); >>>>> +#else >>>>> + return -ENOSYS; >>>>> +#endif >>>> >>>> >>>> >>>> Perhaps one day we should add another uclass which is some sort of >>>> register cache. It could be implemented by I2C and SPI drivers (or >>>> better perhaps the I2C and SPI uclasses could provide a register cache >>>> uclass device for their main when requested). >>>> >>>> For now this seems fine though. I think the 'return -ENOSYS' can just >>>> go at the end of the function and appear once. >>>> >>> >>> Why do we need the registers cache? >>> This maybe is good for a many read operations at a time in the system, >>> but actually I think, that it is not required for the bootloader >>> purposes. >>> >>> If we write some data - sequential, then we probably would like to check >>> it >>> in the same time, e.g. update some range of I2C registers. >>> >>> I don't know the Chromebook design, but how it could be useful for you? >> >> >> We don't need a register cache - I was just thinking of that from the >> kernel. But it feels like an interface like: >> >> int reg_read(int reg, uint32_t *value) >> int reg_write(int reg, uint32_t value) >> int reg_write_range(int reg_start, int reg_count, uint32_t value[]) >> >> might be useful - it could be implemented for both I2C and SPI. >> > > Ok, now I see. > > >>> >>> >>>>> + default: >>>>> + return -ENODEV; >>>>> + } >>>>> +} >>>>> + >>>>> +int pmic_reg_read(struct udevice *dev, unsigned reg, unsigned *val) >>>>> +{ >>>>> + struct pmic_platdata *p; >>>>> + >>>>> + p = dev_get_platdata(dev); >>>>> + if (!p) >>>>> + return -EPERM; >>>>> + >>>>> + switch (p->interface) { >>>>> + case PMIC_I2C: >>>>> +#ifdef CONFIG_DM_PMIC_I2C >>>>> + return pmic_i2c_reg_read(dev, reg, val); >>>>> +#else >>>>> + return -ENOSYS; >>>>> +#endif >>>>> + case PMIC_SPI: >>>>> +#ifdef CONFIG_DM_PMIC_SPI >>>>> + return pmic_spi_reg_read(dev, reg, val); >>>>> +#else >>>>> + return -ENOSYS; >>>>> +#endif >>>>> + default: >>>>> + return -ENODEV; >>>>> + } >>>>> +} >>>>> + >>>>> +int pmic_probe(struct udevice *dev, struct spi_slave *spi_slave) >>>>> +{ >>>>> + struct pmic_platdata *p; >>>>> + >>>>> + p = dev_get_platdata(dev); >>>>> + if (!p) >>>>> + return -EPERM; >>>>> + >>>>> + switch (p->interface) { >>>>> + case PMIC_I2C: >>>>> +#ifdef CONFIG_DM_PMIC_I2C >>>>> + return pmic_i2c_probe(dev); >>>>> +#else >>>>> + return -ENOSYS; >>>>> +#endif >>>>> + case PMIC_SPI: >>>>> + if (!spi_slave) >>>>> + return -EINVAL; >>>>> +#ifdef CONFIG_DM_PMIC_SPI >>>>> + spi_slave = pmic_spi_probe(dev); >>>>> + if (!spi_slave) >>>>> + return -EIO; >>>>> + >>>>> + return 0; >>>>> +#else >>>>> + return -ENOSYS; >>>>> +#endif >>>>> + default: >>>>> + return -ENODEV; >>>>> + } >>>>> +} >>>>> + >>>>> +struct udevice *pmic_get_by_interface(int uclass_id, int bus, int >>>>> addr_cs) >>>> >>>> >>>> >>>> This is an interesting function! Again we can probably improve things >>>> when we have an i2c uclass. >>>> >>> Thanks! But even if we have i2c uclass, then we also should know how to >>> recognize each device, e.g. in the board code. So the interface and >>> address >>> will probably no change. >> >> >> I'm thinking that one day you could do something like: >> >> // Find the regmap associated with the device >> reg_dev = device_get_child(UCLASS_REGMAP, dev); >> >> // Call the regmap uclass to access registers whether it is I2C or SPI >> regmap_write(reg_dev, value); >> > > This could be an another interesting possible feature of dm. > > >>> >>> >>>>> +{ >>>>> + struct pmic_platdata *pl; >>>>> + struct udevice *dev; >>>>> + struct uclass *uc; >>>>> + int ret; >>>>> + >>>>> + if (uclass_id < 0 || uclass_id >= UCLASS_COUNT) { >>>>> + error("Bad uclass id.\n"); >>>>> + return NULL; >>>>> + } >>>>> + >>>>> + ret = uclass_get(uclass_id, &uc); >>>>> + if (ret) { >>>>> + error("PMIC uclass: %d not initialized!\n", uclass_id); >>>>> + return NULL; >>>>> + } >>>>> + >>>>> + uclass_foreach_dev(dev, uc) { >>>>> + if (!dev || !dev->platdata) >>>>> + continue; >>>>> + >>>>> + pl = dev_get_platdata(dev); >>>>> + >>>>> + if (pl->bus != bus) >>>>> + continue; >>>>> + >>>>> + switch (pl->interface) { >>>>> + case PMIC_I2C: >>>>> + if (addr_cs != pl->hw.i2c.addr) >>>>> + continue; >>>>> + break; >>>>> + case PMIC_SPI: >>>>> + if (addr_cs != pl->hw.spi.cs) >>>>> + continue; >>>>> + break; >>>>> + default: >>>>> + error("Unsupported interface of: %s", >>>>> dev->name); >>>>> + return NULL; >>>>> + } >>>>> + >>>>> + ret = device_probe(dev); >>>>> + if (ret) { >>>>> + error("Dev: %s probe failed", dev->name); >>>>> + return NULL; >>>>> + } >>>>> + return dev; >>>>> + } >>>>> + >>>>> + return NULL; >>>>> +} >>>>> + >>>>> +struct udevice *pmic_get_by_name(int uclass_id, char *name) >>>>> +{ >>>>> + struct udevice *dev; >>>>> + struct uclass *uc; >>>>> + int ret; >>>>> + >>>>> + if (uclass_id < 0 || uclass_id >= UCLASS_COUNT) { >>>>> + error("Bad uclass id.\n"); >>>>> + return NULL; >>>>> + } >>>>> + >>>>> + ret = uclass_get(uclass_id, &uc); >>>>> + if (ret) { >>>>> + error("PMIC uclass: %d not initialized!", uclass_id); >>>>> + return NULL; >>>>> + } >>>>> + >>>>> + uclass_foreach_dev(dev, uc) { >>>>> + if (!dev) >>>>> + continue; >>>>> + >>>>> + if (!strncmp(name, dev->name, strlen(name))) { >>>>> + ret = device_probe(dev); >>>>> + if (ret) >>>>> + error("Dev: %s probe failed", >>>>> dev->name); >>>>> + return dev; >>>>> + } >>>>> + } >>>>> + >>>>> + return NULL; >>>>> +} >>>>> + >>>>> +int pmic_init_dm(void) >>>> >>>> >>>> >>>> I don't understand why you need this function at all. Driver model >>>> should find the pmics automatically. Is it because we don't have an >>>> i2c uclass? In that case I think it would be better to limit this hack >>>> to I2C. For SPI it should work correctly without this function. >>>> >>> Currently, it shouldn't and yes - it isn't because of the I2C uclass >>> missing. So no one check the I2C nodes - and its child subnodes. >>> Actually, this can be easy fixed - just don't add the "pmic" alias to the >>> dts. But I will also change fix the code. >>> >>> And by the way - is there any check in the code, which protects for the >>> device bind more than once? >> >> >> No there is no such check at present. >> >>> >>> >>>>> +{ >>>>> + const void *blob = gd->fdt_blob; >>>>> + const struct fdt_property *prop; >>>>> + struct udevice *dev = NULL; >>>>> + const char *path; >>>>> + const char *alias; >>>>> + int alias_node, node, offset, ret = 0; >>>>> + int alias_len; >>>>> + int len; >>>>> + >>>>> + alias = "pmic"; >>>>> + alias_len = strlen(alias); >>>>> + >>>>> + alias_node = fdt_path_offset(blob, "/aliases"); >>>>> + offset = fdt_first_property_offset(blob, alias_node); >>>>> + >>>>> + if (offset < 0) { >>>>> + error("Alias node not found."); >>>>> + return -ENODEV; >>>>> + } >>>>> + >>>>> + offset = fdt_first_property_offset(blob, alias_node); >>>>> + for (; offset > 0; offset = fdt_next_property_offset(blob, >>>>> offset)) { >>>>> + prop = fdt_get_property_by_offset(blob, offset, &len); >>>>> + if (!len) >>>>> + continue; >>>>> + >>>>> + path = fdt_string(blob, fdt32_to_cpu(prop->nameoff)); >>>>> + >>>>> + if (!strncmp(alias, path, alias_len)) >>>>> + node = fdt_path_offset(blob, prop->data); >>>>> + else >>>>> + node = 0; >>>>> + >>>>> + if (node <= 0) >>>>> + continue; >>>>> + >>>>> + ret = lists_bind_fdt(gd->dm_root, blob, node, &dev); >>>>> + if (ret < 0) >>>>> + continue; >>>>> + >>>>> + if (device_probe(dev)) >>>>> + error("Device: %s, probe error", dev->name); >>>>> + } >>>>> + >>>>> + return 0; >>>>> +} >>>>> + >>>>> +UCLASS_DRIVER(pmic) = { >>>>> + .id = UCLASS_PMIC, >>>>> + .name = "pmic", >>>>> +}; >>>>> diff --git a/drivers/power/pmic_i2c.c b/drivers/power/pmic_i2c.c >>>>> new file mode 100644 >>>>> index 0000000..350d375 >>>>> --- /dev/null >>>>> +++ b/drivers/power/pmic_i2c.c >>>>> @@ -0,0 +1,136 @@ >>>>> +/* >>>>> + * Copyright (C) 2014 Samsung Electronics >>>>> + * Przemyslaw Marczak <p.marc...@samsung.com> >>>>> + * >>>>> + * Copyright (C) 2011 Samsung Electronics >>>>> + * Lukasz Majewski <l.majew...@samsung.com> >>>>> + * >>>>> + * (C) Copyright 2010 >>>>> + * Stefano Babic, DENX Software Engineering, sba...@denx.de >>>>> + * >>>>> + * (C) Copyright 2008-2009 Freescale Semiconductor, Inc. >>>>> + * >>>>> + * SPDX-License-Identifier: GPL-2.0+ >>>>> + */ >>>>> + >>>>> +#include <common.h> >>>>> +#include <linux/types.h> >>>>> +#include <power/pmic.h> >>>>> +#include <errno.h> >>>>> +#include <dm.h> >>>>> +#include <i2c.h> >>>>> + >>>>> +int pmic_i2c_reg_write(struct udevice *dev, unsigned reg, unsigned >>>>> val) >>>>> +{ >>>>> + struct pmic_platdata *p; >>>>> + unsigned char buf[4] = { 0 }; >>>>> + >>>>> + if (!dev) >>>>> + return -ENODEV; >>>>> + >>>>> + p = dev->platdata; >>>>> + >>>>> + if (pmic_check_reg(p, reg)) >>>>> + return -EINVAL; >>>>> + >>>>> + I2C_SET_BUS(p->bus); >>>>> + >>>>> + switch (pmic_i2c_tx_num) { >>>>> + case 3: >>>>> + if (p->byte_order == PMIC_SENSOR_BYTE_ORDER_BIG) { >>>>> + buf[2] = (cpu_to_le32(val) >> 16) & 0xff; >>>>> + buf[1] = (cpu_to_le32(val) >> 8) & 0xff; >>>>> + buf[0] = cpu_to_le32(val) & 0xff; >>>>> + } else { >>>>> + buf[0] = (cpu_to_le32(val) >> 16) & 0xff; >>>>> + buf[1] = (cpu_to_le32(val) >> 8) & 0xff; >>>>> + buf[2] = cpu_to_le32(val) & 0xff; >>>>> + } >>>>> + break; >>>>> + case 2: >>>>> + if (p->byte_order == PMIC_SENSOR_BYTE_ORDER_BIG) { >>>>> + buf[1] = (cpu_to_le32(val) >> 8) & 0xff; >>>>> + buf[0] = cpu_to_le32(val) & 0xff; >>>>> + } else { >>>>> + buf[0] = (cpu_to_le32(val) >> 8) & 0xff; >>>>> + buf[1] = cpu_to_le32(val) & 0xff; >>>>> + } >>>>> + break; >>>>> + case 1: >>>>> + buf[0] = cpu_to_le32(val) & 0xff; >>>>> + break; >>>>> + default: >>>>> + printf("%s: invalid tx_num: %d", __func__, >>>>> pmic_i2c_tx_num); >>>>> + return -1; >>>>> + } >>>>> + >>>>> + if (i2c_write(pmic_i2c_addr, reg, 1, buf, pmic_i2c_tx_num)) >>>>> + return -1; >>>>> + >>>>> + return 0; >>>>> +} >>>>> + >>>>> +int pmic_i2c_reg_read(struct udevice *dev, unsigned reg, unsigned >>>>> *val) >>>>> +{ >>>>> + struct pmic_platdata *p; >>>>> + unsigned char buf[4] = { 0 }; >>>>> + u32 ret_val = 0; >>>>> + >>>>> + if (!dev) >>>>> + return -ENODEV; >>>>> + >>>>> + p = dev->platdata; >>>>> + >>>>> + if (pmic_check_reg(p, reg)) >>>>> + return -EINVAL; >>>>> + >>>>> + I2C_SET_BUS(p->bus); >>>>> + >>>>> + if (i2c_read(pmic_i2c_addr, reg, 1, buf, pmic_i2c_tx_num)) >>>>> + return -1; >>>>> + >>>>> + switch (pmic_i2c_tx_num) { >>>>> + case 3: >>>>> + if (p->byte_order == PMIC_SENSOR_BYTE_ORDER_BIG) >>>>> + ret_val = le32_to_cpu(buf[2] << 16 >>>>> + | buf[1] << 8 | buf[0]); >>>>> + else >>>>> + ret_val = le32_to_cpu(buf[0] << 16 | >>>>> + buf[1] << 8 | buf[2]); >>>>> + break; >>>>> + case 2: >>>>> + if (p->byte_order == PMIC_SENSOR_BYTE_ORDER_BIG) >>>>> + ret_val = le32_to_cpu(buf[1] << 8 | buf[0]); >>>>> + else >>>>> + ret_val = le32_to_cpu(buf[0] << 8 | buf[1]); >>>>> + break; >>>>> + case 1: >>>>> + ret_val = le32_to_cpu(buf[0]); >>>>> + break; >>>>> + default: >>>>> + printf("%s: invalid tx_num: %d", __func__, >>>>> pmic_i2c_tx_num); >>>>> + return -1; >>>>> + } >>>>> + memcpy(val, &ret_val, sizeof(ret_val)); >>>>> + >>>>> + return 0; >>>>> +} >>>>> + >>>>> +int pmic_i2c_probe(struct udevice *dev) >>>>> +{ >>>>> + struct pmic_platdata *p; >>>>> + >>>>> + if (!dev) >>>>> + return -ENODEV; >>>>> + >>>>> + p = dev->platdata; >>>>> + >>>>> + i2c_set_bus_num(p->bus); >>>>> + debug("Bus: %d PMIC:%s probed!\n", p->bus, dev->name); >>>>> + if (i2c_probe(pmic_i2c_addr)) { >>>>> + printf("Can't find PMIC:%s\n", dev->name); >>>>> + return -1; >>>>> + } >>>>> + >>>>> + return 0; >>>>> +} >>>>> diff --git a/drivers/power/pmic_spi.c b/drivers/power/pmic_spi.c >>>>> new file mode 100644 >>>>> index 0000000..7851adf >>>>> --- /dev/null >>>>> +++ b/drivers/power/pmic_spi.c >>>>> @@ -0,0 +1,137 @@ >>>>> +/* >>>>> + * Copyright (C) 2014 Samsung Electronics >>>>> + * Przemyslaw Marczak <p.marc...@samsung.com> >>>>> + * >>>>> + * Copyright (C) 2011 Samsung Electronics >>>>> + * Lukasz Majewski <l.majew...@samsung.com> >>>>> + * >>>>> + * (C) Copyright 2010 >>>>> + * Stefano Babic, DENX Software Engineering, sba...@denx.de >>>>> + * >>>>> + * (C) Copyright 2008-2009 Freescale Semiconductor, Inc. >>>>> + * >>>>> + * SPDX-License-Identifier: GPL-2.0+ >>>>> + */ >>>>> + >>>>> +#include <common.h> >>>>> +#include <linux/types.h> >>>>> +#include <power/pmic.h> >>>>> +#include <errno.h> >>>>> +#include <dm.h> >>>>> +#include <spi.h> >>>>> + >>>>> +static struct spi_slave *slave; >>>>> + >>>>> +void pmic_spi_free(struct spi_slave *slave) >>>>> +{ >>>>> + if (slave) >>>>> + spi_free_slave(slave); >>>>> +} >>>>> + >>>>> +struct spi_slave *pmic_spi_probe(struct udevice *dev) >>>>> +{ >>>>> + struct pmic_platdata *p; >>>>> + >>>>> + if (!dev) >>>>> + return NULL; >>>>> + >>>>> + p = dev->platdata; >>>>> + >>>>> + if (pmic_check_reg(p, reg)) >>>>> + return NULL; >>>>> + >>>>> + return spi_setup_slave(p->bus, >>>>> + p->hw.spi.cs, >>>>> + p->hw.spi.clk, >>>>> + p->hw.spi.mode); >>>>> +} >>>>> + >>>>> +static int pmic_spi_reg(struct udevice *dev, unsigned reg, unsigned >>>>> *val, >>>>> + int write) >>>>> +{ >>>>> + struct pmic_platdata *p; >>>>> + u32 pmic_tx, pmic_rx; >>>>> + u32 tmp; >>>>> + >>>>> + if (!dev) >>>>> + return -EINVAL; >>>>> + >>>>> + p = dev->platdata; >>>>> + >>>>> + if (pmic_check_reg(p, reg)) >>>>> + return -EFAULT; >>>>> + >>>>> + if (!slave) { >>>>> + slave = pmic_spi_probe(p); >>>>> + >>>>> + if (!slave) >>>>> + return -ENODEV; >>>>> + } >>>>> + >>>>> + if (pmic_check_reg(p, reg)) >>>>> + return -EFAULT; >>>>> + >>>>> + if (spi_claim_bus(slave)) >>>>> + return -EIO; >>>>> + >>>>> + pmic_tx = p->hw.spi.prepare_tx(reg, val, write); >>>>> + >>>>> + tmp = cpu_to_be32(pmic_tx); >>>>> + >>>>> + if (spi_xfer(slave, pmic_spi_bitlen, &tmp, &pmic_rx, >>>>> + pmic_spi_flags)) { >>>>> + spi_release_bus(slave); >>>>> + return -EIO; >>>>> + } >>>>> + >>>>> + if (write) { >>>>> + pmic_tx = p->hw.spi.prepare_tx(reg, val, 0); >>>>> + tmp = cpu_to_be32(pmic_tx); >>>>> + if (spi_xfer(slave, pmic_spi_bitlen, &tmp, &pmic_rx, >>>>> + pmic_spi_flags)) { >>>>> + spi_release_bus(slave); >>>>> + return -EIO; >>>>> + } >>>>> + } >>>>> + >>>>> + spi_release_bus(slave); >>>>> + *val = cpu_to_be32(pmic_rx); >>>>> + >>>>> + return 0; >>>>> +} >>>>> + >>>>> +int pmic_spi_reg_write(struct udevice *dev, unsigned reg, unsigned >>>>> val) >>>>> +{ >>>>> + struct pmic_platdata *p; >>>>> + >>>>> + if (!dev) >>>>> + return -EINVAL; >>>>> + >>>>> + p = dev->platdata; >>>>> + >>>>> + if (pmic_check_reg(p, reg)) >>>>> + return -EFAULT; >>>>> + >>>>> + if (pmic_spi_reg(p, reg, &val, 1)) >>>>> + return -1; >>>>> + >>>>> + return 0; >>>>> +} >>>>> + >>>>> +int pmic_spi_reg_read(struct udevice *dev, unsigned reg, unsigned >>>>> *val) >>>>> +{ >>>>> + struct pmic_platdata *p; >>>>> + >>>>> + if (!dev) >>>>> + return -EINVAL; >>>>> + >>>>> + p = dev->platdata; >>>>> + >>>>> + if (pmic_check_reg(p, reg)) >>>>> + return -EFAULT; >>>>> + >>>>> + if (pmic_spi_reg(p, reg, val, 0)) >>>>> + return -1; >>>>> + >>>>> + return 0; >>>>> +} >>>>> diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h >>>>> index e3e9296..e6d9d39 100644 >>>>> --- a/include/dm/uclass-id.h >>>>> +++ b/include/dm/uclass-id.h >>>>> @@ -29,6 +29,9 @@ enum uclass_id { >>>>> UCLASS_SPI_FLASH, /* SPI flash */ >>>>> UCLASS_CROS_EC, /* Chrome OS EC */ >>>>> >>>>> + /* PMIC uclass and PMIC related uclasses */ >>>>> + UCLASS_PMIC, >>>>> + >>>>> UCLASS_COUNT, >>>>> UCLASS_INVALID = -1, >>>>> }; >>>>> diff --git a/include/power/pmic.h b/include/power/pmic.h >>>>> index afbc5aa..7114650 100644 >>>>> --- a/include/power/pmic.h >>>>> +++ b/include/power/pmic.h >>>>> @@ -1,4 +1,7 @@ >>>>> /* >>>>> + * Copyright (C) 2014 Samsung Electronics >>>>> + * Przemyslaw Marczak <p.marc...@samsung.com> >>>>> + * >>>>> * Copyright (C) 2011-2012 Samsung Electronics >>>>> * Lukasz Majewski <l.majew...@samsung.com> >>>>> * >>>>> @@ -8,9 +11,12 @@ >>>>> #ifndef __CORE_PMIC_H_ >>>>> #define __CORE_PMIC_H_ >>>>> >>>>> +#include <dm.h> >>>>> #include <linux/list.h> >>>>> +#include <spi.h> >>>>> #include <i2c.h> >>>>> #include <power/power_chrg.h> >>>>> +#include <power/regulator.h> >>>>> >>>>> enum { PMIC_I2C, PMIC_SPI, PMIC_NONE}; >>>>> enum { I2C_PMIC, I2C_NUM, }; >>>>> @@ -78,6 +84,63 @@ struct pmic { >>>>> struct list_head list; >>>>> }; >>>>> >>>>> +#ifdef CONFIG_DM_PMIC >>>>> +/* struct pmic_platdata - a standard descriptor for pmic device, which >>>>> holds >>>>> + * an informations about interface. It is common for all pmic devices. >>>>> + * >>>>> + * Note: >>>>> + * Interface fields are the same as in: struct pmic. >>>>> + * Note: struct pmic will be removed in the future after drivers >>>>> migration >>>>> + * >>>>> + * @bus - a physical bus on which device is connected >>>>> + * @interface - an interface type, one of enum: PMIC_I2C, PMIC_SPI, >>>>> PMIC_NONE >>>>> + * @byte_order - one of enum: PMIC_SENSOR_BYTE_ORDER*_LITTLE/_BIG >>>>> + * @regs_num - number of device registers >>>>> + * @hw - one of union structure: p_i2c or p_spi >>>>> + * based on @interface field >>>>> +*/ >>>>> +struct pmic_platdata { >>>>> + int bus; >>>>> + int interface; >>>>> + int byte_order; >>>>> + int regs_num; >>>>> + union hw hw; >>>> >>>> >>>> >>>> If we have a 'register cache' uclass (later, once i2c is done) then >>>> this could just be a device. >>>> >>>>> +}; >>>>> + >>>>> +/* enum pmic_op_type - used for various pmic devices operation calls, >>>>> + * for decrease a number of functions with the same code for >>>>> read/write >>>>> + * or get/set. >>>>> + * >>>>> + * @PMIC_OP_GET - get operation >>>>> + * @PMIC_OP_SET - set operation >>>>> +*/ >>>>> +enum pmic_op_type { >>>>> + PMIC_OP_GET, >>>>> + PMIC_OP_SET, >>>>> +}; >>>>> + >>>>> +/* drivers/power/pmic-uclass.c */ >>>>> +int power_init_dm(void); >>>>> +struct udevice *pmic_get_by_name(int uclass_id, char *name); >>>>> +struct udevice *pmic_get_by_interface(int uclass_id, int bus, int >>>>> addr_cs); >>>>> +const char *pmic_if_str(int interface); >>>>> +int pmic_check_reg(struct pmic_platdata *p, unsigned reg); >>>>> +int pmic_reg_write(struct udevice *dev, unsigned reg, unsigned val); >>>>> +int pmic_reg_read(struct udevice *dev, unsigned reg, unsigned *val); >>>>> +int pmic_probe(struct udevice *dev, struct spi_slave *spi_slave); >>>>> + >>>>> +/* drivers/power/pmic_i2c.c */ >>>>> +int pmic_i2c_reg_write(struct udevice *dev, unsigned reg, unsigned >>>>> val); >>>>> +int pmic_i2c_reg_read(struct udevice *dev, unsigned reg, unsigned >>>>> *val); >>>>> +int pmic_i2c_probe(struct udevice *dev); >>>>> + >>>>> +/* drivers/power/pmic_spi.c */ >>>>> +int pmic_spi_reg_write(struct udevice *dev, unsigned reg, unsigned >>>>> val); >>>>> +int pmic_spi_reg_read(struct udevice *dev, unsigned reg, unsigned >>>>> *val); >>>>> +struct spi_slave *pmic_spi_probe(struct udevice *dev); >>>>> +#endif /* CONFIG_DM_PMIC */ >>>>> + >>>>> +#ifdef CONFIG_POWER >>>>> int pmic_init(unsigned char bus); >>>>> int power_init_board(void); >>>>> int pmic_dialog_init(unsigned char bus); >>>>> @@ -88,6 +151,7 @@ int pmic_probe(struct pmic *p); >>>>> int pmic_reg_read(struct pmic *p, u32 reg, u32 *val); >>>>> int pmic_reg_write(struct pmic *p, u32 reg, u32 val); >>>>> int pmic_set_output(struct pmic *p, u32 reg, int ldo, int on); >>>> >>>> >>>> >>>> These should have comments. >>>> >>> Ok, I will add it. >>> >>>>> +#endif >>>>> >>>>> #define pmic_i2c_addr (p->hw.i2c.addr) >>>>> #define pmic_i2c_tx_num (p->hw.i2c.tx_num) >>>>> -- >>>>> 1.9.1 >>>>> >>>> >>>> Regards, >>>> Simon >>>> >>> Thank you for the fast review :) >> >> >> Very interested to see this development. >> >> Regards, >> Simon >> > > Thank you again. > I'm going to check the i2c-working tree and maybe rebase the dm-pmic onto > it. > > Is it good idea?
Sounds good. Once I get the main DM patches landed (hopefully this week) I'll rebase the other series including I2C. But for now you should be good to use it. Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot