diff options
Diffstat (limited to 'drivers')
60 files changed, 2474 insertions, 439 deletions
diff --git a/drivers/aiodev/Kconfig b/drivers/aiodev/Kconfig index 88a3b9a343..6bd697702e 100644 --- a/drivers/aiodev/Kconfig +++ b/drivers/aiodev/Kconfig @@ -30,6 +30,12 @@ config LM75 help Support for LM75 and similar devices +config ST_GYRO + tristate "ST L3GD20 SPI gyro driver" + depends on SPI + help + Support for L3GD20 three-axis angular rate sensor. + config MC13XXX_ADC tristate "MC13XXX ADC driver" depends on MFD_MC13XXX diff --git a/drivers/aiodev/Makefile b/drivers/aiodev/Makefile index 4c92a403a2..06a63b0d2d 100644 --- a/drivers/aiodev/Makefile +++ b/drivers/aiodev/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_AIODEV) += core.o obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o obj-$(CONFIG_LM75) += lm75.o +obj-$(CONFIG_ST_GYRO) += st_gyro.o obj-$(CONFIG_MC13XXX_ADC) += mc13xxx_adc.o obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o obj-$(CONFIG_AM335X_ADC) += am335x_adc.o diff --git a/drivers/aiodev/st_gyro.c b/drivers/aiodev/st_gyro.c new file mode 100644 index 0000000000..3938d8239e --- /dev/null +++ b/drivers/aiodev/st_gyro.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2022 Ahmad Fatoum + +#include <common.h> +#include <driver.h> +#include <xfuncs.h> +#include <spi/spi.h> +#include <aiodev.h> + +#define ST_GYRO_WHO_AM_I 0x0F +#define ST_GYRO_CTRL_REG1 0x20 + +#define ST_GYRO_DEFAULT_OUT_TEMP_ADDR 0x26 +#define ST_GYRO_DEFAULT_OUT_X_L_ADDR 0x28 +#define ST_GYRO_DEFAULT_OUT_Y_L_ADDR 0x2a +#define ST_GYRO_DEFAULT_OUT_Z_L_ADDR 0x2c + +#define ST_GYRO_OUT_L_ADDR(idx) \ + (ST_GYRO_DEFAULT_OUT_X_L_ADDR + 2 * (idx)) + +#define ST_GYRO_OUT_H_ADDR(idx) \ + (ST_GYRO_OUT_L_ADDR(idx) + 1) + +#define ST_GYRO_READ 0x80 +#define ST_GYRO_WRITE 0x00 +#define ST_GYRO_MULTI 0x40 + +struct st_gyro { + struct aiodevice aiodev; + struct aiochannel aiochan[4]; + struct spi_device *spi; +}; +#define to_st_gyro(chan) container_of(chan->aiodev, struct st_gyro, aiodev) + +static int st_gyro_read(struct aiochannel *chan, int *val) +{ + struct st_gyro *gyro = to_st_gyro(chan); + int ret; + u8 tx; + u8 rx_h, rx_l; + + if (chan->index == 3) { + tx = ST_GYRO_DEFAULT_OUT_TEMP_ADDR | ST_GYRO_READ; + ret = spi_write_then_read(gyro->spi, &tx, 1, &rx_l, 1); + if (ret) + return ret; + + *val = (s8)rx_l; + return 0; + } + + tx = ST_GYRO_OUT_H_ADDR(chan->index) | ST_GYRO_READ; + ret = spi_write_then_read(gyro->spi, &tx, 1, &rx_h, 1); + if (ret) + return ret; + + tx = ST_GYRO_OUT_L_ADDR(chan->index) | ST_GYRO_READ; + ret = spi_write_then_read(gyro->spi, &tx, 1, &rx_l, 1); + if (ret) + return ret; + + *val = (s16)((rx_h << 8) | rx_l); + *val *= 250; + *val >>= 16; + + return 0; +} + +static int st_gyro_probe(struct device_d *dev) +{ + u8 tx[2], rx[2]; + struct st_gyro *gyro; + int ret, i; + + gyro = xzalloc(sizeof(*gyro)); + gyro->spi = to_spi_device(dev); + + tx[0] = ST_GYRO_WHO_AM_I | ST_GYRO_READ; + ret = spi_write_then_read(gyro->spi, tx, 1, rx, 1); + if (ret) + return -EIO; + if (rx[0] != 0xD4) + return dev_err_probe(dev, -ENODEV, "unexpected device WAI: %02x\n", rx[0]); + + /* initialize device */ + tx[0] = ST_GYRO_CTRL_REG1 | ST_GYRO_WRITE; + tx[1] = 0xF; /* normal mode, 3 channels */ + ret = spi_write(gyro->spi, tx, 2); + if (ret) + return -EIO; + + gyro->aiodev.num_channels = 4; + gyro->aiodev.hwdev = dev; + gyro->aiodev.read = st_gyro_read; + gyro->aiodev.name = "gyroscope"; + gyro->aiodev.channels = + xmalloc(gyro->aiodev.num_channels * + sizeof(gyro->aiodev.channels[0])); + for (i = 0; i < 3; i++) { + gyro->aiodev.channels[i] = &gyro->aiochan[i]; + gyro->aiochan[i].unit = "dps"; + gyro->aiochan[i].index = i; + } + + gyro->aiodev.channels[3] = &gyro->aiochan[3]; + gyro->aiochan[3].unit = "C"; + gyro->aiochan[3].index = 3; + + return aiodevice_register(&gyro->aiodev); +} + +static const struct of_device_id st_gyro_match[] = { + { .compatible = "st,l3gd20-gyro" }, + { /* sentinel */ } +}; + +static struct driver_d st_gyro_driver = { + .name = "st_gyro", + .probe = st_gyro_probe, + .of_compatible = st_gyro_match, +}; +device_spi_driver(st_gyro_driver); diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 303ca061ce..e7288f6a61 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -265,6 +265,8 @@ int unregister_device(struct device_d *old_dev) /* remove device from parents child list */ if (old_dev->parent) list_del(&old_dev->sibling); + if (dev_of_node(old_dev)) + old_dev->device_node->dev = NULL; return 0; } @@ -283,6 +285,7 @@ void free_device_res(struct device_d *dev) dev->name = NULL; free(dev->unique_name); dev->unique_name = NULL; + free(dev->deferred_probe_reason); } EXPORT_SYMBOL(free_device_res); @@ -333,9 +336,13 @@ static int device_probe_deferred(void) } } while (success); - list_for_each_entry(dev, &deferred, active) - dev_err(dev, "probe permanently deferred\n"); - + list_for_each_entry(dev, &deferred, active) { + if (dev->deferred_probe_reason) + dev_err(dev, "probe permanently deferred (%s)\n", + dev->deferred_probe_reason); + else + dev_err(dev, "probe permanently deferred\n"); + } return 0; } late_initcall(device_probe_deferred); @@ -573,6 +580,24 @@ const void *device_get_match_data(struct device_d *dev) return NULL; } +static void device_set_deferred_probe_reason(struct device_d *dev, const struct va_format *vaf) +{ + char *reason; + char *last_char; + + free(dev->deferred_probe_reason); + + reason = xasprintf("%pV", vaf); + + /* drop newline char at end of reason string */ + last_char = reason + strlen(reason) - 1; + + if (*last_char == '\n') + *last_char = '\0'; + + dev->deferred_probe_reason = reason; +} + /** * dev_err_probe - probe error check and log helper * @loglevel: log level configured in source file @@ -584,8 +609,12 @@ const void *device_get_match_data(struct device_d *dev) * This helper implements common pattern present in probe functions for error * checking: print debug or error message depending if the error value is * -EPROBE_DEFER and propagate error upwards. - * In case of -EPROBE_DEFER it sets also defer probe reason, which can be - * checked later by reading devices_deferred debugfs attribute. + * + * In case of -EPROBE_DEFER it sets the device's deferred_probe_reason attribute, + * but does not report an error. The error is recorded and displayed later, if + * (and only if) the probe is permanently deferred. For all other error codes, + * it just outputs the error along with the formatted message. + * * It replaces code sequence:: * * if (err != -EPROBE_DEFER) @@ -601,8 +630,8 @@ const void *device_get_match_data(struct device_d *dev) * Returns @err. * */ -int dev_err_probe(const struct device_d *dev, int err, const char *fmt, ...); -int dev_err_probe(const struct device_d *dev, int err, const char *fmt, ...) +int dev_err_probe(struct device_d *dev, int err, const char *fmt, ...); +int dev_err_probe(struct device_d *dev, int err, const char *fmt, ...) { struct va_format vaf; va_list args; @@ -611,6 +640,9 @@ int dev_err_probe(const struct device_d *dev, int err, const char *fmt, ...) vaf.fmt = fmt; vaf.va = &args; + if (err == -EPROBE_DEFER) + device_set_deferred_probe_reason(dev, &vaf); + dev_printf(err == -EPROBE_DEFER ? MSG_DEBUG : MSG_ERR, dev, "error %pe: %pV", ERR_PTR(err), &vaf); diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 2fb73917b4..c0ea2746b3 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -17,7 +17,7 @@ static int platform_probe(struct device_d *dev) ret = genpd_dev_pm_attach(dev); if (ret < 0) - return ret; + return dev_err_probe(dev, ret, "power domain attach failed\n"); return dev->driver->probe(dev); } diff --git a/drivers/base/power.c b/drivers/base/power.c index 96cac1a091..4a206051b1 100644 --- a/drivers/base/power.c +++ b/drivers/base/power.c @@ -139,14 +139,32 @@ static struct generic_pm_domain *genpd_get_from_provider( struct of_phandle_args *genpdspec) { struct generic_pm_domain *genpd = ERR_PTR(-ENOENT); + struct device_node *node = genpdspec->np; struct of_genpd_provider *provider; + int ret; if (!genpdspec) return ERR_PTR(-EINVAL); + ret = of_device_ensure_probed(node); + if (ret) { + struct device_node *parent; + + /* + * If "barebox,allow-dummy" property is set for power domain + * provider, assume it's turned on. + */ + parent = of_get_parent(node); + if (of_get_property(node, "barebox,allow-dummy", NULL) || + of_get_property(parent, "barebox,allow-dummy", NULL)) + return NULL; + + return ERR_PTR(ret); + } + /* Check if we have such a provider in our array */ list_for_each_entry(provider, &of_genpd_providers, link) { - if (provider->node == genpdspec->np) + if (provider->node == node) genpd = provider->xlate(genpdspec, provider->data); if (!IS_ERR(genpd)) break; @@ -175,7 +193,7 @@ static int genpd_power_on(struct generic_pm_domain *genpd, unsigned int depth) { int ret; - if (genpd_status_on(genpd)) + if (!genpd || genpd_status_on(genpd)) return 0; ret = _genpd_power_on(genpd, true); @@ -211,7 +229,7 @@ static int __genpd_dev_pm_attach(struct device_d *dev, struct device_node *np, return (ret == -ENOENT) ? -EPROBE_DEFER : ret; } - dev_dbg(dev, "adding to PM domain %s\n", pd->name); + dev_dbg(dev, "adding to PM domain %s\n", pd ? pd->name : "dummy"); if (power_on) ret = genpd_power_on(pd, 0); diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c index 5e3705162c..756bc224cc 100644 --- a/drivers/base/regmap/regmap-i2c.c +++ b/drivers/base/regmap/regmap-i2c.c @@ -42,3 +42,40 @@ struct regmap *regmap_init_i2c(struct i2c_client *client, { return regmap_init(&client->dev, ®map_regmap_i2c_bus, client, config); } + +static int regmap_smbus_byte_reg_read(void *client, unsigned int reg, unsigned int *val) +{ + int ret; + + if (reg > 0xff) + return -EINVAL; + + ret = i2c_smbus_read_byte_data(client, reg); + if (ret < 0) + return ret; + + *val = ret; + + return 0; +} + +static int regmap_smbus_byte_reg_write(void *client, unsigned int reg, unsigned int val) +{ + if (val > 0xff || reg > 0xff) + return -EINVAL; + + return i2c_smbus_write_byte_data(client, reg, val); +} + +static const struct regmap_bus regmap_smbus_byte = { + .reg_write = regmap_smbus_byte_reg_write, + .reg_read = regmap_smbus_byte_reg_read, +}; + +struct regmap *regmap_init_i2c_smbus(struct i2c_client *client, + const struct regmap_config *config) +{ + if (config->val_bits != 8 || config->reg_bits != 8) + return ERR_PTR(-ENOSYS); + return regmap_init(&client->dev, ®map_smbus_byte, client, config); +} diff --git a/drivers/base/resource.c b/drivers/base/resource.c index d0d3962077..0134456ffa 100644 --- a/drivers/base/resource.c +++ b/drivers/base/resource.c @@ -20,7 +20,7 @@ struct device_d *device_alloc(const char *devname, int id) return dev; } -int device_add_data(struct device_d *dev, void *data, size_t size) +int device_add_data(struct device_d *dev, const void *data, size_t size) { free(dev->platform_data); diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 68a11438dc..625e81a4ec 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -5,3 +5,24 @@ config VIRTIO_BLK help This is the virtual block driver for virtio. It can be used with QEMU based VMMs (like KVM or Xen). + +config EFI_BLK + bool "EFI block I/O driver" + default y + depends on EFI_BOOTUP + +config EFI_BLK_SEPARATE_USBDISK + bool "rename USB devices to /dev/usbdiskX" + default y + depends on EFI_BLK + help + EFI block devices will be normally called /dev/diskX. Setting this + option will cause block devices instantiated from handles with a + EFI_USB_IO protocol to be called /dev/usbdiskX instead. Note that + some buggy UEFI implementations have been observed to not do this + consistently for all USB mass storage. If you need to absolutely + be sure your boot device is a USB mass storage device and you can't + fix your UEFI, consider disabling this options and setting a GUID + for your disk and checking against it with + + devlookup -v $bootguid /dev/disk$bootsource_instance guid diff --git a/drivers/block/Makefile b/drivers/block/Makefile index c50bdc1d02..a4e14a559c 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_EFI_BOOTUP) += efi-block-io.o +obj-$(CONFIG_EFI_BLK) += efi-block-io.o obj-$(CONFIG_VIRTIO_BLK) += virtio_blk.o diff --git a/drivers/block/efi-block-io.c b/drivers/block/efi-block-io.c index 086afb378a..b78117d445 100644 --- a/drivers/block/efi-block-io.c +++ b/drivers/block/efi-block-io.c @@ -140,7 +140,8 @@ static void efi_bio_print_info(struct device_d *dev) static bool is_bio_usbdev(struct efi_device *efidev) { - return efi_device_has_guid(efidev, EFI_USB_IO_PROTOCOL_GUID); + return IS_ENABLED(CONFIG_EFI_BLK_SEPARATE_USBDISK) && + efi_device_has_guid(efidev, EFI_USB_IO_PROTOCOL_GUID); } static int efi_bio_probe(struct efi_device *efidev) @@ -187,7 +188,7 @@ static int efi_bio_probe(struct efi_device *efidev) return ret; if (efi_get_bootsource() == efidev) - bootsource_set_instance(instance); + bootsource_set_raw_instance(instance); parse_partition_table(&priv->blk); diff --git a/drivers/ddr/imx8m/ddr_init.c b/drivers/ddr/imx8m/ddr_init.c index 9a4b4e2ca8..18969ddb53 100644 --- a/drivers/ddr/imx8m/ddr_init.c +++ b/drivers/ddr/imx8m/ddr_init.c @@ -49,17 +49,18 @@ static void ddr_cfg_umctl2(struct dram_cfg_param *ddrc_cfg, int num) */ #define IMX8M_SAVED_DRAM_TIMING_BASE 0x180000 -static int imx8m_ddr_init(struct dram_timing_info *dram_timing, - enum ddrc_type type) +int imx8m_ddr_init(struct dram_timing_info *dram_timing, + unsigned type) { unsigned long src_ddrc_rcr = MX8M_SRC_DDRC_RCR_ADDR; unsigned int tmp, initial_drate, target_freq; + enum ddrc_type ddrc_type = get_ddrc_type(type); int ret; pr_debug("start DRAM init\n"); /* Step1: Follow the power up procedure */ - switch (type) { + switch (ddrc_type) { case DDRC_TYPE_MQ: reg32_write(src_ddrc_rcr + 0x04, 0x8f00000f); reg32_write(src_ddrc_rcr, 0x8f00000f); @@ -81,7 +82,7 @@ static int imx8m_ddr_init(struct dram_timing_info *dram_timing, initial_drate = dram_timing->fsp_msg[0].drate; /* default to the frequency point 0 clock */ - ddrphy_init_set_dfi_clk(initial_drate, type); + ddrphy_init_set_dfi_clk(initial_drate, ddrc_type); /* D-aasert the presetn */ reg32_write(src_ddrc_rcr, 0x8F000006); @@ -107,7 +108,7 @@ static int imx8m_ddr_init(struct dram_timing_info *dram_timing, /* if ddr type is LPDDR4, do it */ tmp = reg32_read(DDRC_MSTR(0)); - if (tmp & (0x1 << 5) && type != DDRC_TYPE_MN) + if (tmp & (0x1 << 5) && ddrc_type != DDRC_TYPE_MN) reg32_write(DDRC_DDR_SS_GPR0, 0x01); /* LPDDR4 mode */ /* determine the initial boot frequency */ @@ -154,7 +155,7 @@ static int imx8m_ddr_init(struct dram_timing_info *dram_timing, reg32_write(DDRC_SWCTL(0), 0x00000000); /* Apply rank-to-rank workaround */ - update_umctl2_rank_space_setting(dram_timing->fsp_msg_num - 1, type); + update_umctl2_rank_space_setting(dram_timing->fsp_msg_num - 1, ddrc_type); /* Step16: Set DFIMISC.dfi_init_start to 1 */ setbits_le32(DDRC_DFIMISC(0), (0x1 << 5)); @@ -210,23 +211,3 @@ static int imx8m_ddr_init(struct dram_timing_info *dram_timing, return 0; } - -int imx8mm_ddr_init(struct dram_timing_info *dram_timing) -{ - return imx8m_ddr_init(dram_timing, DDRC_TYPE_MM); -} - -int imx8mn_ddr_init(struct dram_timing_info *dram_timing) -{ - return imx8m_ddr_init(dram_timing, DDRC_TYPE_MN); -} - -int imx8mq_ddr_init(struct dram_timing_info *dram_timing) -{ - return imx8m_ddr_init(dram_timing, DDRC_TYPE_MQ); -} - -int imx8mp_ddr_init(struct dram_timing_info *dram_timing) -{ - return imx8m_ddr_init(dram_timing, DDRC_TYPE_MP); -} diff --git a/drivers/ddr/imx8m/ddrphy_train.c b/drivers/ddr/imx8m/ddrphy_train.c index 9dc20a4762..e9d35afdfb 100644 --- a/drivers/ddr/imx8m/ddrphy_train.c +++ b/drivers/ddr/imx8m/ddrphy_train.c @@ -11,6 +11,48 @@ #include <firmware.h> #include <mach/imx8m-regs.h> +static const u16 *lpddr4_imem_1d; +static size_t lpddr4_imem_1d_size; +static const u16 *lpddr4_dmem_1d; +static size_t lpddr4_dmem_1d_size; +static const u16 *lpddr4_imem_2d; +static size_t lpddr4_imem_2d_size; +static const u16 *lpddr4_dmem_2d; +static size_t lpddr4_dmem_2d_size; + +void ddr_get_firmware_lpddr4(void) +{ + get_builtin_firmware(lpddr4_pmu_train_1d_imem_bin, &lpddr4_imem_1d, + &lpddr4_imem_1d_size); + get_builtin_firmware(lpddr4_pmu_train_1d_dmem_bin, &lpddr4_dmem_1d, + &lpddr4_dmem_1d_size); + get_builtin_firmware(lpddr4_pmu_train_2d_imem_bin, &lpddr4_imem_2d, + &lpddr4_imem_2d_size); + get_builtin_firmware(lpddr4_pmu_train_2d_dmem_bin, &lpddr4_dmem_2d, + &lpddr4_dmem_2d_size); +} + +static const u16 *ddr4_imem_1d; +static size_t ddr4_imem_1d_size; +static const u16 *ddr4_dmem_1d; +static size_t ddr4_dmem_1d_size; +static const u16 *ddr4_imem_2d; +static size_t ddr4_imem_2d_size; +static const u16 *ddr4_dmem_2d; +static size_t ddr4_dmem_2d_size; + +void ddr_get_firmware_ddr(void) +{ + get_builtin_firmware(ddr4_imem_1d_bin, &ddr4_imem_1d, + &ddr4_imem_1d_size); + get_builtin_firmware(ddr4_dmem_1d_bin, &ddr4_dmem_1d, + &ddr4_dmem_1d_size); + get_builtin_firmware(ddr4_imem_2d_bin, &ddr4_imem_2d, + &ddr4_imem_2d_size); + get_builtin_firmware(ddr4_dmem_2d_bin, &ddr4_dmem_2d, + &ddr4_dmem_2d_size); +} + void ddr_load_train_code(enum dram_type dram_type, enum fw_type fw_type) { const u16 *imem, *dmem; @@ -18,19 +60,27 @@ void ddr_load_train_code(enum dram_type dram_type, enum fw_type fw_type) if (dram_is_lpddr4(dram_type)) { if (fw_type == FW_1D_IMAGE) { - get_builtin_firmware(lpddr4_pmu_train_1d_imem_bin, &imem, &isize); - get_builtin_firmware(lpddr4_pmu_train_1d_dmem_bin, &dmem, &dsize); + imem = lpddr4_imem_1d; + isize = lpddr4_imem_1d_size; + dmem = lpddr4_dmem_1d; + dsize = lpddr4_dmem_1d_size; } else { - get_builtin_firmware(lpddr4_pmu_train_2d_imem_bin, &imem, &isize); - get_builtin_firmware(lpddr4_pmu_train_2d_dmem_bin, &dmem, &dsize); + imem = lpddr4_imem_2d; + isize = lpddr4_imem_2d_size; + dmem = lpddr4_dmem_2d; + dsize = lpddr4_dmem_2d_size; } } else if (dram_is_ddr4(dram_type)) { if (fw_type == FW_1D_IMAGE) { - get_builtin_firmware(ddr4_imem_1d_bin, &imem, &isize); - get_builtin_firmware(ddr4_dmem_1d_bin, &dmem, &dsize); + imem = ddr4_imem_1d; + isize = ddr4_imem_1d_size; + dmem = ddr4_dmem_1d; + dsize = ddr4_dmem_1d_size; } else { - get_builtin_firmware(ddr4_imem_2d_bin, &imem, &isize); - get_builtin_firmware(ddr4_dmem_2d_bin, &dmem, &dsize); + imem = ddr4_imem_2d; + isize = ddr4_imem_2d_size; + dmem = ddr4_dmem_2d; + dsize = ddr4_dmem_2d_size; } } else { panic("No matching DDR PHY firmware found"); @@ -43,8 +93,10 @@ void ddr_load_train_code(enum dram_type dram_type, enum fw_type fw_type) DDRC_PHY_DMEM, dmem, dsize); } -int ddr_cfg_phy(struct dram_timing_info *dram_timing, enum ddrc_type type) +int ddr_cfg_phy(struct dram_timing_info *dram_timing, unsigned type) { + enum ddrc_type ddrc_type = get_ddrc_type(type); + enum dram_type dram_type = get_dram_type(type); struct dram_cfg_param *dram_cfg; struct dram_fsp_msg *fsp_msg; unsigned int num; @@ -66,11 +118,11 @@ int ddr_cfg_phy(struct dram_timing_info *dram_timing, enum ddrc_type type) for (i = 0; i < dram_timing->fsp_msg_num; i++) { pr_debug("DRAM PHY training for %dMTS\n", fsp_msg->drate); /* set dram PHY input clocks to desired frequency */ - ddrphy_init_set_dfi_clk(fsp_msg->drate, type); + ddrphy_init_set_dfi_clk(fsp_msg->drate, ddrc_type); /* load the dram training firmware image */ dwc_ddrphy_apb_wr(0xd0000, 0x0); - ddr_load_train_code(dram_timing->dram_type, fsp_msg->fw_type); + ddr_load_train_code(dram_type, fsp_msg->fw_type); /* load the frequency set point message block parameter */ dram_cfg = fsp_msg->fsp_cfg; diff --git a/drivers/efi/efi-device.c b/drivers/efi/efi-device.c index f91d09e8ea..af5406afa6 100644 --- a/drivers/efi/efi-device.c +++ b/drivers/efi/efi-device.c @@ -426,8 +426,7 @@ static void efi_set_bootsource(void) out: - bootsource_set(src); - bootsource_set_instance(instance); + bootsource_set_raw(src, instance); } static int efi_init_devices(void) diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index ef3d76b3f4..fc02a53a2b 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -1247,11 +1247,12 @@ static const struct of_device_id scmi_of_match[] = { { /* Sentinel */ }, }; -static struct driver_d scmi_driver = { +static struct driver_d arm_scmi_driver = { .name = "arm-scmi", .of_compatible = scmi_of_match, .probe = scmi_probe, }; +core_platform_driver(arm_scmi_driver); static int __init scmi_bus_driver_init(void) { @@ -1267,12 +1268,6 @@ static int __init scmi_bus_driver_init(void) } pure_initcall(scmi_bus_driver_init); -static int __init scmi_platform_driver_init(void) -{ - return platform_driver_register(&scmi_driver); -} -core_initcall(scmi_platform_driver_init); - MODULE_ALIAS("platform: arm-scmi"); MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>"); MODULE_DESCRIPTION("ARM SCMI protocol driver"); diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index fefd20de6f..612ef3a82e 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -219,11 +219,7 @@ static int pcf857x_probe(struct device_d *dev) */ gpio->out = ~n_latch; - ret = gpiochip_add(&gpio->chip); - if (ret) - return ret; - - return ret; + return gpiochip_add(&gpio->chip); } static const struct of_device_id pcf857x_dt_ids[] = { diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index f845a57394..97a99b84e3 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -444,44 +444,27 @@ static int of_hog_gpio(struct device_node *np, struct gpio_chip *chip, unsigned int idx) { struct device_node *chip_np = chip->dev->device_node; + struct of_phandle_args gpiospec; unsigned long flags = 0; - u32 gpio_cells, gpio_num, gpio_flags; + u32 gpio_flags; int ret, gpio; const char *name = NULL; - ret = of_property_read_u32(chip_np, "#gpio-cells", &gpio_cells); + ret = of_parse_phandle_with_args(chip_np, "gpios", "#gpio-cells", idx, + &gpiospec); if (ret) return ret; - /* - * Support for GPIOs that don't have #gpio-cells set to 2 is - * not implemented - */ - if (WARN_ON(gpio_cells != 2)) - return -ENOTSUPP; - - ret = of_property_read_u32_index(np, "gpios", idx * gpio_cells, - &gpio_num); - if (ret) - return ret; - - ret = of_property_read_u32_index(np, "gpios", idx * gpio_cells + 1, - &gpio_flags); - if (ret) - return ret; - - if (gpio_flags & OF_GPIO_ACTIVE_LOW) - flags |= GPIOF_ACTIVE_LOW; - - gpio = gpio_get_num(chip->dev, gpio_num); + gpio = gpio_of_xlate(chip->dev, &gpiospec, &gpio_flags); if (gpio == -EPROBE_DEFER) return gpio; - if (gpio < 0) { - dev_err(chip->dev, "unable to get gpio %u\n", gpio_num); + dev_err(chip->dev, "unable to get gpio: %d\n", gpio); return gpio; } + if (gpio_flags & OF_GPIO_ACTIVE_LOW) + flags |= GPIOF_ACTIVE_LOW; /* * Note that, in order to be compatible with Linux, the code @@ -636,7 +619,24 @@ void gpiochip_remove(struct gpio_chip *chip) list_del(&chip->list); } -int gpio_get_num(struct device_d *dev, int gpio) +static int of_gpio_simple_xlate(struct gpio_chip *chip, + const struct of_phandle_args *gpiospec, + u32 *flags) +{ + /* + * Support for GPIOs that don't have #gpio-cells set to 2 is + * not implemented + */ + if (WARN_ON(gpiospec->args_count != 2)) + return -ENOTSUPP; + + if (flags) + *flags = gpiospec->args[1]; + + return chip->base + gpiospec->args[0]; +} + +int gpio_of_xlate(struct device_d *dev, struct of_phandle_args *gpiospec, int *flags) { struct gpio_chip *chip; @@ -644,8 +644,12 @@ int gpio_get_num(struct device_d *dev, int gpio) return -ENODEV; list_for_each_entry(chip, &chip_list, list) { - if (chip->dev == dev) - return chip->base + gpio; + if (chip->dev != dev) + continue; + if (chip->ops->of_xlate) + return chip->ops->of_xlate(chip, gpiospec, flags); + else + return of_gpio_simple_xlate(chip, gpiospec, flags); } return -EPROBE_DEFER; diff --git a/drivers/i2c/busses/i2c-bcm283x.c b/drivers/i2c/busses/i2c-bcm283x.c index 097f73d983..fdba3b91bd 100644 --- a/drivers/i2c/busses/i2c-bcm283x.c +++ b/drivers/i2c/busses/i2c-bcm283x.c @@ -147,7 +147,7 @@ static int bcm283x_i2c_msg_xfer(struct bcm283x_i2c *bcm_i2c, if (ret) { dev_err(dev, "timeout: 10bit read initilization\n"); - return ret; + goto out; } if (reg_s & BSC_S_ERR) goto nack; @@ -178,7 +178,7 @@ static int bcm283x_i2c_msg_xfer(struct bcm283x_i2c *bcm_i2c, if (ret) { dev_err(dev, "timeout: waiting for data in FIFO\n"); - return ret; + goto out; } if (reg_s & BSC_S_ERR) goto nack; @@ -197,7 +197,7 @@ static int bcm283x_i2c_msg_xfer(struct bcm283x_i2c *bcm_i2c, if (ret) { dev_err(dev, "timeout: waiting for space in FIFO\n"); - return ret; + goto out; } if (reg_s & BSC_S_ERR) goto nack; @@ -216,16 +216,23 @@ static int bcm283x_i2c_msg_xfer(struct bcm283x_i2c *bcm_i2c, if (ret) { dev_err(dev, "timeout: waiting for transfer to end\n"); - return ret; + goto out; } if (reg_s & BSC_S_ERR) goto nack; - writel(BSC_S_DONE | BSC_S_ERR | BSC_S_CLKT, &bcm_i2c->regs->s); - writel(BSC_C_CLEAR1 | BSC_C_I2CEN, &bcm_i2c->regs->c); - return 0; + goto out; nack: dev_dbg(dev, "device with addr %x didn't ACK\n", msg->addr); - return -EREMOTEIO; + writel(BSC_S_ERR, &bcm_i2c->regs->s); + timeout = calc_byte_timeout_us(bcm_i2c->bitrate); + // Wait for end of transfer so BSC has time to send STOP condition + readl_poll_timeout(&bcm_i2c->regs->s, reg_s, ~reg_s & BSC_S_TA, timeout); + ret = -EREMOTEIO; +out: + // Return to default state for next xfer + writel(BSC_S_DONE | BSC_S_ERR | BSC_S_CLKT, &bcm_i2c->regs->s); + writel(BSC_C_CLEAR1 | BSC_C_I2CEN, &bcm_i2c->regs->c); + return ret; } static int bcm283x_i2c_xfer(struct i2c_adapter *adapter, diff --git a/drivers/i2c/busses/i2c-imx-early.c b/drivers/i2c/busses/i2c-imx-early.c index a79d7bd88c..4e0f7e517d 100644 --- a/drivers/i2c/busses/i2c-imx-early.c +++ b/drivers/i2c/busses/i2c-imx-early.c @@ -9,11 +9,12 @@ */ #include <common.h> #include <i2c/i2c.h> -#include <i2c/i2c-early.h> +#include <pbl/i2c.h> #include "i2c-imx.h" struct fsl_i2c { + struct pbl_i2c i2c; void __iomem *regs; unsigned int i2cr_ien_opcode; unsigned int i2sr_clr_opcode; @@ -170,7 +171,7 @@ static int i2c_fsl_write(struct fsl_i2c *fsl_i2c, struct i2c_msg *msg) /* write data */ for (i = 0; i < msg->len; i++) { ret = i2c_fsl_send(fsl_i2c, msg->buf[i]); - if (ret) + if (ret) return ret; } @@ -229,9 +230,9 @@ static int i2c_fsl_read(struct fsl_i2c *fsl_i2c, struct i2c_msg *msg) * If successful returns the number of messages transferred, otherwise a negative * error code is returned. */ -int i2c_fsl_xfer(void *ctx, struct i2c_msg *msgs, int num) +static int i2c_fsl_xfer(struct pbl_i2c *i2c, struct i2c_msg *msgs, int num) { - struct fsl_i2c *fsl_i2c = ctx; + struct fsl_i2c *fsl_i2c = container_of(i2c, struct fsl_i2c, i2c); unsigned int i, temp; int ret; @@ -288,7 +289,7 @@ static struct fsl_i2c fsl_i2c; * This function returns a context pointer suitable to transfer I2C messages * using i2c_fsl_xfer. */ -void *ls1046_i2c_init(void __iomem *regs) +struct pbl_i2c *ls1046_i2c_init(void __iomem *regs) { fsl_i2c.regs = regs; fsl_i2c.regshift = 0; @@ -297,10 +298,12 @@ void *ls1046_i2c_init(void __iomem *regs) /* Divider for ~100kHz when coming from the ROM */ fsl_i2c.ifdr = 0x3e; - return &fsl_i2c; + fsl_i2c.i2c.xfer = i2c_fsl_xfer; + + return &fsl_i2c.i2c; } -void *imx8m_i2c_early_init(void __iomem *regs) +struct pbl_i2c *imx8m_i2c_early_init(void __iomem *regs) { fsl_i2c.regs = regs; fsl_i2c.regshift = 2; @@ -309,5 +312,7 @@ void *imx8m_i2c_early_init(void __iomem *regs) /* Divider for ~100kHz when coming from the ROM */ fsl_i2c.ifdr = 0x0f; - return &fsl_i2c; + fsl_i2c.i2c.xfer = i2c_fsl_xfer; + + return &fsl_i2c.i2c; } diff --git a/drivers/led/led-pca955x.c b/drivers/led/led-pca955x.c index 848feb9773..aa518fe738 100644 --- a/drivers/led/led-pca955x.c +++ b/drivers/led/led-pca955x.c @@ -387,11 +387,10 @@ static int led_pca955x_probe(struct device_d *dev) err = pca955x_write_psc(client, 0, 0); if (err) return err; + err = pca955x_write_psc(client, 1, 0); - if (err) - return err; - return 0; + return err; } static struct driver_d led_pca955x_driver = { diff --git a/drivers/mci/atmel-sdhci-pbl.c b/drivers/mci/atmel-sdhci-pbl.c index 626e4008fe..2c5f107abd 100644 --- a/drivers/mci/atmel-sdhci-pbl.c +++ b/drivers/mci/atmel-sdhci-pbl.c @@ -8,7 +8,7 @@ */ #include <common.h> -#include <pbl.h> +#include <pbl/bio.h> #include <mci.h> #include <debug_ll.h> #include <mach/xload.h> diff --git a/drivers/mci/atmel_mci_pbl.c b/drivers/mci/atmel_mci_pbl.c index 767d6f3ce2..65d8b3632a 100644 --- a/drivers/mci/atmel_mci_pbl.c +++ b/drivers/mci/atmel_mci_pbl.c @@ -114,3 +114,8 @@ int at91_mci_bio_init(struct pbl_bio *bio, void __iomem *base, return 0; } + +void at91_mci_bio_set_highcapacity(bool highcapacity_card) +{ + atmci_sdcard.highcapacity_card = highcapacity_card; +} diff --git a/drivers/mci/imx-esdhc-pbl.c b/drivers/mci/imx-esdhc-pbl.c index 5a76e7a663..c81eba5b9d 100644 --- a/drivers/mci/imx-esdhc-pbl.c +++ b/drivers/mci/imx-esdhc-pbl.c @@ -44,7 +44,7 @@ static int esdhc_send_ext_csd(struct fsl_esdhc_host *host) return esdhc_send_cmd(host, &cmd, &data); } -static bool esdhc_bootpart_active(struct fsl_esdhc_host *host) +static bool __maybe_unused esdhc_bootpart_active(struct fsl_esdhc_host *host) { unsigned bootpart; diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c index b8f71e1598..8c08a4f61f 100644 --- a/drivers/mci/mci-core.c +++ b/drivers/mci/mci-core.c @@ -1941,6 +1941,16 @@ int mci_register(struct mci_host *host) host->supply = regulator_get(hw_dev, "vmmc"); if (IS_ERR(host->supply)) { + /* + * If you know your regulator to be always online on boot, but + * can't easily add a barebox driver for it, you may use + * barebox,allow-dummy-supply in your board's regulator device + * tree node to side step this warning. + * + * If you run into this warning, because your regulator driver + * hasn't probed the device yet, consider enabling deep probe + * for your board, to probe dependencies on demand. + */ dev_warn(hw_dev, "Failed to get 'vmmc' regulator (ignored).\n"); host->supply = NULL; } diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 9d4a82a9bb..6c6b65dacf 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -108,4 +108,13 @@ config MFD_ATMEL_FLEXCOM by the probe function of this MFD driver according to a device tree property. +config MFD_RK808 + tristate "Rockchip RK805/RK808/RK809/RK817/RK818 Power Management Chip" + depends on I2C && OFDEVICE + help + If you say yes here you get support for the RK805, RK808, RK809, + RK817 and RK818 Power Management chips. + This driver provides common support for accessing the device + through I2C interface. + endmenu diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 50f54cfcf2..7b5d0398d1 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -1,4 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only +obj-y += core.o + obj-$(CONFIG_MFD_ACT8846) += act8846.o obj-$(CONFIG_MFD_DA9053) += da9053.o obj-$(CONFIG_MFD_DA9063) += da9063.o @@ -19,3 +21,4 @@ obj-$(CONFIG_FINTEK_SUPERIO) += fintek-superio.o obj-$(CONFIG_SMSC_SUPERIO) += smsc-superio.o obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o obj-$(CONFIG_MFD_ATMEL_FLEXCOM) += atmel-flexcom.o +obj-$(CONFIG_MFD_RK808) += rk808.o diff --git a/drivers/mfd/core.c b/drivers/mfd/core.c new file mode 100644 index 0000000000..495427ae9c --- /dev/null +++ b/drivers/mfd/core.c @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <linux/mfd/core.h> +#include <driver.h> + +int mfd_add_devices(struct device_d *parent, const struct mfd_cell *cells, int n_devs) +{ + struct device_d *dev; + int ret, i; + + for (i = 0; i < n_devs; i++) { + dev = device_alloc(cells[i].name, DEVICE_ID_DYNAMIC); + dev->parent = parent; + + ret = device_add_data(dev, &cells[i], sizeof(cells[i])); + if (ret) + return ret; + + ret = platform_device_register(dev); + if (ret) + return ret; + } + + return 0; +} diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c new file mode 100644 index 0000000000..1b5b9d3a17 --- /dev/null +++ b/drivers/mfd/rk808.c @@ -0,0 +1,395 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * MFD core driver for Rockchip RK808/RK818 + * + * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd + * + * Author: Chris Zhong <zyw@rock-chips.com> + * Author: Zhang Qing <zhangqing@rock-chips.com> + * + * Copyright (C) 2016 PHYTEC Messtechnik GmbH + * + * Author: Wadim Egorov <w.egorov@phytec.de> + */ + +#define pr_fmt(fmt) "rk808: " fmt + +#include <common.h> +#include <i2c/i2c.h> +#include <linux/mfd/rk808.h> +#include <linux/mfd/core.h> +#include <driver.h> +#include <poweroff.h> +#include <of.h> +#include <regmap.h> + +struct rk808_reg_data { + int addr; + int mask; + int value; +}; + +static const struct regmap_config rk818_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = RK818_USB_CTRL_REG, +}; + +static const struct regmap_config rk805_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = RK805_OFF_SOURCE_REG, +}; + +static const struct regmap_config rk808_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = RK808_IO_POL_REG, +}; + +static const struct regmap_config rk817_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = RK817_GPIO_INT_CFG, +}; + +static const struct mfd_cell rk805s[] = { + { .name = "rk808-clkout", }, + { .name = "rk808-regulator", }, + { .name = "rk805-pinctrl", }, + { .name = "rk808-rtc", }, + { .name = "rk805-pwrkey", }, +}; + +static const struct mfd_cell rk808s[] = { + { .name = "rk808-clkout", }, + { .name = "rk808-regulator", }, + { .name = "rk808-rtc", }, +}; + +static const struct mfd_cell rk817s[] = { + { .name = "rk808-clkout", }, + { .name = "rk808-regulator", }, + { .name = "rk805-pwrkey", }, + { .name = "rk808-rtc", }, + { .name = "rk817-codec", }, +}; + +static const struct mfd_cell rk818s[] = { + { .name = "rk808-clkout", }, + { .name = "rk808-regulator", }, + { .name = "rk808-rtc", }, +}; + +static const struct rk808_reg_data rk805_pre_init_reg[] = { + {RK805_BUCK1_CONFIG_REG, RK805_BUCK1_2_ILMAX_MASK, + RK805_BUCK1_2_ILMAX_4000MA}, + {RK805_BUCK2_CONFIG_REG, RK805_BUCK1_2_ILMAX_MASK, + RK805_BUCK1_2_ILMAX_4000MA}, + {RK805_BUCK3_CONFIG_REG, RK805_BUCK3_4_ILMAX_MASK, + RK805_BUCK3_ILMAX_3000MA}, + {RK805_BUCK4_CONFIG_REG, RK805_BUCK3_4_ILMAX_MASK, + RK805_BUCK4_ILMAX_3500MA}, + {RK805_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_400MA}, + {RK805_THERMAL_REG, TEMP_HOTDIE_MSK, TEMP115C}, +}; + +static const struct rk808_reg_data rk808_pre_init_reg[] = { + { RK808_BUCK3_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_150MA }, + { RK808_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_200MA }, + { RK808_BOOST_CONFIG_REG, BOOST_ILMIN_MASK, BOOST_ILMIN_100MA }, + { RK808_BUCK1_CONFIG_REG, BUCK1_RATE_MASK, BUCK_ILMIN_200MA }, + { RK808_BUCK2_CONFIG_REG, BUCK2_RATE_MASK, BUCK_ILMIN_200MA }, + { RK808_DCDC_UV_ACT_REG, BUCK_UV_ACT_MASK, BUCK_UV_ACT_DISABLE}, + { RK808_VB_MON_REG, MASK_ALL, VB_LO_ACT | + VB_LO_SEL_3500MV }, +}; + +static const struct rk808_reg_data rk817_pre_init_reg[] = { + {RK817_RTC_CTRL_REG, RTC_STOP, RTC_STOP}, + /* Codec specific registers */ + { RK817_CODEC_DTOP_VUCTL, MASK_ALL, 0x03 }, + { RK817_CODEC_DTOP_VUCTIME, MASK_ALL, 0x00 }, + { RK817_CODEC_DTOP_LPT_SRST, MASK_ALL, 0x00 }, + { RK817_CODEC_DTOP_DIGEN_CLKE, MASK_ALL, 0x00 }, + /* from vendor driver, CODEC_AREF_RTCFG0 not defined in data sheet */ + { RK817_CODEC_AREF_RTCFG0, MASK_ALL, 0x00 }, + { RK817_CODEC_AREF_RTCFG1, MASK_ALL, 0x06 }, + { RK817_CODEC_AADC_CFG0, MASK_ALL, 0xc8 }, + /* from vendor driver, CODEC_AADC_CFG1 not defined in data sheet */ + { RK817_CODEC_AADC_CFG1, MASK_ALL, 0x00 }, + { RK817_CODEC_DADC_VOLL, MASK_ALL, 0x00 }, + { RK817_CODEC_DADC_VOLR, MASK_ALL, 0x00 }, + { RK817_CODEC_DADC_SR_ACL0, MASK_ALL, 0x00 }, + { RK817_CODEC_DADC_ALC1, MASK_ALL, 0x00 }, + { RK817_CODEC_DADC_ALC2, MASK_ALL, 0x00 }, + { RK817_CODEC_DADC_NG, MASK_ALL, 0x00 }, + { RK817_CODEC_DADC_HPF, MASK_ALL, 0x00 }, + { RK817_CODEC_DADC_RVOLL, MASK_ALL, 0xff }, + { RK817_CODEC_DADC_RVOLR, MASK_ALL, 0xff }, + { RK817_CODEC_AMIC_CFG0, MASK_ALL, 0x70 }, + { RK817_CODEC_AMIC_CFG1, MASK_ALL, 0x00 }, + { RK817_CODEC_DMIC_PGA_GAIN, MASK_ALL, 0x66 }, + { RK817_CODEC_DMIC_LMT1, MASK_ALL, 0x00 }, + { RK817_CODEC_DMIC_LMT2, MASK_ALL, 0x00 }, + { RK817_CODEC_DMIC_NG1, MASK_ALL, 0x00 }, + { RK817_CODEC_DMIC_NG2, MASK_ALL, 0x00 }, + /* from vendor driver, CODEC_ADAC_CFG0 not defined in data sheet */ + { RK817_CODEC_ADAC_CFG0, MASK_ALL, 0x00 }, + { RK817_CODEC_ADAC_CFG1, MASK_ALL, 0x07 }, + { RK817_CODEC_DDAC_POPD_DACST, MASK_ALL, 0x82 }, + { RK817_CODEC_DDAC_VOLL, MASK_ALL, 0x00 }, + { RK817_CODEC_DDAC_VOLR, MASK_ALL, 0x00 }, + { RK817_CODEC_DDAC_SR_LMT0, MASK_ALL, 0x00 }, + { RK817_CODEC_DDAC_LMT1, MASK_ALL, 0x00 }, + { RK817_CODEC_DDAC_LMT2, MASK_ALL, 0x00 }, + { RK817_CODEC_DDAC_MUTE_MIXCTL, MASK_ALL, 0xa0 }, + { RK817_CODEC_DDAC_RVOLL, MASK_ALL, 0xff }, + { RK817_CODEC_DADC_RVOLR, MASK_ALL, 0xff }, + { RK817_CODEC_AMIC_CFG0, MASK_ALL, 0x70 }, + { RK817_CODEC_AMIC_CFG1, MASK_ALL, 0x00 }, + { RK817_CODEC_DMIC_PGA_GAIN, MASK_ALL, 0x66 }, + { RK817_CODEC_DMIC_LMT1, MASK_ALL, 0x00 }, + { RK817_CODEC_DMIC_LMT2, MASK_ALL, 0x00 }, + { RK817_CODEC_DMIC_NG1, MASK_ALL, 0x00 }, + { RK817_CODEC_DMIC_NG2, MASK_ALL, 0x00 }, + /* from vendor driver, CODEC_ADAC_CFG0 not defined in data sheet */ + { RK817_CODEC_ADAC_CFG0, MASK_ALL, 0x00 }, + { RK817_CODEC_ADAC_CFG1, MASK_ALL, 0x07 }, + { RK817_CODEC_DDAC_POPD_DACST, MASK_ALL, 0x82 }, + { RK817_CODEC_DDAC_VOLL, MASK_ALL, 0x00 }, + { RK817_CODEC_DDAC_VOLR, MASK_ALL, 0x00 }, + { RK817_CODEC_DDAC_SR_LMT0, MASK_ALL, 0x00 }, + { RK817_CODEC_DDAC_LMT1, MASK_ALL, 0x00 }, + { RK817_CODEC_DDAC_LMT2, MASK_ALL, 0x00 }, + { RK817_CODEC_DDAC_MUTE_MIXCTL, MASK_ALL, 0xa0 }, + { RK817_CODEC_DDAC_RVOLL, MASK_ALL, 0xff }, + { RK817_CODEC_DDAC_RVOLR, MASK_ALL, 0xff }, + { RK817_CODEC_AHP_ANTI0, MASK_ALL, 0x00 }, + { RK817_CODEC_AHP_ANTI1, MASK_ALL, 0x00 }, + { RK817_CODEC_AHP_CFG0, MASK_ALL, 0xe0 }, + { RK817_CODEC_AHP_CFG1, MASK_ALL, 0x1f }, + { RK817_CODEC_AHP_CP, MASK_ALL, 0x09 }, + { RK817_CODEC_ACLASSD_CFG1, MASK_ALL, 0x69 }, + { RK817_CODEC_ACLASSD_CFG2, MASK_ALL, 0x44 }, + { RK817_CODEC_APLL_CFG0, MASK_ALL, 0x04 }, + { RK817_CODEC_APLL_CFG1, MASK_ALL, 0x00 }, + { RK817_CODEC_APLL_CFG2, MASK_ALL, 0x30 }, + { RK817_CODEC_APLL_CFG3, MASK_ALL, 0x19 }, + { RK817_CODEC_APLL_CFG4, MASK_ALL, 0x65 }, + { RK817_CODEC_APLL_CFG5, MASK_ALL, 0x01 }, + { RK817_CODEC_DI2S_CKM, MASK_ALL, 0x01 }, + { RK817_CODEC_DI2S_RSD, MASK_ALL, 0x00 }, + { RK817_CODEC_DI2S_RXCR1, MASK_ALL, 0x00 }, + { RK817_CODEC_DI2S_RXCR2, MASK_ALL, 0x17 }, + { RK817_CODEC_DI2S_RXCMD_TSD, MASK_ALL, 0x00 }, + { RK817_CODEC_DI2S_TXCR1, MASK_ALL, 0x00 }, + { RK817_CODEC_DI2S_TXCR2, MASK_ALL, 0x17 }, + { RK817_CODEC_DI2S_TXCR3_TXCMD, MASK_ALL, 0x00 }, + {RK817_GPIO_INT_CFG, RK817_INT_POL_MSK, RK817_INT_POL_L}, + {RK817_SYS_CFG(1), RK817_HOTDIE_TEMP_MSK | RK817_TSD_TEMP_MSK, + RK817_HOTDIE_105 | RK817_TSD_140}, +}; + +static const struct rk808_reg_data rk818_pre_init_reg[] = { + /* improve efficiency */ + { RK818_BUCK2_CONFIG_REG, BUCK2_RATE_MASK, BUCK_ILMIN_250MA }, + { RK818_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_250MA }, + { RK818_BOOST_CONFIG_REG, BOOST_ILMIN_MASK, BOOST_ILMIN_100MA }, + { RK818_USB_CTRL_REG, RK818_USB_ILIM_SEL_MASK, + RK818_USB_ILMIN_2000MA }, + /* close charger when usb lower then 3.4V */ + { RK818_USB_CTRL_REG, RK818_USB_CHG_SD_VSEL_MASK, + (0x7 << 4) }, + /* no action when vref */ + { RK818_H5V_EN_REG, BIT(1), RK818_REF_RDY_CTRL }, + /* enable HDMI 5V */ + { RK818_H5V_EN_REG, BIT(0), RK818_H5V_EN }, + { RK808_VB_MON_REG, MASK_ALL, VB_LO_ACT | + VB_LO_SEL_3500MV }, +}; + +static void rk808_poweroff(struct poweroff_handler *handler) +{ + struct rk808 *rk808 = container_of(handler, struct rk808, poweroff); + int ret; + unsigned int reg, bit; + + switch (rk808->variant) { + case RK805_ID: + reg = RK805_DEV_CTRL_REG; + bit = DEV_OFF; + break; + case RK808_ID: + reg = RK808_DEVCTRL_REG, + bit = DEV_OFF_RST; + break; + case RK817_ID: + reg = RK817_SYS_CFG(3); + bit = DEV_OFF; + break; + case RK818_ID: + reg = RK818_DEVCTRL_REG; + bit = DEV_OFF; + break; + default: + return; + } + + shutdown_barebox(); + + ret = regmap_update_bits(rk808->regmap, reg, bit, bit); + if (ret) + pr_err("Failed to shutdown device!\n"); + + mdelay(1000); + hang(); +} + +static int rk808_probe(struct device_d *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct device_node *np = dev->device_node; + struct rk808 *rk808; + const struct rk808_reg_data *pre_init_reg; + const struct mfd_cell *cells; + int nr_pre_init_regs; + int nr_cells; + int msb, lsb; + unsigned char pmic_id_msb, pmic_id_lsb; + int ret; + int i; + + rk808 = kzalloc(sizeof(*rk808), GFP_KERNEL); + if (!rk808) + return -ENOMEM; + + dev->priv = rk808; + + if (of_device_is_compatible(np, "rockchip,rk817") || + of_device_is_compatible(np, "rockchip,rk809")) { + pmic_id_msb = RK817_ID_MSB; + pmic_id_lsb = RK817_ID_LSB; + } else { + pmic_id_msb = RK808_ID_MSB; + pmic_id_lsb = RK808_ID_LSB; + } + + /* Read chip variant */ + msb = i2c_smbus_read_byte_data(client, pmic_id_msb); + if (msb < 0) { + dev_err(dev, "failed to read the chip id at 0x%x\n", + RK808_ID_MSB); + return msb; + } + + lsb = i2c_smbus_read_byte_data(client, pmic_id_lsb); + if (lsb < 0) { + dev_err(dev, "failed to read the chip id at 0x%x\n", + RK808_ID_LSB); + return lsb; + } + + rk808->variant = ((msb << 8) | lsb) & RK8XX_ID_MSK; + dev_info(dev, "chip id: 0x%x\n", (unsigned int)rk808->variant); + + switch (rk808->variant) { + case RK805_ID: + rk808->regmap_cfg = &rk805_regmap_config; + pre_init_reg = rk805_pre_init_reg; + nr_pre_init_regs = ARRAY_SIZE(rk805_pre_init_reg); + cells = rk805s; + nr_cells = ARRAY_SIZE(rk805s); + break; + case RK808_ID: + rk808->regmap_cfg = &rk808_regmap_config; + pre_init_reg = rk808_pre_init_reg; + nr_pre_init_regs = ARRAY_SIZE(rk808_pre_init_reg); + cells = rk808s; + nr_cells = ARRAY_SIZE(rk808s); + break; + case RK818_ID: + rk808->regmap_cfg = &rk818_regmap_config; + pre_init_reg = rk818_pre_init_reg; + nr_pre_init_regs = ARRAY_SIZE(rk818_pre_init_reg); + cells = rk818s; + nr_cells = ARRAY_SIZE(rk818s); + break; + case RK809_ID: + case RK817_ID: + rk808->regmap_cfg = &rk817_regmap_config; + pre_init_reg = rk817_pre_init_reg; + nr_pre_init_regs = ARRAY_SIZE(rk817_pre_init_reg); + cells = rk817s; + nr_cells = ARRAY_SIZE(rk817s); + break; + default: + dev_err(dev, "Unsupported RK8XX ID %lu\n", + rk808->variant); + return -EINVAL; + } + + rk808->i2c = client; + i2c_set_clientdata(client, rk808); + + rk808->regmap = regmap_init_i2c_smbus(client, rk808->regmap_cfg); + if (IS_ERR(rk808->regmap)) { + dev_err(dev, "regmap initialization failed\n"); + return PTR_ERR(rk808->regmap); + } + + ret = regmap_register_cdev(rk808->regmap, NULL); + if (ret) + return ret; + + for (i = 0; i < nr_pre_init_regs; i++) { + ret = regmap_update_bits(rk808->regmap, + pre_init_reg[i].addr, + pre_init_reg[i].mask, + pre_init_reg[i].value); + if (ret) { + dev_err(dev, + "0x%x write err\n", + pre_init_reg[i].addr); + return ret; + } + } + + ret = mfd_add_devices(dev, cells, nr_cells); + if (ret) { + dev_err(dev, "failed to add MFD devices %d\n", ret); + return ret; + } + + rk808->poweroff.name = "stpmic1-poweroff"; + rk808->poweroff.poweroff = rk808_poweroff; + rk808->poweroff.priority = 200; + + if (of_property_read_bool(np, "rockchip,system-power-controller")) + rk808->poweroff.priority += 100; + + poweroff_handler_register(&rk808->poweroff); + return 0; +} + +static const struct of_device_id rk808_of_match[] = { + { .compatible = "rockchip,rk805" }, + { .compatible = "rockchip,rk808" }, + { .compatible = "rockchip,rk809" }, + { .compatible = "rockchip,rk817" }, + { .compatible = "rockchip,rk818" }, + { }, +}; + +static struct driver_d rk808_i2c_driver = { + .name = "rk808", + .of_compatible = rk808_of_match, + .probe = rk808_probe, +}; +coredevice_i2c_driver(rk808_i2c_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>"); +MODULE_AUTHOR("Zhang Qing <zhangqing@rock-chips.com>"); +MODULE_AUTHOR("Wadim Egorov <w.egorov@phytec.de>"); +MODULE_DESCRIPTION("RK808/RK818 PMIC driver"); diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 803444cc44..341d02a1da 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -55,71 +55,75 @@ config DRIVER_NET_DAVINCI_EMAC select PHYLIB config DRIVER_NET_DESIGNWARE - bool "Designware Universal MAC1000 ethernet platform support" + bool "Designware DWMAC1000 Ethernet driver support" if COMPILE_TEST depends on HAS_DMA select PHYLIB help - This option enables support for the Synopsys - Designware Core Univesal MAC 10M/100M/1G ethernet IP. - -if DRIVER_NET_DESIGNWARE + This option is selected by platform glue drivers that contain + a DWMAC1000-compatible Ethernet IP. config DRIVER_NET_DESIGNWARE_GENERIC - bool "Designware Universal MAC ethernet generic driver" + bool "Generic Synopsis Designware Ethernet driver" + select DRIVER_NET_DESIGNWARE + depends on HAS_DMA help - This option enables support for the Synopsys - Designware Core Univesal MAC 10M/100M/1G ethernet IP on SoCFPGA. + This option enables support for the generic Synopsys + Designware Core Universal MAC 10M/100M/1G binding. Supported + are 3.70a and 3.72. Most integrations additionally require + access to platform-specific registers, e.g. for clocking. + If you are on such a platform, use the platform specific + driver instead. config DRIVER_NET_DESIGNWARE_SOCFPGA - bool "Designware Universal MAC ethernet driver for SoCFPGA platforms" - depends on ARCH_SOCFPGA || COMPILE_TEST + bool "SOCFPGA Designware Ethernet driver" + depends on HAS_DMA && (ARCH_SOCFPGA || COMPILE_TEST) + select DRIVER_NET_DESIGNWARE select MFD_SYSCON select RESET_CONTROLLER help This option enables support for the Synopsys - Designware Core Univesal MAC 10M/100M/1G ethernet IP on SoCFPGA. + Designware Core Universal MAC 10M/100M/1G Ethernet IP on SoCFPGA. config DRIVER_NET_DESIGNWARE_STARFIVE - bool "Designware Universal MAC ethernet driver for StarFive platforms" - depends on SOC_STARFIVE || COMPILE_TEST + bool "StarFive Designware Ethernet driver" + depends on HAS_DMA && (SOC_STARFIVE || COMPILE_TEST) + select DRIVER_NET_DESIGNWARE select MFD_SYSCON help This option enables support for the Synopsys - Designware Core Univesal MAC 10M/100M/1G ethernet IP on StarFive. - -endif + Designware Core Universal MAC 10M/100M/1G Ethernet IP on StarFive. config DRIVER_NET_DESIGNWARE_EQOS - bool "Designware Designware Ethernet QoS support" - depends on HAS_DMA - depends on COMMON_CLK - depends on OFTREE + bool "Designware EQOS (GMAC4) Ethernet driver support" if COMPILE_TEST + depends on HAS_DMA && OFTREE select PHYLIB help This option enables support for the Synopsys Designware Ethernet Quality-of-Service (GMAC4). -if DRIVER_NET_DESIGNWARE_EQOS - config DRIVER_NET_DESIGNWARE_STM32 - bool "Designware EQOS STM32 driver" + bool "STM32 Designware Ethernet driver" + depends on HAS_DMA && COMMON_CLK && OFTREE && (ARCH_STM32MP || COMPILE_TEST) + select DRIVER_NET_DESIGNWARE_EQOS select MFD_SYSCON help - This option enables support for the ethernet MAC on the STM32MP platforms. + This option enables support for the Ethernet MAC on the STM32MP platforms. config DRIVER_NET_DESIGNWARE_TEGRA186 - bool "Designware Universal MAC ethernet driver for Tegra 186 platforms" + bool "Tegra 186/194 Designware Ethernet driver" + depends on HAS_DMA && COMMON_CLK && OFTREE && (ARCH_TEGRA || COMPILE_TEST) + select DRIVER_NET_DESIGNWARE_EQOS select RESET_CONTROLLER help - This option enables support for the ethernet MAC on the Tegra186 & 194. + This option enables support for the Ethernet MAC on the Tegra186 & 194. config DRIVER_NET_DESIGNWARE_ROCKCHIP - bool "Designware Universal MAC ethernet driver for Rockchip platforms" + bool "Rockchip Designware Ethernet driver" + select DRIVER_NET_DESIGNWARE_EQOS + depends on HAS_DMA && COMMON_CLK && OFTREE && (ARCH_ROCKCHIP || COMPILE_TEST) select MFD_SYSCON help - This option enables support for the ethernet MAC on different Rockchip SoCs - -endif + This option enables support for the Ethernet MAC on different Rockchip SoCs config DRIVER_NET_DM9K bool "Davicom dm9k[E|A|B] ethernet driver" diff --git a/drivers/net/designware_eqos.c b/drivers/net/designware_eqos.c index 6b372e4274..79b9979697 100644 --- a/drivers/net/designware_eqos.c +++ b/drivers/net/designware_eqos.c @@ -623,10 +623,6 @@ static int eqos_start(struct eth_device *edev) last_rx_desc = (ulong)&eqos->rx_descs[(EQOS_DESCRIPTORS_RX - 1)]; writel(last_rx_desc, &eqos->dma_regs->ch0_rxdesc_tail_pointer); - barrier(); - - eqos->started = true; - return 0; } @@ -635,13 +631,6 @@ static void eqos_stop(struct eth_device *edev) struct eqos *eqos = edev->priv; int i; - if (!eqos->started) - return; - - eqos->started = false; - - barrier(); - /* Disable TX DMA */ clrbits_le32(&eqos->dma_regs->ch0_tx_control, EQOS_DMA_CH0_TX_CONTROL_ST); diff --git a/drivers/net/designware_eqos.h b/drivers/net/designware_eqos.h index be7bead09e..1b6b0400e1 100644 --- a/drivers/net/designware_eqos.h +++ b/drivers/net/designware_eqos.h @@ -60,13 +60,11 @@ struct eqos { const struct eqos_ops *ops; void *priv; - bool started; }; struct device_d; int eqos_probe(struct device_d *dev, const struct eqos_ops *ops, void *priv); void eqos_remove(struct device_d *dev); -int eqos_reset(struct eqos *priv); int eqos_get_ethaddr(struct eth_device *edev, unsigned char *mac); int eqos_set_ethaddr(struct eth_device *edev, const unsigned char *mac); diff --git a/drivers/net/designware_stm32.c b/drivers/net/designware_stm32.c index 0a5ced98f5..43f2d0987c 100644 --- a/drivers/net/designware_stm32.c +++ b/drivers/net/designware_stm32.c @@ -163,14 +163,7 @@ static int eqos_init_stm32(struct device_d *dev, struct eqos *eqos) dev_dbg(dev, "No phy clock provided. Continuing without.\n"); } - ret = clk_bulk_enable(priv->num_clks, priv->clks); - if (ret < 0) { - eqos_err(eqos, "clk_bulk_enable() failed: %s\n", - strerror(-ret)); - return ret; - } - - return 0; + return clk_bulk_enable(priv->num_clks, priv->clks); } static struct eqos_ops stm32_ops = { diff --git a/drivers/net/designware_tegra186.c b/drivers/net/designware_tegra186.c index 0241b9ad16..0cbbdb46a4 100644 --- a/drivers/net/designware_tegra186.c +++ b/drivers/net/designware_tegra186.c @@ -195,7 +195,7 @@ static int eqos_set_ethaddr_tegra186(struct eth_device *edev, const unsigned cha * ported to some system where the expectation above is true. */ - if (!eqos->started) { + if (!edev->active) { memcpy(eqos->macaddr, mac, 6); return 0; } diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 52ad3d4cdb..3a5ee9988e 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -1388,6 +1388,9 @@ struct e1000_eeprom_info { #define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ #define PHY_EXT_STATUS 0x0F /* Extended Status Reg */ +#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ +#define MAX_PHY_MULTI_PAGE_REG 0xF /* Registers equal on all pages */ + /* M88E1000 Specific Registers */ #define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */ #define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */ diff --git a/drivers/net/e1000/main.c b/drivers/net/e1000/main.c index f67c5d867b..363730de0a 100644 --- a/drivers/net/e1000/main.c +++ b/drivers/net/e1000/main.c @@ -54,13 +54,17 @@ static int e1000_get_speed_and_duplex(struct e1000_hw *hw, uint16_t *speed, uint16_t *duplex); static int e1000_read_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *phy_data); +static int e1000_phy_write(struct mii_bus *bus, int phy_addr, int reg_addr, + u16 phy_data); static int e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t phy_data); static int32_t e1000_phy_hw_reset(struct e1000_hw *hw); static int e1000_phy_reset(struct e1000_hw *hw); static int e1000_detect_gig_phy(struct e1000_hw *hw); static void e1000_set_media_type(struct e1000_hw *hw); - +static void e1000_configure_tx(struct e1000_hw *hw); +static void e1000_configure_rx(struct e1000_hw *hw); +static void e1000_setup_rctl(struct e1000_hw *hw); static int32_t e1000_check_phy_reset_block(struct e1000_hw *hw); @@ -243,6 +247,10 @@ int32_t e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask) int32_t timeout = 200; DEBUGFUNC(); + + if (hw->mac_type <= e1000_82547_rev_2) + return E1000_SUCCESS; + while (timeout) { if (e1000_get_hw_eeprom_semaphore(hw)) return -E1000_ERR_SWFW_SYNC; @@ -274,6 +282,9 @@ int32_t e1000_swfw_sync_release(struct e1000_hw *hw, uint16_t mask) { uint32_t swfw_sync; + if (hw->mac_type <= e1000_82547_rev_2) + return E1000_SUCCESS; + if (e1000_get_hw_eeprom_semaphore(hw)) return -E1000_ERR_SWFW_SYNC; @@ -802,6 +813,10 @@ static int e1000_open(struct eth_device *edev) e1000_write_reg(hw, E1000_CTRL_EXT, ctrl_ext); } + e1000_configure_tx(hw); + e1000_configure_rx(hw); + e1000_setup_rctl(hw); + return 0; } @@ -2627,6 +2642,15 @@ static int e1000_read_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, { int ret; + if ((hw->phy_type == e1000_phy_igp) && (reg_addr > MAX_PHY_MULTI_PAGE_REG)) { + ret = e1000_phy_write(&hw->miibus, 1, IGP01E1000_PHY_PAGE_SELECT, + (u16)reg_addr); + if (ret) + return ret; + + reg_addr &= MAX_PHY_REG_ADDRESS; + } + ret = e1000_phy_read(&hw->miibus, 1, reg_addr); if (ret < 0) return ret; @@ -2702,6 +2726,17 @@ static int e1000_phy_write(struct mii_bus *bus, int phy_addr, ******************************************************************************/ static int e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t phy_data) { + int ret; + + if ((hw->phy_type == e1000_phy_igp) && (reg_addr > MAX_PHY_MULTI_PAGE_REG)) { + ret = e1000_phy_write(&hw->miibus, 1, IGP01E1000_PHY_PAGE_SELECT, + (u16)reg_addr); + if (ret) + return ret; + + reg_addr &= MAX_PHY_REG_ADDRESS; + } + return e1000_phy_write(&hw->miibus, 1, reg_addr, phy_data); } @@ -3546,10 +3581,6 @@ static int e1000_init(struct eth_device *edev) if (hw->mac_type == e1000_igb) mdelay(15); - e1000_configure_tx(hw); - e1000_configure_rx(hw); - e1000_setup_rctl(hw); - return 0; } @@ -3575,9 +3606,6 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *id) edev->priv = hw; hw->packet = dma_alloc(PAGE_SIZE); - if (!hw->packet) - return -ENOMEM; - hw->packet_dma = dma_map_single(hw->dev, hw->packet, PAGE_SIZE, DMA_FROM_DEVICE); if (dma_mapping_error(hw->dev, hw->packet_dma)) diff --git a/drivers/net/fec_imx.c b/drivers/net/fec_imx.c index 0c2d600d12..673555a48a 100644 --- a/drivers/net/fec_imx.c +++ b/drivers/net/fec_imx.c @@ -320,6 +320,10 @@ static int fec_init(struct eth_device *dev) /* size of each buffer */ writel(FEC_MAX_PKT_SIZE, fec->regs + FEC_EMRBR); + /* set rx and tx buffer descriptor base address */ + writel(virt_to_phys(fec->tbd_base), fec->regs + FEC_ETDSR); + writel(virt_to_phys(fec->rbd_base), fec->regs + FEC_ERDSR); + return 0; } @@ -359,6 +363,8 @@ static int fec_open(struct eth_device *edev) if (fec->phy_init) fec->phy_init(edev->phydev); + fec_init(edev); + /* * Initialize RxBD/TxBD rings */ @@ -839,9 +845,6 @@ static int fec_probe(struct device_d *dev) base += FEC_RBD_NUM * sizeof(struct buffer_descriptor); fec->tbd_base = base; - writel(virt_to_phys(fec->tbd_base), fec->regs + FEC_ETDSR); - writel(virt_to_phys(fec->rbd_base), fec->regs + FEC_ERDSR); - ret = fec_alloc_receive_packets(fec, FEC_RBD_NUM, FEC_MAX_PKT_SIZE); if (ret < 0) goto free_xbd; @@ -861,8 +864,6 @@ static int fec_probe(struct device_d *dev) if (ret) goto free_receive_packets; - fec_init(edev); - fec->miibus.read = fec_miibus_read; fec->miibus.write = fec_miibus_write; diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c index 341f5f240e..e923e179bf 100644 --- a/drivers/net/rtl8169.c +++ b/drivers/net/rtl8169.c @@ -42,11 +42,13 @@ struct rtl8169_priv { volatile struct bufdesc *tx_desc; dma_addr_t tx_desc_phys; void *tx_buf; + dma_addr_t tx_buf_phys; unsigned int cur_tx; volatile struct bufdesc *rx_desc; dma_addr_t rx_desc_phys; void *rx_buf; + dma_addr_t rx_buf_phys; unsigned int cur_rx; struct mii_bus miibus; @@ -218,14 +220,17 @@ static void rtl8169_init_ring(struct rtl8169_priv *priv) priv->cur_rx = priv->cur_tx = 0; - priv->tx_desc = dma_alloc_coherent(NUM_TX_DESC * - sizeof(struct bufdesc), &priv->tx_desc_phys); + priv->tx_desc = dma_alloc_coherent(NUM_TX_DESC * sizeof(struct bufdesc), + &priv->tx_desc_phys); priv->tx_buf = malloc(NUM_TX_DESC * PKT_BUF_SIZE); - priv->rx_desc = dma_alloc_coherent(NUM_RX_DESC * - sizeof(struct bufdesc), &priv->rx_desc_phys); + priv->tx_buf_phys = dma_map_single(&priv->edev.dev, priv->tx_buf, + NUM_TX_DESC * PKT_BUF_SIZE, DMA_TO_DEVICE); + + priv->rx_desc = dma_alloc_coherent(NUM_RX_DESC * sizeof(struct bufdesc), + &priv->rx_desc_phys); priv->rx_buf = malloc(NUM_RX_DESC * PKT_BUF_SIZE); - dma_sync_single_for_device((unsigned long)priv->rx_buf, - NUM_RX_DESC * PKT_BUF_SIZE, DMA_FROM_DEVICE); + priv->rx_buf_phys = dma_map_single(&priv->edev.dev, priv->rx_buf, + NUM_RX_DESC * PKT_BUF_SIZE, DMA_FROM_DEVICE); for (i = 0; i < NUM_RX_DESC; i++) { if (i == (NUM_RX_DESC - 1)) @@ -236,7 +241,7 @@ static void rtl8169_init_ring(struct rtl8169_priv *priv) cpu_to_le32(BD_STAT_OWN | PKT_BUF_SIZE); priv->rx_desc[i].buf_addr = - cpu_to_le32(virt_to_phys(priv->rx_buf + i * PKT_BUF_SIZE)); + cpu_to_le32(priv->rx_buf_phys + i * PKT_BUF_SIZE); } } @@ -288,6 +293,8 @@ static int rtl8169_eth_open(struct eth_device *edev) struct rtl8169_priv *priv = edev->priv; int ret; + pci_set_master(priv->pci_dev); + rtl8169_init_ring(priv); rtl8169_hw_start(priv); @@ -353,12 +360,12 @@ static int rtl8169_eth_send(struct eth_device *edev, void *packet, if (packet_length < ETH_ZLEN) memset(priv->tx_buf + entry * PKT_BUF_SIZE, 0, ETH_ZLEN); memcpy(priv->tx_buf + entry * PKT_BUF_SIZE, packet, packet_length); - dma_sync_single_for_device((unsigned long)priv->tx_buf + entry * + dma_sync_single_for_device(priv->tx_buf_phys + entry * PKT_BUF_SIZE, PKT_BUF_SIZE, DMA_TO_DEVICE); priv->tx_desc[entry].buf_Haddr = 0; priv->tx_desc[entry].buf_addr = - cpu_to_le32(virt_to_phys(priv->tx_buf + entry * PKT_BUF_SIZE)); + cpu_to_le32(priv->tx_buf_phys + entry * PKT_BUF_SIZE); if (entry != (NUM_TX_DESC - 1)) { priv->tx_desc[entry].status = @@ -375,8 +382,8 @@ static int rtl8169_eth_send(struct eth_device *edev, void *packet, while (le32_to_cpu(priv->tx_desc[entry].status) & BD_STAT_OWN) ; - dma_sync_single_for_cpu((unsigned long)priv->tx_buf + entry * - PKT_BUF_SIZE, PKT_BUF_SIZE, DMA_TO_DEVICE); + dma_sync_single_for_cpu(priv->tx_buf_phys + entry * PKT_BUF_SIZE, + PKT_BUF_SIZE, DMA_TO_DEVICE); priv->cur_tx++; @@ -395,15 +402,13 @@ static int rtl8169_eth_rx(struct eth_device *edev) if (!(le32_to_cpu(priv->rx_desc[entry].status) & BD_STAT_RX_RES)) { pkt_size = (le32_to_cpu(priv->rx_desc[entry].status) & 0x1fff) - 4; - dma_sync_single_for_cpu((unsigned long)priv->rx_buf - + entry * PKT_BUF_SIZE, + dma_sync_single_for_cpu(priv->rx_buf_phys + entry * PKT_BUF_SIZE, pkt_size, DMA_FROM_DEVICE); net_receive(edev, priv->rx_buf + entry * PKT_BUF_SIZE, pkt_size); - dma_sync_single_for_device((unsigned long)priv->rx_buf - + entry * PKT_BUF_SIZE, + dma_sync_single_for_device(priv->rx_buf_phys + entry * PKT_BUF_SIZE, pkt_size, DMA_FROM_DEVICE); if (entry == NUM_RX_DESC - 1) @@ -413,8 +418,8 @@ static int rtl8169_eth_rx(struct eth_device *edev) priv->rx_desc[entry].status = cpu_to_le32(BD_STAT_OWN | PKT_BUF_SIZE); priv->rx_desc[entry].buf_addr = - cpu_to_le32(virt_to_phys(priv->rx_buf + - entry * PKT_BUF_SIZE)); + cpu_to_le32(priv->rx_buf_phys + + entry * PKT_BUF_SIZE); } else { dev_err(&edev->dev, "rx error\n"); } @@ -473,6 +478,18 @@ static void rtl8169_eth_halt(struct eth_device *edev) RTL_W32(priv, RxMissed, 0); pci_clear_master(priv->pci_dev); + + dma_unmap_single(&edev->dev, priv->tx_buf_phys, NUM_TX_DESC * PKT_BUF_SIZE, + DMA_TO_DEVICE); + free(priv->tx_buf); + dma_free_coherent((void *)priv->tx_desc, priv->tx_desc_phys, + NUM_TX_DESC * sizeof(struct bufdesc)); + + dma_unmap_single(&edev->dev, priv->rx_buf_phys, NUM_RX_DESC * PKT_BUF_SIZE, + DMA_FROM_DEVICE); + free(priv->rx_buf); + dma_free_coherent((void *)priv->rx_desc, priv->rx_desc_phys, + NUM_RX_DESC * sizeof(struct bufdesc)); } static int rtl8169_probe(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/of/base.c b/drivers/of/base.c index 83291c4785..b91ee92e1b 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -17,8 +17,8 @@ #include <linux/sizes.h> #include <of_graph.h> #include <string.h> +#include <linux/clk.h> #include <linux/ctype.h> -#include <linux/amba/bus.h> #include <linux/err.h> static struct device_node *root_node; @@ -2006,7 +2006,26 @@ int of_property_read_string_helper(const struct device_node *np, return i <= 0 ? -ENODATA : i; } -static int __of_print_nodes(struct device_node *node, int indent, const char *prefix) +static void __of_print_property_prefixed(const struct property *p, int indent, + unsigned maxpropsize, const char *prefix) +{ + unsigned length; + + printf("%s%*s%s", prefix, indent * 8, "", p->name); + + length = min_t(unsigned, p->length, maxpropsize); + if (length) { + printf(" = "); + of_print_property(of_property_get_value(p), length); + } + if (length != p->length) + printf(" /* %u more bytes omitted */", p->length - length); + + printf(";\n"); +} + +static int __of_print_nodes(struct device_node *node, int indent, + unsigned maxpropsize, const char *prefix) { struct device_node *n; struct property *p; @@ -2020,20 +2039,14 @@ static int __of_print_nodes(struct device_node *node, int indent, const char *pr printf("%s%*s%s%s\n", prefix, indent * 8, "", node->name, node->name ? " {" : "{"); - list_for_each_entry(p, &node->properties, list) { - printf("%s%*s%s", prefix, (indent + 1) * 8, "", p->name); - if (p->length) { - printf(" = "); - of_print_property(of_property_get_value(p), p->length); - } - printf(";\n"); - } + list_for_each_entry(p, &node->properties, list) + __of_print_property_prefixed(p, indent + 1, maxpropsize, prefix); if (ctrlc()) return -EINTR; list_for_each_entry(n, &node->children, parent_list) { - ret = __of_print_nodes(n, indent + 1, prefix); + ret = __of_print_nodes(n, indent + 1, maxpropsize, prefix); if (ret) return ret; } @@ -2042,27 +2055,22 @@ static int __of_print_nodes(struct device_node *node, int indent, const char *pr return 0; } -void of_print_nodes(struct device_node *node, int indent) +void of_print_nodes(struct device_node *node, int indent, unsigned maxpropsize) { - __of_print_nodes(node, indent, NULL); + __of_print_nodes(node, indent, maxpropsize, NULL); } -static void __of_print_property(struct property *p, int indent) +static void __of_print_property(struct property *p, int indent, unsigned maxpropsize) { - printf("%*s%s", indent * 8, "", p->name); - if (p->length) { - printf(" = "); - of_print_property(of_property_get_value(p), p->length); - } - printf(";\n"); + __of_print_property_prefixed(p, indent, maxpropsize, ""); } -void of_print_properties(struct device_node *node) +void of_print_properties(struct device_node *node, unsigned maxpropsize) { struct property *prop; list_for_each_entry(prop, &node->properties, list) - __of_print_property(prop, 0); + __of_print_property(prop, 0, maxpropsize); } static int __of_print_parents(struct device_node *node) @@ -2130,7 +2138,7 @@ int of_diff(struct device_node *a, struct device_node *b, int indent) continue; of_print_parents(a, &printed); printf("- "); - __of_print_property(ap, indent); + __of_print_property(ap, indent, ~0); continue; } @@ -2140,9 +2148,9 @@ int of_diff(struct device_node *a, struct device_node *b, int indent) continue; of_print_parents(a, &printed); printf("- "); - __of_print_property(ap, indent); + __of_print_property(ap, indent, ~0); printf("+ "); - __of_print_property(bp, indent); + __of_print_property(bp, indent, ~0); } } @@ -2154,7 +2162,7 @@ int of_diff(struct device_node *a, struct device_node *b, int indent) continue; of_print_parents(a, &printed); printf("+ "); - __of_print_property(bp, indent); + __of_print_property(bp, indent, ~0); } } @@ -2167,7 +2175,7 @@ int of_diff(struct device_node *a, struct device_node *b, int indent) if (silent) continue; of_print_parents(a, &printed); - __of_print_nodes(ca, indent, "- "); + __of_print_nodes(ca, indent, ~0, "- "); } } @@ -2177,7 +2185,7 @@ int of_diff(struct device_node *a, struct device_node *b, int indent) if (silent) continue; of_print_parents(a, &printed); - __of_print_nodes(cb, indent, "+ "); + __of_print_nodes(cb, indent, ~0, "+ "); } } @@ -2213,8 +2221,8 @@ struct device_node *of_new_node(struct device_node *parent, const char *name) return node; } -static struct property *__of_new_property(struct device_node *node, const char *name, - void *data, int len) +struct property *__of_new_property(struct device_node *node, const char *name, + void *data, int len) { struct property *prop; @@ -2321,6 +2329,39 @@ int of_set_property(struct device_node *np, const char *name, const void *val, i return 0; } +int of_append_property(struct device_node *np, const char *name, const void *val, int len) +{ + struct property *pp; + int orig_len; + void *buf; + + if (!np) + return -ENOENT; + + pp = of_find_property(np, name, NULL); + if (!pp) { + of_new_property(np, name, val, len); + return 0; + } + + orig_len = pp->length; + buf = realloc(pp->value, orig_len + len); + if (!buf) + return -ENOMEM; + + memcpy(buf + orig_len, val, len); + + pp->value = buf; + pp->length += len; + + if (pp->value_const) { + memcpy(buf, pp->value_const, orig_len); + pp->value_const = NULL; + } + + return 0; +} + int of_property_sprintf(struct device_node *np, const char *propname, const char *fmt, ...) { diff --git a/drivers/of/of_gpio.c b/drivers/of/of_gpio.c index 42e0347529..c23923b425 100644 --- a/drivers/of/of_gpio.c +++ b/drivers/of/of_gpio.c @@ -62,6 +62,7 @@ int of_get_named_gpio_flags(struct device_node *np, const char *propname, { struct of_phandle_args out_args; struct device_d *dev; + int of_flags; int ret; ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", @@ -79,7 +80,7 @@ int of_get_named_gpio_flags(struct device_node *np, const char *propname, return -EPROBE_DEFER; } - ret = gpio_get_num(dev, out_args.args[0]); + ret = gpio_of_xlate(dev, &out_args, &of_flags); if (ret == -EPROBE_DEFER) return ret; if (ret < 0) { @@ -89,7 +90,7 @@ int of_get_named_gpio_flags(struct device_node *np, const char *propname, } if (flags) { - *flags = out_args.args[1]; + *flags = of_flags; of_gpio_flags_quirks(np, propname, flags, index); } diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index b298da0000..8a57bd1aa9 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -220,6 +220,11 @@ static struct phy_provider *of_phy_provider_lookup(struct device_node *node) { struct phy_provider *phy_provider; struct device_node *child; + int ret; + + ret = of_device_ensure_probed(node); + if (ret) + return ERR_PTR(ret); list_for_each_entry(phy_provider, &phy_provider_list, list) { if (phy_provider->dev->device_node == node) @@ -255,10 +260,6 @@ static struct phy *_of_phy_get(struct device_node *np, int index) if (ret) return ERR_PTR(-ENODEV); - ret = of_device_ensure_probed(args.np); - if (ret) - return ERR_PTR(ret); - phy_provider = of_phy_provider_lookup(args.np); if (IS_ERR(phy_provider)) { return ERR_CAST(phy_provider); @@ -316,7 +317,7 @@ struct phy *of_phy_get_by_phandle(struct device_d *dev, const char *phandle, phy_provider = of_phy_provider_lookup(np); if (IS_ERR(phy_provider)) { - return ERR_PTR(-ENODEV); + return ERR_CAST(phy_provider); } return phy_provider->of_xlate(phy_provider->dev, NULL); diff --git a/drivers/pinctrl/pinctrl-stm32.c b/drivers/pinctrl/pinctrl-stm32.c index cee10636ce..fc0cc78f43 100644 --- a/drivers/pinctrl/pinctrl-stm32.c +++ b/drivers/pinctrl/pinctrl-stm32.c @@ -24,7 +24,6 @@ struct stm32_gpio_bank { void __iomem *base; struct gpio_chip chip; - struct clk *clk; const char *name; }; @@ -154,8 +153,6 @@ static int __stm32_pinctrl_set_state(struct device_d *dev, struct device_node *p "fn %u, mode %u, alt %u\n", bank->name, offset, func, mode, alt); - clk_enable(bank->clk); - __stm32_pmx_set_mode(bank->base, offset, mode, alt); if (adjust_slew_rate) @@ -173,8 +170,6 @@ static int __stm32_pinctrl_set_state(struct device_d *dev, struct device_node *p __stm32_pmx_gpio_output(bank->base, offset, 0); else if (dir == PIN_OUTPUT_HIGH) __stm32_pmx_gpio_output(bank->base, offset, 1); - - clk_disable(bank->clk); } return 0; @@ -219,8 +214,6 @@ static int stm32_gpio_get_direction(struct gpio_chip *chip, unsigned int gpio) int ret; u32 mode, alt; - clk_enable(bank->clk); - __stm32_pmx_get_mode(bank->base, stm32_gpio_pin(gpio, NULL), &mode, &alt); if ((alt == 0) && (mode == 0)) ret = 1; @@ -229,8 +222,6 @@ static int stm32_gpio_get_direction(struct gpio_chip *chip, unsigned int gpio) else ret = -EINVAL; - clk_disable(bank->clk); - return ret; } @@ -238,37 +229,22 @@ static void stm32_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) { struct stm32_gpio_bank *bank = to_stm32_gpio_bank(chip); - clk_enable(bank->clk); - __stm32_pmx_gpio_set(bank->base, stm32_gpio_pin(gpio, NULL), value); - - clk_disable(bank->clk); } static int stm32_gpio_get(struct gpio_chip *chip, unsigned gpio) { struct stm32_gpio_bank *bank = to_stm32_gpio_bank(chip); - int ret; - - clk_enable(bank->clk); - - ret = __stm32_pmx_gpio_get(bank->base, stm32_gpio_pin(gpio, NULL)); - clk_disable(bank->clk); - - return ret; + return __stm32_pmx_gpio_get(bank->base, stm32_gpio_pin(gpio, NULL)); } static int stm32_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) { struct stm32_gpio_bank *bank = to_stm32_gpio_bank(chip); - clk_enable(bank->clk); - __stm32_pmx_gpio_input(bank->base, stm32_gpio_pin(gpio, NULL)); - clk_disable(bank->clk); - return 0; } @@ -277,12 +253,8 @@ static int stm32_gpio_direction_output(struct gpio_chip *chip, { struct stm32_gpio_bank *bank = to_stm32_gpio_bank(chip); - clk_enable(bank->clk); - __stm32_pmx_gpio_output(bank->base, stm32_gpio_pin(gpio, NULL), value); - clk_disable(bank->clk); - return 0; } @@ -302,6 +274,7 @@ static int stm32_gpiochip_add(struct stm32_gpio_bank *bank, struct resource *iores; enum { PINCTRL_PHANDLE, GPIOCTRL_OFFSET, PINCTRL_OFFSET, PINCOUNT, GPIO_RANGE_NCELLS }; const __be32 *gpio_ranges; + struct clk *clk; u32 ngpios; int ret, size; @@ -350,12 +323,15 @@ static int stm32_gpiochip_add(struct stm32_gpio_bank *bank, bank->chip.base = be32_to_cpu(gpio_ranges[PINCTRL_OFFSET]); bank->chip.ops = &stm32_gpio_ops; bank->chip.dev = dev; - bank->clk = clk_get(dev, NULL); - if (IS_ERR(bank->clk)) { - dev_err(dev, "failed to get clk (%ld)\n", PTR_ERR(bank->clk)); - return PTR_ERR(bank->clk); + + clk = clk_get(dev, NULL); + if (IS_ERR(clk)) { + dev_err(dev, "failed to get clk (%ld)\n", PTR_ERR(clk)); + return PTR_ERR(clk); } + clk_enable(clk); + return gpiochip_add(&bank->chip); } diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c index 01709e0019..1316af4213 100644 --- a/drivers/power/reset/reboot-mode.c +++ b/drivers/power/reset/reboot-mode.c @@ -12,8 +12,6 @@ #include <globalvar.h> #include <magicvar.h> -#define PREFIX "mode-" - static int __priority; static struct reboot_mode_driver *__boot_mode; @@ -111,6 +109,19 @@ static void reboot_mode_print(struct reboot_mode_driver *reboot, __pr_printk(7, "\n"); } +static const char *get_mode_name(const struct property *prop) +{ + unsigned prefix_len; + + prefix_len = str_has_prefix(prop->name, "mode-"); + if (!prefix_len) + prefix_len = str_has_prefix(prop->name, "barebox,mode-"); + if (!prefix_len) + return NULL; + + return prop->name + prefix_len; +} + /** * reboot_mode_register - register a reboot mode driver * @reboot: reboot mode driver @@ -123,7 +134,6 @@ int reboot_mode_register(struct reboot_mode_driver *reboot, { struct property *prop; struct device_node *np = reboot->dev->device_node; - size_t len = strlen(PREFIX); const char *alias; size_t nmodes = 0; int i = 0; @@ -132,7 +142,7 @@ int reboot_mode_register(struct reboot_mode_driver *reboot, for_each_property_of_node(np, prop) { u32 magic; - if (strncmp(prop->name, PREFIX, len)) + if (!get_mode_name(prop)) continue; if (of_property_read_u32(np, prop->name, &magic)) continue; @@ -154,16 +164,9 @@ int reboot_mode_register(struct reboot_mode_driver *reboot, magic = &reboot->magics[i * nelems]; mode = &reboot->modes[i]; - if (strncmp(prop->name, PREFIX, len)) - continue; - - if (of_property_read_u32_array(np, prop->name, magic, nelems)) { - dev_err(reboot->dev, "reboot mode %s without magic number\n", - *mode); + *mode = get_mode_name(prop); + if (!*mode) continue; - } - - *mode = prop->name + len; if (*mode[0] == '\0') { ret = -EINVAL; dev_err(reboot->dev, "invalid mode name(%s): too short!\n", @@ -174,6 +177,12 @@ int reboot_mode_register(struct reboot_mode_driver *reboot, if (!strcmp(*mode, "normal")) normal = i; + if (of_property_read_u32_array(np, prop->name, magic, nelems)) { + dev_err(reboot->dev, "reboot mode %s without magic number\n", + *mode); + continue; + } + reboot_mode_print(reboot, *mode, magic); i++; diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index 648f75fb72..9ec81e18b1 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -55,15 +55,7 @@ #define PWMV2_CPRD 0x0C #define PWMV2_CPRDUPD 0x10 -/* - * Max value for duty and period - * - * Although the duty and period register is 32 bit, - * however only the LSB 16 bits are significant. - */ -#define PWM_MAX_DTY 0xFFFF -#define PWM_MAX_PRD 0xFFFF -#define PRD_MAX_PRES 10 +#define PWM_MAX_PRES 10 struct atmel_pwm_registers { u8 period; @@ -72,30 +64,53 @@ struct atmel_pwm_registers { u8 duty_upd; }; -struct atmel_pwm; +struct atmel_pwm_config { + u32 period_bits; +}; -struct atmel_pwm_chip { - struct pwm_chip chip; - struct atmel_pwm *atmel; +struct atmel_pwm_data { + struct atmel_pwm_registers regs; + struct atmel_pwm_config cfg; }; -struct atmel_pwm { - struct atmel_pwm_chip atmel_pwm_chip[PWM_CHANNELS]; - const struct atmel_pwm_registers *regs; +struct atmel_pwm_chip { + struct pwm_chip chips[PWM_CHANNELS]; struct clk *clk; void __iomem *base; struct device_d *dev; + const struct atmel_pwm_data *data; + + /* + * The hardware supports a mechanism to update a channel's duty cycle at + * the end of the currently running period. When such an update is + * pending we delay disabling the PWM until the new configuration is + * active because otherwise pmw_config(duty_cycle=0); pwm_disable(); + * might not result in an inactive output. + * This bitmask tracks for which channels an update is pending in + * hardware. + */ + u32 update_pending; + + /* Protects .update_pending */ + spinlock_t lock; }; static inline struct atmel_pwm_chip *to_atmel_pwm_chip(struct pwm_chip *chip) { - return container_of(chip, struct atmel_pwm_chip, chip); + struct pwm_chip (*chips)[4] = (void *)&chip[-chip->id]; + return container_of(chips, struct atmel_pwm_chip, chips); +} + +static inline u32 atmel_pwm_readl(struct atmel_pwm_chip *chip, + unsigned long offset) +{ + return readl_relaxed(chip->base + offset); } static inline void atmel_pwm_writel(struct atmel_pwm_chip *chip, unsigned long offset, unsigned long val) { - writel(val, chip->atmel->base + offset); + writel_relaxed(val, chip->base + offset); } static inline u32 atmel_pwm_ch_readl(struct atmel_pwm_chip *chip, @@ -103,7 +118,7 @@ static inline u32 atmel_pwm_ch_readl(struct atmel_pwm_chip *chip, { unsigned long base = PWM_CH_REG_OFFSET + ch * PWM_CH_REG_SIZE; - return readl(chip->atmel->base + base + offset); + return atmel_pwm_readl(chip, base + offset); } static inline void atmel_pwm_ch_writel(struct atmel_pwm_chip *chip, @@ -112,24 +127,95 @@ static inline void atmel_pwm_ch_writel(struct atmel_pwm_chip *chip, { unsigned long base = PWM_CH_REG_OFFSET + ch * PWM_CH_REG_SIZE; - writel(val, chip->atmel->base + base + offset); + atmel_pwm_writel(chip, base + offset, val); +} + +static void atmel_pwm_update_pending(struct atmel_pwm_chip *chip) +{ + /* + * Each channel that has its bit in ISR set started a new period since + * ISR was cleared and so there is no more update pending. Note that + * reading ISR clears it, so this needs to handle all channels to not + * loose information. + */ + u32 isr = atmel_pwm_readl(chip, PWM_ISR); + + chip->update_pending &= ~isr; +} + +static void atmel_pwm_set_pending(struct atmel_pwm_chip *chip, unsigned int ch) +{ + spin_lock(&chip->lock); + + /* + * Clear pending flags in hardware because otherwise there might still + * be a stale flag in ISR. + */ + atmel_pwm_update_pending(chip); + + chip->update_pending |= (1 << ch); + + spin_unlock(&chip->lock); +} + +static int atmel_pwm_test_pending(struct atmel_pwm_chip *chip, unsigned int ch) +{ + int ret = 0; + + spin_lock(&chip->lock); + + if (chip->update_pending & (1 << ch)) { + atmel_pwm_update_pending(chip); + + if (chip->update_pending & (1 << ch)) + ret = 1; + } + + spin_unlock(&chip->lock); + + return ret; +} + +static int atmel_pwm_wait_nonpending(struct atmel_pwm_chip *chip, unsigned int ch) +{ + unsigned long timeout = get_time_ns() + 2 * HZ; + int ret; + + while ((ret = atmel_pwm_test_pending(chip, ch)) && + !is_timeout(get_time_ns(), timeout)) + udelay(100); + + return ret ? -ETIMEDOUT : 0; } -static int atmel_pwm_calculate_cprd_and_pres(struct atmel_pwm_chip *atmel_pwm, - int period, +static int atmel_pwm_calculate_cprd_and_pres(struct pwm_chip *chip, + unsigned long clkrate, + const struct pwm_state *state, unsigned long *cprd, u32 *pres) { - unsigned long long cycles = period; + struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); + unsigned long long cycles = state->period_ns; + int shift; + /* Calculate the period cycles and prescale value */ - cycles *= clk_get_rate(atmel_pwm->atmel->clk); + cycles *= clkrate; do_div(cycles, NSEC_PER_SEC); - for (*pres = 0; cycles > PWM_MAX_PRD; cycles >>= 1) - (*pres)++; + /* + * The register for the period length is cfg.period_bits bits wide. + * So for each bit the number of clock cycles is wider divide the input + * clock frequency by two using pres and shift cprd accordingly. + */ + shift = fls(cycles) - atmel_pwm->data->cfg.period_bits; - if (*pres > PRD_MAX_PRES) { - dev_err(atmel_pwm->atmel->dev, "pres exceeds the maximum value\n"); + if (shift > PWM_MAX_PRES) { + dev_err(atmel_pwm->dev, "pres exceeds the maximum value\n"); return -EINVAL; + } else if (shift > 0) { + *pres = shift; + cycles >>= *pres; + } else { + *pres = 0; } *cprd = cycles; @@ -137,137 +223,238 @@ static int atmel_pwm_calculate_cprd_and_pres(struct atmel_pwm_chip *atmel_pwm, return 0; } -static void atmel_pwm_calculate_cdty(int duty, int period, - unsigned long cprd, unsigned long *cdty) +static void atmel_pwm_calculate_cdty(const struct pwm_state *state, + unsigned long clkrate, unsigned long cprd, + u32 pres, unsigned long *cdty) { - unsigned long long cycles = duty; + unsigned long long cycles = state->duty_ns; - cycles *= cprd; - do_div(cycles, period); + cycles *= clkrate; + do_div(cycles, NSEC_PER_SEC); + cycles >>= pres; *cdty = cprd - cycles; } -static void atmel_pwm_set_cprd_cdty(struct atmel_pwm_chip *atmel_pwm, int ch, +static void atmel_pwm_update_cdty(struct pwm_chip *chip, unsigned long cdty) +{ + struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); + u32 val; + + if (atmel_pwm->data->regs.duty_upd == + atmel_pwm->data->regs.period_upd) { + val = atmel_pwm_ch_readl(atmel_pwm, chip->id, PWM_CMR); + val &= ~PWM_CMR_UPD_CDTY; + atmel_pwm_ch_writel(atmel_pwm, chip->id, PWM_CMR, val); + } + + atmel_pwm_ch_writel(atmel_pwm, chip->id, + atmel_pwm->data->regs.duty_upd, cdty); + atmel_pwm_set_pending(atmel_pwm, chip->id); +} + +static void atmel_pwm_set_cprd_cdty(struct pwm_chip *chip, unsigned long cprd, unsigned long cdty) { - const struct atmel_pwm_registers *regs = atmel_pwm->atmel->regs; + struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); - atmel_pwm_ch_writel(atmel_pwm, ch, regs->duty, cdty); - atmel_pwm_ch_writel(atmel_pwm, ch, regs->period, cprd); + atmel_pwm_ch_writel(atmel_pwm, chip->id, + atmel_pwm->data->regs.duty, cdty); + atmel_pwm_ch_writel(atmel_pwm, chip->id, + atmel_pwm->data->regs.period, cprd); } -static int atmel_pwm_config(struct pwm_chip *chip, int duty_ns, int period_ns) +static void atmel_pwm_disable(struct pwm_chip *chip, bool disable_clk) { struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); - unsigned long cprd, cdty; - u32 pres, val; - int ret; - int ch; + unsigned long timeout; - ch = atmel_pwm->chip.id; - ret = atmel_pwm_calculate_cprd_and_pres(atmel_pwm, period_ns, &cprd, &pres); - if (ret) - return ret; + atmel_pwm_wait_nonpending(atmel_pwm, chip->id); - atmel_pwm_calculate_cdty(duty_ns, period_ns, cprd, &cdty); + atmel_pwm_writel(atmel_pwm, PWM_DIS, 1 << chip->id); - /* It is necessary to preserve CPOL, inside CMR */ - val = atmel_pwm_ch_readl(atmel_pwm, ch, PWM_CMR); - val = (val & ~PWM_CMR_CPRE_MSK) | (pres & PWM_CMR_CPRE_MSK); - /* Assuming normal polarity */ - val &= ~PWM_CMR_CPOL; + /* + * Wait for the PWM channel disable operation to be effective before + * stopping the clock. + */ + timeout = get_time_ns() + 2 * HZ; - atmel_pwm_ch_writel(atmel_pwm, ch, PWM_CMR, val); - atmel_pwm_set_cprd_cdty(atmel_pwm, ch, cprd, cdty); + while ((atmel_pwm_readl(atmel_pwm, PWM_SR) & (1 << chip->id)) && + !is_timeout(get_time_ns(), timeout)) + udelay(100); - return 0; + if (disable_clk) + clk_disable(atmel_pwm->clk); } -static int atmel_pwm_enable(struct pwm_chip *chip) +static int atmel_pwm_apply(struct pwm_chip *chip, const struct pwm_state *state) { struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); + struct pwm_state cstate; + unsigned long cprd, cdty; + u32 pres, val; + int ret; - atmel_pwm_writel(atmel_pwm, PWM_ENA, 1 << atmel_pwm->chip.id); - return 0; -} + cstate = chip->state; -static void atmel_pwm_disable(struct pwm_chip *chip) -{ - struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); + if (state->p_enable) { + unsigned long clkrate = clk_get_rate(atmel_pwm->clk); + + if (cstate.p_enable && + cstate.polarity == state->polarity && + cstate.period_ns == state->period_ns) { + u32 cmr = atmel_pwm_ch_readl(atmel_pwm, chip->id, PWM_CMR); + + cprd = atmel_pwm_ch_readl(atmel_pwm, chip->id, + atmel_pwm->data->regs.period); + pres = cmr & PWM_CMR_CPRE_MSK; + + atmel_pwm_calculate_cdty(state, clkrate, cprd, pres, &cdty); + atmel_pwm_update_cdty(chip, cdty); + return 0; + } + + ret = atmel_pwm_calculate_cprd_and_pres(chip, clkrate, state, &cprd, + &pres); + if (ret) { + dev_err(atmel_pwm->dev, + "failed to calculate cprd and prescaler\n"); + return ret; + } + + atmel_pwm_calculate_cdty(state, clkrate, cprd, pres, &cdty); - atmel_pwm_writel(atmel_pwm, PWM_DIS, 1 << atmel_pwm->chip.id); + if (cstate.p_enable) { + atmel_pwm_disable(chip, false); + } else { + ret = clk_enable(atmel_pwm->clk); + if (ret) { + dev_err(atmel_pwm->dev, "failed to enable clock\n"); + return ret; + } + } + + /* It is necessary to preserve CPOL, inside CMR */ + val = atmel_pwm_ch_readl(atmel_pwm, chip->id, PWM_CMR); + val = (val & ~PWM_CMR_CPRE_MSK) | (pres & PWM_CMR_CPRE_MSK); + if (state->polarity == PWM_POLARITY_NORMAL) + val &= ~PWM_CMR_CPOL; + else + val |= PWM_CMR_CPOL; + atmel_pwm_ch_writel(atmel_pwm, chip->id, PWM_CMR, val); + atmel_pwm_set_cprd_cdty(chip, cprd, cdty); + atmel_pwm_writel(atmel_pwm, PWM_ENA, 1 << chip->id); + } else if (cstate.p_enable) { + atmel_pwm_disable(chip, true); + } + + return 0; } -static struct pwm_ops atmel_pwm_ops = { - .config = atmel_pwm_config, - .enable = atmel_pwm_enable, - .disable = atmel_pwm_disable, +static const struct pwm_ops atmel_pwm_ops = { + .apply = atmel_pwm_apply, }; -static const struct atmel_pwm_registers atmel_pwm_regs_v1 = { - .period = PWMV1_CPRD, - .period_upd = PWMV1_CUPD, - .duty = PWMV1_CDTY, - .duty_upd = PWMV1_CUPD, +static const struct atmel_pwm_data atmel_sam9rl_pwm_data = { + .regs = { + .period = PWMV1_CPRD, + .period_upd = PWMV1_CUPD, + .duty = PWMV1_CDTY, + .duty_upd = PWMV1_CUPD, + }, + .cfg = { + /* 16 bits to keep period and duty. */ + .period_bits = 16, + }, +}; + +static const struct atmel_pwm_data atmel_sama5_pwm_data = { + .regs = { + .period = PWMV2_CPRD, + .period_upd = PWMV2_CPRDUPD, + .duty = PWMV2_CDTY, + .duty_upd = PWMV2_CDTYUPD, + }, + .cfg = { + /* 16 bits to keep period and duty. */ + .period_bits = 16, + }, }; -static const struct atmel_pwm_registers atmel_pwm_regs_v2 = { - .period = PWMV2_CPRD, - .period_upd = PWMV2_CPRDUPD, - .duty = PWMV2_CDTY, - .duty_upd = PWMV2_CDTYUPD, +static const struct atmel_pwm_data mchp_sam9x60_pwm_data = { + .regs = { + .period = PWMV1_CPRD, + .period_upd = PWMV1_CUPD, + .duty = PWMV1_CDTY, + .duty_upd = PWMV1_CUPD, + }, + .cfg = { + /* 32 bits to keep period and duty. */ + .period_bits = 32, + }, }; static const struct of_device_id atmel_pwm_dt_ids[] = { { .compatible = "atmel,at91sam9rl-pwm", - .data = &atmel_pwm_regs_v1, + .data = &atmel_sam9rl_pwm_data, }, { .compatible = "atmel,sama5d3-pwm", - .data = &atmel_pwm_regs_v2, + .data = &atmel_sama5_pwm_data, }, { .compatible = "atmel,sama5d2-pwm", - .data = &atmel_pwm_regs_v2, + .data = &atmel_sama5_pwm_data, + }, { + .compatible = "microchip,sam9x60-pwm", + .data = &mchp_sam9x60_pwm_data, }, { /* sentinel */ }, }; +static int id = -1; + static int atmel_pwm_probe(struct device_d *dev) { - const struct atmel_pwm_registers *regs; - struct atmel_pwm *atmel_pwm; - struct resource *res; + const struct atmel_pwm_data *data; + struct atmel_pwm_chip *atmel_pwm; + struct resource *iores; + const char *alias; int ret; int i; - ret = dev_get_drvdata(dev, (const void **)®s); + ret = dev_get_drvdata(dev, (const void **)&data); if (ret) return ret; atmel_pwm = xzalloc(sizeof(*atmel_pwm)); - atmel_pwm->regs = regs; + atmel_pwm->data = data; atmel_pwm->dev = dev; atmel_pwm->clk = clk_get(dev, "pwm_clk"); if (IS_ERR(atmel_pwm->clk)) return PTR_ERR(atmel_pwm->clk); - res = dev_request_mem_resource(dev, 0); - if (IS_ERR(res)) - return PTR_ERR(res); + iores = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores)) + return PTR_ERR(iores); - atmel_pwm->base = IOMEM(res->start); + atmel_pwm->base = IOMEM(iores->start); + alias = of_alias_get(dev->device_node); + if (!alias) + id++; for (i = 0; i < PWM_CHANNELS; i++) { - struct atmel_pwm_chip *chip = &atmel_pwm->atmel_pwm_chip[i]; - chip->chip.ops = &atmel_pwm_ops; - chip->chip.devname = basprintf("pwm%d", i); - chip->chip.id = i; - chip->atmel = atmel_pwm; - - ret = pwmchip_add(&chip->chip, dev); - if (ret < 0) { - dev_err(dev, "failed to add pwm chip[%d] %d\n", i, ret); + struct pwm_chip *chip = &atmel_pwm->chips[i]; + + if (alias) + chip->devname = basprintf("%sch%u", alias, i + 1); + else + chip->devname = basprintf("pwm%uch%u", id, i + 1); + + chip->ops = &atmel_pwm_ops; + chip->id = i; + ret = pwmchip_add(chip, dev); + if (ret) { + dev_err(dev, "failed to add pwm chip %d\n", ret); return ret; } } diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 609765d895..c542b72796 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -206,7 +206,7 @@ static int imx_pwm_probe(struct device_d *dev) struct resource *iores; const struct imx_pwm_data *data; struct imx_chip *imx; - int ret = 0; + int ret; ret = dev_get_drvdata(dev, (const void **)&data); if (ret) @@ -236,11 +236,7 @@ static int imx_pwm_probe(struct device_d *dev) imx->config = data->config; imx->set_enable = data->set_enable; - ret = pwmchip_add(&imx->chip, dev); - if (ret < 0) - return ret; - - return 0; + return pwmchip_add(&imx->chip, dev);; } static struct driver_d imx_pwm_driver = { diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 38a47b7bc2..56abe3896e 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -55,6 +55,7 @@ config REGULATOR_ANATOP regulators. It is recommended that this option be enabled on i.MX6 platform. + config REGULATOR_ARM_SCMI tristate "SCMI based regulator driver" depends on ARM_SCMI_PROTOCOL && OFDEVICE @@ -64,4 +65,14 @@ config REGULATOR_ARM_SCMI This driver uses SCMI Message Protocol driver to interact with the firmware providing the device Voltage functionality. +config REGULATOR_RK808 + tristate "Rockchip RK805/RK808/RK809/RK817/RK818 Power regulators" + depends on MFD_RK808 + help + Select this option to enable the power regulator of ROCKCHIP + PMIC RK805,RK809&RK817,RK808 and RK818. + This driver supports the control of different power rails of device + through regulator interface. The device supports multiple DCDC/LDO + outputs which can be controlled by i2c communication. + endif diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 5eaa657ad1..95e42719d1 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o obj-$(CONFIG_REGULATOR_STM32_PWR) += stm32-pwr.o obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o obj-$(CONFIG_REGULATOR_ARM_SCMI) += scmi-regulator.o +obj-$(CONFIG_REGULATOR_RK808) += rk808-regulator.o diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index af8a0cb4fc..4876f0f44b 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -9,6 +9,7 @@ #include <of.h> #include <malloc.h> #include <linux/err.h> +#include <deep-probe.h> static LIST_HEAD(regulator_list); @@ -42,6 +43,7 @@ static int regulator_map_voltage(struct regulator_dev *rdev, int min_uV, static int regulator_enable_internal(struct regulator_internal *ri) { + struct regulator_dev *rdev = ri->rdev; int ret; if (ri->enable_count) { @@ -49,13 +51,20 @@ static int regulator_enable_internal(struct regulator_internal *ri) return 0; } - if (!ri->rdev->desc->ops->enable) + if (!rdev->desc->ops->enable) return -ENOSYS; - ret = ri->rdev->desc->ops->enable(ri->rdev); + /* turn on parent regulator */ + ret = regulator_enable(rdev->supply); if (ret) return ret; + ret = rdev->desc->ops->enable(ri->rdev); + if (ret) { + regulator_disable(rdev->supply); + return ret; + } + if (ri->enable_time_us) udelay(ri->enable_time_us); @@ -66,6 +75,7 @@ static int regulator_enable_internal(struct regulator_internal *ri) static int regulator_disable_internal(struct regulator_internal *ri) { + struct regulator_dev *rdev = ri->rdev; int ret; if (!ri->enable_count) @@ -76,16 +86,20 @@ static int regulator_disable_internal(struct regulator_internal *ri) return 0; } - if (!ri->rdev->desc->ops->disable) + /* Crisis averted, be loud about the unbalanced regulator use */ + if (WARN_ON(rdev->always_on)) + return -EPERM; + + if (!rdev->desc->ops->disable) return -ENOSYS; - ret = ri->rdev->desc->ops->disable(ri->rdev); + ret = rdev->desc->ops->disable(rdev); if (ret) return ret; ri->enable_count--; - return 0; + return regulator_disable(ri->rdev->supply); } static int regulator_set_voltage_internal(struct regulator_internal *ri, @@ -115,6 +129,41 @@ static int regulator_set_voltage_internal(struct regulator_internal *ri, return -ENOSYS; } +static int regulator_resolve_supply(struct regulator_dev *rdev) +{ + struct regulator *supply; + const char *supply_name; + + if (!rdev || rdev->supply) + return 0; + + supply_name = rdev->desc->supply_name; + if (!supply_name) + return 0; + + supply = regulator_get(rdev->dev, supply_name); + if (IS_ERR(supply)) { + if (deep_probe_is_supported()) + return PTR_ERR(supply); + + /* For historic reasons, some regulator consumers don't handle + * -EPROBE_DEFER (e.g. vmmc-supply). If we now start propagating + * parent EPROBE_DEFER, previously requested vmmc-supply with + * always-on parent that worked before will end up not being + * requested breaking MMC use. So for non-deep probe systems, + * just make best effort to resolve, but don't fail the get if + * we couldn't. If you want to get rid of this warning, consider + * migrating your platform to have deep probe support. + */ + dev_warn(rdev->dev, "Failed to get '%s' regulator (ignored).\n", + supply_name); + return 0; + } + + rdev->supply = supply; + return 0; +} + static struct regulator_internal * __regulator_register(struct regulator_dev *rd, const char *name) { struct regulator_internal *ri; @@ -131,6 +180,10 @@ static struct regulator_internal * __regulator_register(struct regulator_dev *rd ri->name = xstrdup(name); if (rd->boot_on || rd->always_on) { + ret = regulator_resolve_supply(ri->rdev); + if (ret < 0) + goto err; + ret = regulator_enable_internal(ri); if (ret && ret != -ENOSYS) goto err; @@ -333,6 +386,7 @@ struct regulator *regulator_get(struct device_d *dev, const char *supply) { struct regulator_internal *ri = NULL; struct regulator *r; + int ret; if (dev->device_node) { ri = of_regulator_get(dev, supply); @@ -349,6 +403,10 @@ struct regulator *regulator_get(struct device_d *dev, const char *supply) if (!ri) return NULL; + ret = regulator_resolve_supply(ri->rdev); + if (ret < 0) + return ERR_PTR(ret); + r = xzalloc(sizeof(*r)); r->ri = ri; r->dev = dev; @@ -569,9 +627,16 @@ EXPORT_SYMBOL_GPL(regulator_bulk_free); int regulator_get_voltage(struct regulator *regulator) { - struct regulator_dev *rdev = regulator->ri->rdev; + struct regulator_internal *ri; + struct regulator_dev *rdev; int sel, ret; + if (!regulator) + return -EINVAL; + + ri = regulator->ri; + rdev = ri->rdev; + if (rdev->desc->ops->get_voltage_sel) { sel = rdev->desc->ops->get_voltage_sel(rdev); if (sel < 0) @@ -583,6 +648,10 @@ int regulator_get_voltage(struct regulator *regulator) ret = rdev->desc->ops->list_voltage(rdev, 0); } else if (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1)) { ret = rdev->desc->fixed_uV; + } else if (ri->min_uv && ri->min_uv == ri->max_uv) { + ret = ri->min_uv; + } else if (rdev->supply) { + ret = regulator_get_voltage(rdev->supply); } else { return -EINVAL; } diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index ae16df8a0c..bdb01c0a95 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -15,7 +15,6 @@ struct regulator_fixed { int gpio; - int always_on; struct regulator_dev rdev; struct regulator_desc rdesc; }; @@ -34,9 +33,6 @@ static int regulator_fixed_disable(struct regulator_dev *rdev) { struct regulator_fixed *fix = container_of(rdev, struct regulator_fixed, rdev); - if (fix->always_on) - return 0; - if (!gpio_is_valid(fix->gpio)) return 0; @@ -76,15 +72,12 @@ static int regulator_fixed_probe(struct device_d *dev) if (!of_property_read_u32(np, "off-on-delay-us", &delay)) fix->rdesc.off_on_delay = delay; - if (of_find_property(np, "regulator-always-on", NULL) || - of_find_property(np, "regulator-boot-on", NULL)) { - fix->always_on = 1; - regulator_fixed_enable(&fix->rdev); - } + if (of_find_property(np, "vin-supply", NULL)) + fix->rdesc.supply_name = "vin"; ret = of_regulator_register(&fix->rdev, np); if (ret) - return ret; + goto err; return 0; err: diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c new file mode 100644 index 0000000000..39eadbd3eb --- /dev/null +++ b/drivers/regulator/rk808-regulator.c @@ -0,0 +1,963 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Regulator driver for Rockchip RK808 + * + * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd + * + * Author: Chris Zhong <zyw@rock-chips.com> + * Author: Zhang Qing <zhangqing@rock-chips.com> + */ + +#include <common.h> +#include <driver.h> +#include <gpio.h> +#include <init.h> +#include <i2c/i2c.h> +#include <of_device.h> +#include <regmap.h> +#include <linux/regulator/of_regulator.h> +#include <regulator.h> +#include <linux/mfd/rk808.h> + +/* Field Definitions */ +#define RK808_BUCK_VSEL_MASK 0x3f +#define RK808_BUCK4_VSEL_MASK 0xf +#define RK808_LDO_VSEL_MASK 0x1f + +#define RK809_BUCK5_VSEL_MASK 0x7 + +#define RK817_LDO_VSEL_MASK 0x7f +#define RK817_BOOST_VSEL_MASK 0x7 +#define RK817_BUCK_VSEL_MASK 0x7f + +#define RK818_BUCK_VSEL_MASK 0x3f +#define RK818_BUCK4_VSEL_MASK 0x1f +#define RK818_LDO_VSEL_MASK 0x1f +#define RK818_LDO3_ON_VSEL_MASK 0xf +#define RK818_BOOST_ON_VSEL_MASK 0xe0 + +#define ENABLE_MASK(id) (BIT(id) | BIT(4 + (id))) +#define DISABLE_VAL(id) (BIT(4 + (id))) + +#define RK817_BOOST_DESC(_supply_name, _min, _max, _step, _vreg,\ + _vmask, _ereg, _emask, _enval, _disval, _etime) \ + {{ \ + .supply_name = (_supply_name), \ + .n_voltages = (((_max) - (_min)) / (_step) + 1), \ + .min_uV = (_min) * 1000, \ + .uV_step = (_step) * 1000, \ + .vsel_reg = (_vreg), \ + .vsel_mask = (_vmask), \ + .enable_reg = (_ereg), \ + .enable_mask = (_emask), \ + .enable_val = (_enval), \ + .disable_val = (_disval), \ + .off_on_delay = (_etime), \ + .ops = &rk817_boost_ops, \ + }} + +#define RK8XX_DESC_COM(_supply_name, _min, _max, _step, _vreg, \ + _vmask, _ereg, _emask, _enval, _disval, _etime, _ops) \ + {{ \ + .supply_name = (_supply_name), \ + .n_voltages = (((_max) - (_min)) / (_step) + 1), \ + .min_uV = (_min) * 1000, \ + .uV_step = (_step) * 1000, \ + .vsel_reg = (_vreg), \ + .vsel_mask = (_vmask), \ + .enable_reg = (_ereg), \ + .enable_mask = (_emask), \ + .enable_val = (_enval), \ + .disable_val = (_disval), \ + .off_on_delay = (_etime), \ + .ops = _ops, \ + }} + +#define RK805_DESC(_supply_name, _min, _max, _step, _vreg, \ + _vmask, _ereg, _emask, _etime) \ + RK8XX_DESC_COM(_supply_name, _min, _max, _step, _vreg, \ + _vmask, _ereg, _emask, 0, 0, _etime, &rk808_reg_ops) + +#define RK8XX_DESC(_supply_name, _min, _max, _step, _vreg, \ + _vmask, _ereg, _emask, _etime) \ + RK8XX_DESC_COM(_supply_name, _min, _max, _step, _vreg, \ + _vmask, _ereg, _emask, 0, 0, _etime, &rk808_reg_ops) + +#define RK817_DESC(_supply_name, _min, _max, _step, _vreg, \ + _vmask, _ereg, _emask, _disval, _etime) \ + RK8XX_DESC_COM(_supply_name, _min, _max, _step, _vreg, \ + _vmask, _ereg, _emask, _emask, _disval, _etime, &rk817_reg_ops) + +#define RKXX_DESC_SWITCH_COM(_supply_name,_ereg, _emask, \ + _enval, _disval, _ops) \ + {{ \ + .supply_name = (_supply_name), \ + .enable_reg = (_ereg), \ + .enable_mask = (_emask), \ + .enable_val = (_enval), \ + .disable_val = (_disval), \ + .ops = _ops \ + }} + +#define RK817_DESC_SWITCH(_supply_name, _ereg, _emask, \ + _disval) \ + RKXX_DESC_SWITCH_COM(_supply_name, _ereg, _emask, \ + _emask, _disval, &rk817_switch_ops) + +#define RK8XX_DESC_SWITCH(_supply_name, _ereg, _emask) \ + RKXX_DESC_SWITCH_COM(_supply_name, _ereg, _emask, \ + 0, 0, &rk808_switch_ops) + +static const struct regulator_linear_range rk808_ldo3_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(800000, 0, 13, 100000), + REGULATOR_LINEAR_RANGE(2500000, 15, 15, 0), +}; + +#define RK809_BUCK5_SEL_CNT (8) + +static const struct regulator_linear_range rk809_buck5_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(1500000, 0, 0, 0), + REGULATOR_LINEAR_RANGE(1800000, 1, 3, 200000), + REGULATOR_LINEAR_RANGE(2800000, 4, 5, 200000), + REGULATOR_LINEAR_RANGE(3300000, 6, 7, 300000), +}; + +#define RK817_BUCK1_MIN0 500000 +#define RK817_BUCK1_MAX0 1500000 + +#define RK817_BUCK1_MIN1 1600000 +#define RK817_BUCK1_MAX1 2400000 + +#define RK817_BUCK3_MAX1 3400000 + +#define RK817_BUCK1_STP0 12500 +#define RK817_BUCK1_STP1 100000 + +#define RK817_BUCK1_SEL0 ((RK817_BUCK1_MAX0 - RK817_BUCK1_MIN0) /\ + RK817_BUCK1_STP0) +#define RK817_BUCK1_SEL1 ((RK817_BUCK1_MAX1 - RK817_BUCK1_MIN1) /\ + RK817_BUCK1_STP1) + +#define RK817_BUCK3_SEL1 ((RK817_BUCK3_MAX1 - RK817_BUCK1_MIN1) /\ + RK817_BUCK1_STP1) + +#define RK817_BUCK1_SEL_CNT (RK817_BUCK1_SEL0 + RK817_BUCK1_SEL1 + 1) +#define RK817_BUCK3_SEL_CNT (RK817_BUCK1_SEL0 + RK817_BUCK3_SEL1 + 1) + +static const struct regulator_linear_range rk817_buck1_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(RK817_BUCK1_MIN0, 0, + RK817_BUCK1_SEL0, RK817_BUCK1_STP0), + REGULATOR_LINEAR_RANGE(RK817_BUCK1_MIN1, RK817_BUCK1_SEL0 + 1, + RK817_BUCK1_SEL_CNT, RK817_BUCK1_STP1), +}; + +static const struct regulator_linear_range rk817_buck3_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(RK817_BUCK1_MIN0, 0, + RK817_BUCK1_SEL0, RK817_BUCK1_STP0), + REGULATOR_LINEAR_RANGE(RK817_BUCK1_MIN1, RK817_BUCK1_SEL0 + 1, + RK817_BUCK3_SEL_CNT, RK817_BUCK1_STP1), +}; + +struct rk_regulator_cfg { + struct regulator_desc desc; + struct regulator_dev rdev; +}; + +static int rk8xx_is_enabled_wmsk_regmap(struct regulator_dev *rdev) +{ + unsigned int val; + int ret; + + ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val); + if (ret != 0) + return ret; + + /* add write mask bit */ + val |= (rdev->desc->enable_mask & 0xf0); + val &= rdev->desc->enable_mask; + + if (rdev->desc->enable_is_inverted) { + if (rdev->desc->enable_val) + return val != rdev->desc->enable_val; + return (val == 0); + } + if (rdev->desc->enable_val) + return val == rdev->desc->enable_val; + return val != 0; +} + +static struct regulator_ops rk808_buck1_2_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +static struct regulator_ops rk808_reg_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +static struct regulator_ops rk808_reg_ops_ranges = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +static struct regulator_ops rk808_switch_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +static const struct regulator_linear_range rk805_buck_1_2_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(712500, 0, 59, 12500), + REGULATOR_LINEAR_RANGE(1800000, 60, 62, 200000), + REGULATOR_LINEAR_RANGE(2300000, 63, 63, 0), +}; + +static const struct regulator_ops rk809_buck5_ops_range = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = rk8xx_is_enabled_wmsk_regmap, +}; + +static const struct regulator_ops rk817_reg_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = rk8xx_is_enabled_wmsk_regmap, +}; + +static const struct regulator_ops rk817_boost_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = rk8xx_is_enabled_wmsk_regmap, +}; + +static const struct regulator_ops rk817_buck_ops_range = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = rk8xx_is_enabled_wmsk_regmap, +}; + +static const struct regulator_ops rk817_switch_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = rk8xx_is_enabled_wmsk_regmap, +}; + +static struct rk_regulator_cfg rk805_reg[] = { + {{ + /* .name = "DCDC_REG1", */ + .supply_name = "vcc1", + .ops = &rk808_reg_ops_ranges, + .n_voltages = 64, + .linear_ranges = rk805_buck_1_2_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk805_buck_1_2_voltage_ranges), + .vsel_reg = RK805_BUCK1_ON_VSEL_REG, + .vsel_mask = RK818_BUCK_VSEL_MASK, + .enable_reg = RK805_DCDC_EN_REG, + .enable_mask = BIT(0), + }}, {{ + /* .name = "DCDC_REG2", */ + .supply_name = "vcc2", + .ops = &rk808_reg_ops_ranges, + .n_voltages = 64, + .linear_ranges = rk805_buck_1_2_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk805_buck_1_2_voltage_ranges), + .vsel_reg = RK805_BUCK2_ON_VSEL_REG, + .vsel_mask = RK818_BUCK_VSEL_MASK, + .enable_reg = RK805_DCDC_EN_REG, + .enable_mask = BIT(1), + }}, {{ + /* .name = "DCDC_REG3", */ + .supply_name = "vcc3", + .ops = &rk808_switch_ops, + .n_voltages = 1, + .enable_reg = RK805_DCDC_EN_REG, + .enable_mask = BIT(2), + }}, + + RK805_DESC(/* "DCDC_REG4", */ "vcc4", 800, 3400, 100, + RK805_BUCK4_ON_VSEL_REG, RK818_BUCK4_VSEL_MASK, + RK805_DCDC_EN_REG, BIT(3), 0), + + RK805_DESC(/* "LDO_REG1", */ "vcc5", 800, 3400, 100, + RK805_LDO1_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK805_LDO_EN_REG, + BIT(0), 400), + RK805_DESC(/* "LDO_REG2", */ "vcc5", 800, 3400, 100, + RK805_LDO2_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK805_LDO_EN_REG, + BIT(1), 400), + RK805_DESC(/* "LDO_REG3", */ "vcc6", 800, 3400, 100, + RK805_LDO3_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK805_LDO_EN_REG, + BIT(2), 400), +}; +static_assert(ARRAY_SIZE(rk805_reg) == RK805_NUM_REGULATORS); + +static struct rk_regulator_cfg rk808_reg[] = { + {{ + /* .name = "DCDC_REG1", */ + .supply_name = "vcc1", + .ops = &rk808_buck1_2_ops, + .min_uV = 712500, + .uV_step = 12500, + .n_voltages = 64, + .vsel_reg = RK808_BUCK1_ON_VSEL_REG, + .vsel_mask = RK808_BUCK_VSEL_MASK, + .enable_reg = RK808_DCDC_EN_REG, + .enable_mask = BIT(0), + }}, {{ + /* .name = "DCDC_REG2", */ + .supply_name = "vcc2", + .ops = &rk808_buck1_2_ops, + .min_uV = 712500, + .uV_step = 12500, + .n_voltages = 64, + .vsel_reg = RK808_BUCK2_ON_VSEL_REG, + .vsel_mask = RK808_BUCK_VSEL_MASK, + .enable_reg = RK808_DCDC_EN_REG, + .enable_mask = BIT(1), + }}, {{ + /* .name = "DCDC_REG3", */ + .supply_name = "vcc3", + .ops = &rk808_switch_ops, + .n_voltages = 1, + .enable_reg = RK808_DCDC_EN_REG, + .enable_mask = BIT(2), + }}, {{ + /* .name = "DCDC_REG4", */ + .supply_name = "vcc4", + .ops = &rk808_reg_ops, + .min_uV = 1800000, + .uV_step = 100000, + .n_voltages = 16, + .vsel_reg = RK808_BUCK4_ON_VSEL_REG, + .vsel_mask = RK808_BUCK4_VSEL_MASK, + .enable_reg = RK808_DCDC_EN_REG, + .enable_mask = BIT(3), + }}, {{ + /* .name = "LDO_REG1", */ + .supply_name = "vcc6", + .ops = &rk808_reg_ops, + .min_uV = 1800000, + .uV_step = 100000, + .n_voltages = 17, + .vsel_reg = RK808_LDO1_ON_VSEL_REG, + .vsel_mask = RK808_LDO_VSEL_MASK, + .enable_reg = RK808_LDO_EN_REG, + .enable_mask = BIT(0), + .off_on_delay = 400, + }}, {{ + /* .name = "LDO_REG2", */ + .supply_name = "vcc6", + .ops = &rk808_reg_ops, + .min_uV = 1800000, + .uV_step = 100000, + .n_voltages = 17, + .vsel_reg = RK808_LDO2_ON_VSEL_REG, + .vsel_mask = RK808_LDO_VSEL_MASK, + .enable_reg = RK808_LDO_EN_REG, + .enable_mask = BIT(1), + .off_on_delay = 400, + }}, {{ + /* .name = "LDO_REG3", */ + .supply_name = "vcc7", + .ops = &rk808_reg_ops_ranges, + .n_voltages = 16, + .linear_ranges = rk808_ldo3_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk808_ldo3_voltage_ranges), + .vsel_reg = RK808_LDO3_ON_VSEL_REG, + .vsel_mask = RK808_BUCK4_VSEL_MASK, + .enable_reg = RK808_LDO_EN_REG, + .enable_mask = BIT(2), + .off_on_delay = 400, + }}, {{ + /* .name = "LDO_REG4", */ + .supply_name = "vcc9", + .ops = &rk808_reg_ops, + .min_uV = 1800000, + .uV_step = 100000, + .n_voltages = 17, + .vsel_reg = RK808_LDO4_ON_VSEL_REG, + .vsel_mask = RK808_LDO_VSEL_MASK, + .enable_reg = RK808_LDO_EN_REG, + .enable_mask = BIT(3), + .off_on_delay = 400, + }}, {{ + /* .name = "LDO_REG5", */ + .supply_name = "vcc9", + .ops = &rk808_reg_ops, + .min_uV = 1800000, + .uV_step = 100000, + .n_voltages = 17, + .vsel_reg = RK808_LDO5_ON_VSEL_REG, + .vsel_mask = RK808_LDO_VSEL_MASK, + .enable_reg = RK808_LDO_EN_REG, + .enable_mask = BIT(4), + .off_on_delay = 400, + }}, {{ + /* .name = "LDO_REG6", */ + .supply_name = "vcc10", + .ops = &rk808_reg_ops, + .min_uV = 800000, + .uV_step = 100000, + .n_voltages = 18, + .vsel_reg = RK808_LDO6_ON_VSEL_REG, + .vsel_mask = RK808_LDO_VSEL_MASK, + .enable_reg = RK808_LDO_EN_REG, + .enable_mask = BIT(5), + .off_on_delay = 400, + }}, {{ + /* .name = "LDO_REG7", */ + .supply_name = "vcc7", + .ops = &rk808_reg_ops, + .min_uV = 800000, + .uV_step = 100000, + .n_voltages = 18, + .vsel_reg = RK808_LDO7_ON_VSEL_REG, + .vsel_mask = RK808_LDO_VSEL_MASK, + .enable_reg = RK808_LDO_EN_REG, + .enable_mask = BIT(6), + .off_on_delay = 400, + }}, {{ + /* .name = "LDO_REG8", */ + .supply_name = "vcc11", + .ops = &rk808_reg_ops, + .min_uV = 1800000, + .uV_step = 100000, + .n_voltages = 17, + .vsel_reg = RK808_LDO8_ON_VSEL_REG, + .vsel_mask = RK808_LDO_VSEL_MASK, + .enable_reg = RK808_LDO_EN_REG, + .enable_mask = BIT(7), + .off_on_delay = 400, + }}, {{ + /* .name = "SWITCH_REG1", */ + .supply_name = "vcc8", + .ops = &rk808_switch_ops, + .enable_reg = RK808_DCDC_EN_REG, + .enable_mask = BIT(5), + }}, {{ + /* .name = "SWITCH_REG2", */ + .supply_name = "vcc12", + .ops = &rk808_switch_ops, + .enable_reg = RK808_DCDC_EN_REG, + .enable_mask = BIT(6), + }}, +}; +static_assert(ARRAY_SIZE(rk808_reg) == RK808_NUM_REGULATORS); + +static struct rk_regulator_cfg rk809_reg[] = { + {{ + /* .name = "DCDC_REG1", */ + .supply_name = "vcc1", + .ops = &rk817_buck_ops_range, + .n_voltages = RK817_BUCK1_SEL_CNT + 1, + .linear_ranges = rk817_buck1_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk817_buck1_voltage_ranges), + .vsel_reg = RK817_BUCK1_ON_VSEL_REG, + .vsel_mask = RK817_BUCK_VSEL_MASK, + .enable_reg = RK817_POWER_EN_REG(0), + .enable_mask = ENABLE_MASK(RK817_ID_DCDC1), + .enable_val = ENABLE_MASK(RK817_ID_DCDC1), + .disable_val = DISABLE_VAL(RK817_ID_DCDC1), + }}, {{ + /* .name = "DCDC_REG2", */ + .supply_name = "vcc2", + .ops = &rk817_buck_ops_range, + .n_voltages = RK817_BUCK1_SEL_CNT + 1, + .linear_ranges = rk817_buck1_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk817_buck1_voltage_ranges), + .vsel_reg = RK817_BUCK2_ON_VSEL_REG, + .vsel_mask = RK817_BUCK_VSEL_MASK, + .enable_reg = RK817_POWER_EN_REG(0), + .enable_mask = ENABLE_MASK(RK817_ID_DCDC2), + .enable_val = ENABLE_MASK(RK817_ID_DCDC2), + .disable_val = DISABLE_VAL(RK817_ID_DCDC2), + }}, {{ + /* .name = "DCDC_REG3", */ + .supply_name = "vcc3", + .ops = &rk817_buck_ops_range, + .n_voltages = RK817_BUCK1_SEL_CNT + 1, + .linear_ranges = rk817_buck1_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk817_buck1_voltage_ranges), + .vsel_reg = RK817_BUCK3_ON_VSEL_REG, + .vsel_mask = RK817_BUCK_VSEL_MASK, + .enable_reg = RK817_POWER_EN_REG(0), + .enable_mask = ENABLE_MASK(RK817_ID_DCDC3), + .enable_val = ENABLE_MASK(RK817_ID_DCDC3), + .disable_val = DISABLE_VAL(RK817_ID_DCDC3), + }}, {{ + /* .name = "DCDC_REG4", */ + .supply_name = "vcc4", + .ops = &rk817_buck_ops_range, + .n_voltages = RK817_BUCK3_SEL_CNT + 1, + .linear_ranges = rk817_buck3_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk817_buck3_voltage_ranges), + .vsel_reg = RK817_BUCK4_ON_VSEL_REG, + .vsel_mask = RK817_BUCK_VSEL_MASK, + .enable_reg = RK817_POWER_EN_REG(0), + .enable_mask = ENABLE_MASK(RK817_ID_DCDC4), + .enable_val = ENABLE_MASK(RK817_ID_DCDC4), + .disable_val = DISABLE_VAL(RK817_ID_DCDC4), + }}, {{ + /* .name = "DCDC_REG5", */ + .supply_name = "vcc9", + .ops = &rk809_buck5_ops_range, + .n_voltages = RK809_BUCK5_SEL_CNT, + .linear_ranges = rk809_buck5_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk809_buck5_voltage_ranges), + .vsel_reg = RK809_BUCK5_CONFIG(0), + .vsel_mask = RK809_BUCK5_VSEL_MASK, + .enable_reg = RK817_POWER_EN_REG(3), + .enable_mask = ENABLE_MASK(1), + .enable_val = ENABLE_MASK(1), + .disable_val = DISABLE_VAL(1), + }}, + RK817_DESC(/* "LDO_REG1", */ "vcc5", 600, 3400, 25, + RK817_LDO_ON_VSEL_REG(0), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(1), ENABLE_MASK(0), + DISABLE_VAL(0), 400), + RK817_DESC(/* "LDO_REG2", */ "vcc5", 600, 3400, 25, + RK817_LDO_ON_VSEL_REG(1), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(1), ENABLE_MASK(1), + DISABLE_VAL(1), 400), + RK817_DESC(/* "LDO_REG3", */ "vcc5", 600, 3400, 25, + RK817_LDO_ON_VSEL_REG(2), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(1), ENABLE_MASK(2), + DISABLE_VAL(2), 400), + RK817_DESC(/* "LDO_REG4", */ "vcc6", 600, 3400, 25, + RK817_LDO_ON_VSEL_REG(3), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(1), ENABLE_MASK(3), + DISABLE_VAL(3), 400), + RK817_DESC(/* "LDO_REG5", */ "vcc6", 600, 3400, 25, + RK817_LDO_ON_VSEL_REG(4), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(2), ENABLE_MASK(0), + DISABLE_VAL(0), 400), + RK817_DESC(/* "LDO_REG6", */ "vcc6", 600, 3400, 25, + RK817_LDO_ON_VSEL_REG(5), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(2), ENABLE_MASK(1), + DISABLE_VAL(1), 400), + RK817_DESC(/* "LDO_REG7", */ "vcc7", 600, 3400, 25, + RK817_LDO_ON_VSEL_REG(6), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(2), ENABLE_MASK(2), + DISABLE_VAL(2), 400), + RK817_DESC(/* "LDO_REG8", */ "vcc7", 600, 3400, 25, + RK817_LDO_ON_VSEL_REG(7), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(2), ENABLE_MASK(3), + DISABLE_VAL(3), 400), + RK817_DESC(/* "LDO_REG9", */ "vcc7", 600, 3400, 25, + RK817_LDO_ON_VSEL_REG(8), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(3), ENABLE_MASK(0), + DISABLE_VAL(0), 400), + RK817_DESC_SWITCH(/* "SWITCH_REG1", */ "vcc9", + RK817_POWER_EN_REG(3), ENABLE_MASK(2), DISABLE_VAL(2)), + RK817_DESC_SWITCH(/* "SWITCH_REG2", */ "vcc8", + RK817_POWER_EN_REG(3), ENABLE_MASK(3), DISABLE_VAL(3)), +}; +static_assert(ARRAY_SIZE(rk809_reg) == RK809_NUM_REGULATORS); + +static struct rk_regulator_cfg rk817_reg[] = { + {{ + /* .name = "DCDC_REG1", */ + .supply_name = "vcc1", + .ops = &rk817_buck_ops_range, + .n_voltages = RK817_BUCK1_SEL_CNT + 1, + .linear_ranges = rk817_buck1_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk817_buck1_voltage_ranges), + .vsel_reg = RK817_BUCK1_ON_VSEL_REG, + .vsel_mask = RK817_BUCK_VSEL_MASK, + .enable_reg = RK817_POWER_EN_REG(0), + .enable_mask = ENABLE_MASK(RK817_ID_DCDC1), + .enable_val = ENABLE_MASK(RK817_ID_DCDC1), + .disable_val = DISABLE_VAL(RK817_ID_DCDC1), + }}, {{ + /* .name = "DCDC_REG2", */ + .supply_name = "vcc2", + .ops = &rk817_buck_ops_range, + .n_voltages = RK817_BUCK1_SEL_CNT + 1, + .linear_ranges = rk817_buck1_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk817_buck1_voltage_ranges), + .vsel_reg = RK817_BUCK2_ON_VSEL_REG, + .vsel_mask = RK817_BUCK_VSEL_MASK, + .enable_reg = RK817_POWER_EN_REG(0), + .enable_mask = ENABLE_MASK(RK817_ID_DCDC2), + .enable_val = ENABLE_MASK(RK817_ID_DCDC2), + .disable_val = DISABLE_VAL(RK817_ID_DCDC2), + }}, {{ + /* .name = "DCDC_REG3", */ + .supply_name = "vcc3", + .ops = &rk817_buck_ops_range, + .n_voltages = RK817_BUCK1_SEL_CNT + 1, + .linear_ranges = rk817_buck1_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk817_buck1_voltage_ranges), + .vsel_reg = RK817_BUCK3_ON_VSEL_REG, + .vsel_mask = RK817_BUCK_VSEL_MASK, + .enable_reg = RK817_POWER_EN_REG(0), + .enable_mask = ENABLE_MASK(RK817_ID_DCDC3), + .enable_val = ENABLE_MASK(RK817_ID_DCDC3), + .disable_val = DISABLE_VAL(RK817_ID_DCDC3), + }}, {{ + /* .name = "DCDC_REG4", */ + .supply_name = "vcc4", + .ops = &rk817_buck_ops_range, + .n_voltages = RK817_BUCK3_SEL_CNT + 1, + .linear_ranges = rk817_buck3_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk817_buck3_voltage_ranges), + .vsel_reg = RK817_BUCK4_ON_VSEL_REG, + .vsel_mask = RK817_BUCK_VSEL_MASK, + .enable_reg = RK817_POWER_EN_REG(0), + .enable_mask = ENABLE_MASK(RK817_ID_DCDC4), + .enable_val = ENABLE_MASK(RK817_ID_DCDC4), + .disable_val = DISABLE_VAL(RK817_ID_DCDC4), + }}, + RK817_DESC(/* "LDO_REG1", */ "vcc5", 600, 3400, 25, + RK817_LDO_ON_VSEL_REG(0), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(1), ENABLE_MASK(0), + DISABLE_VAL(0), 400), + RK817_DESC(/* "LDO_REG2", */ "vcc5", 600, 3400, 25, + RK817_LDO_ON_VSEL_REG(1), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(1), ENABLE_MASK(1), + DISABLE_VAL(1), 400), + RK817_DESC(/* "LDO_REG3", */ "vcc5", 600, 3400, 25, + RK817_LDO_ON_VSEL_REG(2), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(1), ENABLE_MASK(2), + DISABLE_VAL(2), 400), + RK817_DESC(/* "LDO_REG4", */ "vcc6", 600, 3400, 25, + RK817_LDO_ON_VSEL_REG(3), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(1), ENABLE_MASK(3), + DISABLE_VAL(3), 400), + RK817_DESC(/* "LDO_REG5", */ "vcc6", 600, 3400, 25, + RK817_LDO_ON_VSEL_REG(4), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(2), ENABLE_MASK(0), + DISABLE_VAL(0), 400), + RK817_DESC(/* "LDO_REG6", */ "vcc6", 600, 3400, 25, + RK817_LDO_ON_VSEL_REG(5), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(2), ENABLE_MASK(1), + DISABLE_VAL(1), 400), + RK817_DESC(/* "LDO_REG7", */ "vcc7", 600, 3400, 25, + RK817_LDO_ON_VSEL_REG(6), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(2), ENABLE_MASK(2), + DISABLE_VAL(2), 400), + RK817_DESC(/* "LDO_REG8", */ "vcc7", 600, 3400, 25, + RK817_LDO_ON_VSEL_REG(7), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(2), ENABLE_MASK(3), + DISABLE_VAL(3), 400), + RK817_DESC(/* "LDO_REG9", */ "vcc7", 600, 3400, 25, + RK817_LDO_ON_VSEL_REG(8), RK817_LDO_VSEL_MASK, + RK817_POWER_EN_REG(3), ENABLE_MASK(0), + DISABLE_VAL(0), 400), + RK817_BOOST_DESC(/* "BOOST", */ "vcc8", 4700, 5400, 100, + RK817_BOOST_OTG_CFG, RK817_BOOST_VSEL_MASK, + RK817_POWER_EN_REG(3), ENABLE_MASK(1), ENABLE_MASK(1), + DISABLE_VAL(1), 400), + RK817_DESC_SWITCH(/* "OTG_SWITCH", */ "vcc9", + RK817_POWER_EN_REG(3), ENABLE_MASK(2), DISABLE_VAL(2)), +}; +static_assert(ARRAY_SIZE(rk817_reg) == RK817_NUM_REGULATORS); + +static struct rk_regulator_cfg rk818_reg[] = { + {{ + /* .name = "DCDC_REG1", */ + .supply_name = "vcc1", + .ops = &rk808_reg_ops, + .min_uV = 712500, + .uV_step = 12500, + .n_voltages = 64, + .vsel_reg = RK818_BUCK1_ON_VSEL_REG, + .vsel_mask = RK818_BUCK_VSEL_MASK, + .enable_reg = RK818_DCDC_EN_REG, + .enable_mask = BIT(0), + }}, {{ + /* .name = "DCDC_REG2", */ + .supply_name = "vcc2", + .ops = &rk808_reg_ops, + .min_uV = 712500, + .uV_step = 12500, + .n_voltages = 64, + .vsel_reg = RK818_BUCK2_ON_VSEL_REG, + .vsel_mask = RK818_BUCK_VSEL_MASK, + .enable_reg = RK818_DCDC_EN_REG, + .enable_mask = BIT(1), + }}, {{ + /* .name = "DCDC_REG3", */ + .supply_name = "vcc3", + .ops = &rk808_switch_ops, + .n_voltages = 1, + .enable_reg = RK818_DCDC_EN_REG, + .enable_mask = BIT(2), + }}, + RK8XX_DESC(/* "DCDC_REG4", */ "vcc4", 1800, 3600, 100, + RK818_BUCK4_ON_VSEL_REG, RK818_BUCK4_VSEL_MASK, + RK818_DCDC_EN_REG, BIT(3), 0), + RK8XX_DESC(/* "DCDC_BOOST", */ "boost", 4700, 5400, 100, + RK818_BOOST_LDO9_ON_VSEL_REG, RK818_BOOST_ON_VSEL_MASK, + RK818_DCDC_EN_REG, BIT(4), 0), + RK8XX_DESC(/* "LDO_REG1", */ "vcc6", 1800, 3400, 100, + RK818_LDO1_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG, + BIT(0), 400), + RK8XX_DESC(/* "LDO_REG2", */ "vcc6", 1800, 3400, 100, + RK818_LDO2_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG, + BIT(1), 400), + {{ + /* .name = "LDO_REG3", */ + .supply_name = "vcc7", + .ops = &rk808_reg_ops_ranges, + .n_voltages = 16, + .linear_ranges = rk808_ldo3_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk808_ldo3_voltage_ranges), + .vsel_reg = RK818_LDO3_ON_VSEL_REG, + .vsel_mask = RK818_LDO3_ON_VSEL_MASK, + .enable_reg = RK818_LDO_EN_REG, + .enable_mask = BIT(2), + .off_on_delay = 400, + }}, + RK8XX_DESC(/* "LDO_REG4", */ "vcc8", 1800, 3400, 100, + RK818_LDO4_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG, + BIT(3), 400), + RK8XX_DESC(/* "LDO_REG5", */ "vcc7", 1800, 3400, 100, + RK818_LDO5_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG, + BIT(4), 400), + RK8XX_DESC(/* "LDO_REG6", */ "vcc8", 800, 2500, 100, + RK818_LDO6_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG, + BIT(5), 400), + RK8XX_DESC(/* "LDO_REG7", */ "vcc7", 800, 2500, 100, + RK818_LDO7_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG, + BIT(6), 400), + RK8XX_DESC(/* "LDO_REG8", */ "vcc8", 1800, 3400, 100, + RK818_LDO8_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG, + BIT(7), 400), + RK8XX_DESC(/* "LDO_REG9", */ "vcc9", 1800, 3400, 100, + RK818_BOOST_LDO9_ON_VSEL_REG, RK818_LDO_VSEL_MASK, + RK818_DCDC_EN_REG, BIT(5), 400), + RK8XX_DESC_SWITCH(/* "SWITCH_REG", */ "vcc9", + RK818_DCDC_EN_REG, BIT(6)), + RK8XX_DESC_SWITCH(/* "HDMI_SWITCH", */ "h_5v", + RK818_H5V_EN_REG, BIT(0)), + RK8XX_DESC_SWITCH(/* "OTG_SWITCH", */ "usb", + RK818_DCDC_EN_REG, BIT(7)), +}; +static_assert(ARRAY_SIZE(rk818_reg) == RK818_NUM_REGULATORS); + +static int rk808_regulator_register(struct rk808 *rk808, int id, + struct of_regulator_match *match, + struct rk_regulator_cfg *cfg) +{ + struct device_d *dev = &rk808->i2c->dev; + int ret; + + if (!match->of_node) { + dev_dbg(dev, "Skip missing DTB regulator %s", match->name); + return 0; + } + + cfg->rdev.desc = &cfg->desc; + cfg->rdev.dev = dev; + cfg->rdev.regmap = rk808->regmap; + + ret = of_regulator_register(&cfg->rdev, match->of_node); + if (ret) { + dev_err(dev, "failed to register %s regulator\n", match->name); + return ret; + } + + dev_dbg(dev, "registered %s\n", match->name); + + return 0; +} + +#define MATCH(variant, _name, _id) [RK##variant##_ID_##_id] = \ + { .name = #_name, .desc = &rk##variant##_reg[RK##variant##_ID_##_id].desc } + +static struct of_regulator_match rk805_reg_matches[] = { + MATCH(805, DCDC_REG1, DCDC1), + MATCH(805, DCDC_REG2, DCDC2), + MATCH(805, DCDC_REG3, DCDC3), + MATCH(805, DCDC_REG4, DCDC4), + MATCH(805, LDO_REG1, LDO1), + MATCH(805, LDO_REG2, LDO2), + MATCH(805, LDO_REG3, LDO3), +}; +static_assert(ARRAY_SIZE(rk805_reg_matches) == RK805_NUM_REGULATORS); + +static struct of_regulator_match rk808_reg_matches[] = { + MATCH(808, DCDC_REG1, DCDC1), + MATCH(808, DCDC_REG2, DCDC2), + MATCH(808, DCDC_REG3, DCDC3), + MATCH(808, DCDC_REG4, DCDC4), + MATCH(808, LDO_REG1, LDO1), + MATCH(808, LDO_REG2, LDO2), + MATCH(808, LDO_REG3, LDO3), + MATCH(808, LDO_REG4, LDO4), + MATCH(808, LDO_REG5, LDO5), + MATCH(808, LDO_REG6, LDO6), + MATCH(808, LDO_REG7, LDO7), + MATCH(808, LDO_REG8, LDO8), + MATCH(808, SWITCH_REG1, SWITCH1), + MATCH(808, SWITCH_REG2, SWITCH2), +}; +static_assert(ARRAY_SIZE(rk808_reg_matches) == RK808_NUM_REGULATORS); + +static struct of_regulator_match rk809_reg_matches[] = { + MATCH(809, DCDC_REG1, DCDC1), + MATCH(809, DCDC_REG2, DCDC2), + MATCH(809, DCDC_REG3, DCDC3), + MATCH(809, DCDC_REG4, DCDC4), + MATCH(809, LDO_REG1, LDO1), + MATCH(809, LDO_REG2, LDO2), + MATCH(809, LDO_REG3, LDO3), + MATCH(809, LDO_REG4, LDO4), + MATCH(809, LDO_REG5, LDO5), + MATCH(809, LDO_REG6, LDO6), + MATCH(809, LDO_REG7, LDO7), + MATCH(809, LDO_REG8, LDO8), + MATCH(809, LDO_REG9, LDO9), + MATCH(809, DCDC_REG5, DCDC5), + MATCH(809, SWITCH_REG1, SW1), + MATCH(809, SWITCH_REG2, SW2), +}; +static_assert(ARRAY_SIZE(rk809_reg_matches) == RK809_NUM_REGULATORS); + +static struct of_regulator_match rk817_reg_matches[] = { + MATCH(817, DCDC_REG1, DCDC1), + MATCH(817, DCDC_REG2, DCDC2), + MATCH(817, DCDC_REG3, DCDC3), + MATCH(817, DCDC_REG4, DCDC4), + MATCH(817, LDO_REG1, LDO1), + MATCH(817, LDO_REG2, LDO2), + MATCH(817, LDO_REG3, LDO3), + MATCH(817, LDO_REG4, LDO4), + MATCH(817, LDO_REG5, LDO5), + MATCH(817, LDO_REG6, LDO6), + MATCH(817, LDO_REG7, LDO7), + MATCH(817, LDO_REG8, LDO8), + MATCH(817, LDO_REG9, LDO9), + MATCH(817, BOOST, BOOST), + MATCH(817, OTG_SWITCH, BOOST_OTG_SW), +}; +static_assert(ARRAY_SIZE(rk817_reg_matches) == RK817_NUM_REGULATORS); + +static struct of_regulator_match rk818_reg_matches[] = { + MATCH(818, DCDC_REG1, DCDC1), + MATCH(818, DCDC_REG2, DCDC2), + MATCH(818, DCDC_REG3, DCDC3), + MATCH(818, DCDC_REG4, DCDC4), + MATCH(818, DCDC_BOOST, BOOST), + MATCH(818, LDO_REG1, LDO1), + MATCH(818, LDO_REG2, LDO2), + MATCH(818, LDO_REG3, LDO3), + MATCH(818, LDO_REG4, LDO4), + MATCH(818, LDO_REG5, LDO5), + MATCH(818, LDO_REG6, LDO6), + MATCH(818, LDO_REG7, LDO7), + MATCH(818, LDO_REG8, LDO8), + MATCH(818, LDO_REG9, LDO9), + MATCH(818, SWITCH_REG, SWITCH), + MATCH(818, HDMI_SWITCH, HDMI_SWITCH), + MATCH(818, OTG_SWITCH, OTG_SWITCH), +}; +static_assert(ARRAY_SIZE(rk818_reg_matches) == RK818_NUM_REGULATORS); + +static int rk808_regulator_dt_parse(struct device_d *dev, + struct of_regulator_match *matches, + int nregulators) +{ + struct device_node *np = dev->device_node; + + np = of_get_child_by_name(np, "regulators"); + if (!np) + return -ENOENT; + + return of_regulator_match(dev, np, matches, nregulators); +} + +static int rk808_regulator_probe(struct device_d *dev) +{ + struct rk808 *rk808 = dev->parent->priv; + struct rk_regulator_cfg *regulators; + struct of_regulator_match *matches; + int ret, i, nregulators; + + switch (rk808->variant) { + case RK805_ID: + regulators = rk805_reg; + matches = rk805_reg_matches; + nregulators = RK805_NUM_REGULATORS; + break; + case RK808_ID: + regulators = rk808_reg; + matches = rk808_reg_matches; + nregulators = RK809_NUM_REGULATORS; + break; + case RK809_ID: + regulators = rk809_reg; + matches = rk809_reg_matches; + nregulators = RK809_NUM_REGULATORS; + break; + case RK817_ID: + regulators = rk817_reg; + matches = rk817_reg_matches; + nregulators = RK817_NUM_REGULATORS; + break; + case RK818_ID: + regulators = rk818_reg; + matches = rk818_reg_matches; + nregulators = RK818_NUM_REGULATORS; + break; + default: + dev_err(dev, "unsupported RK8XX ID %lu\n", rk808->variant); + return -EINVAL; + } + + ret = rk808_regulator_dt_parse(&rk808->i2c->dev, matches, nregulators); + if (ret < 0) + return ret; + + /* Instantiate the regulators */ + for (i = 0; i < nregulators; i++) { + ret = rk808_regulator_register(rk808, i, &matches[i], + ®ulators[i]); + if (ret < 0) + return ret; + } + + return 0; +} + +static struct driver_d rk808_regulator_driver = { + .name = "rk808-regulator", + .probe = rk808_regulator_probe, +}; +device_platform_driver(rk808_regulator_driver); + +MODULE_DESCRIPTION("regulator driver for the rk808 series PMICs"); +MODULE_AUTHOR("Chris Zhong<zyw@rock-chips.com>"); +MODULE_AUTHOR("Zhang Qing<zhangqing@rock-chips.com>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:rk808-regulator"); diff --git a/drivers/reset/core.c b/drivers/reset/core.c index 4355c3415e..b252f94d6e 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -157,14 +157,14 @@ int reset_control_deassert(struct reset_control *rstc) EXPORT_SYMBOL_GPL(reset_control_deassert); /** - * of_reset_control_count - Count reset lines - * @node: device node + * reset_control_get_count - Count reset lines + * @dev: device * * Returns number of resets, 0 if none specified */ -static int of_reset_control_count(struct device_node *node) +int reset_control_get_count(struct device_d *dev) { - return of_count_phandle_with_args(node, "resets", "#reset-cells"); + return of_count_phandle_with_args(dev->device_node, "resets", "#reset-cells"); } /** @@ -236,8 +236,11 @@ struct reset_control *of_reset_control_get(struct device_node *node, { int index = 0; - if (id) + if (id) { index = of_property_match_string(node, "reset-names", id); + if (index < 0) + return ERR_PTR(-ENOENT); + } return of_reset_control_get_by_index(node, index); } @@ -354,7 +357,7 @@ int device_reset_all(struct device_d *dev) struct reset_control *rstc; int ret, i; - for (i = 0; i < of_reset_control_count(dev->device_node); i++) { + for (i = 0; i < reset_control_get_count(dev); i++) { int ret; rstc = of_reset_control_get_by_index(dev->device_node, i); diff --git a/drivers/rtc/rtc-abracon.c b/drivers/rtc/rtc-abracon.c index 6144fc0aa9..585b95c4a7 100644 --- a/drivers/rtc/rtc-abracon.c +++ b/drivers/rtc/rtc-abracon.c @@ -84,7 +84,6 @@ static int abracon_probe(struct device_d *dev) { struct i2c_client *client = to_i2c_client(dev); struct abracon *abracon; - int ret; abracon = xzalloc(sizeof(*abracon)); @@ -93,9 +92,7 @@ static int abracon_probe(struct device_d *dev) abracon->rtc.ops = &ds13xx_rtc_ops; abracon->rtc.dev = dev; - ret = rtc_register(&abracon->rtc); - - return ret; + return rtc_register(&abracon->rtc); }; static struct platform_device_id abracon_id[] = { diff --git a/drivers/rtc/rtc-pcf85363.c b/drivers/rtc/rtc-pcf85363.c index 7b785d6a77..b9f0fc6012 100644 --- a/drivers/rtc/rtc-pcf85363.c +++ b/drivers/rtc/rtc-pcf85363.c @@ -131,7 +131,6 @@ static int pcf85363_probe(struct device_d *dev) struct i2c_client *client = to_i2c_client(dev); struct pcf85363 *pcf85363; struct regmap *regmap; - int ret; regmap = regmap_init_i2c(client, &pcf85363_regmap_i2c_config); @@ -147,9 +146,7 @@ static int pcf85363_probe(struct device_d *dev) pcf85363->rtc.ops = &rtc_ops; pcf85363->rtc.dev = dev; - ret = rtc_register(&pcf85363->rtc); - - return ret; + return rtc_register(&pcf85363->rtc); } static struct platform_device_id dev_ids[] = { diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c index 07f951e535..e5cbc3624e 100644 --- a/drivers/serial/serial_ns16550.c +++ b/drivers/serial/serial_ns16550.c @@ -309,11 +309,11 @@ static void ns16550_flush(struct console_device *cdev) static void ns16550_probe_dt(struct device_d *dev, struct ns16550_priv *priv) { - struct device_node *np = dev->device_node; + struct device_node *np = dev_of_node(dev); u32 offset; u32 width = 1; - if (!IS_ENABLED(CONFIG_OFDEVICE)) + if (!np) return; of_property_read_u32(np, "clock-frequency", &priv->plat.clock); @@ -368,7 +368,7 @@ static __maybe_unused struct ns16550_drvdata omap_drvdata = { .linux_earlycon_name = "omap8250", }; -static __maybe_unused struct ns16550_drvdata am43xx_drvdata = { +static __maybe_unused struct ns16550_drvdata omap_clk48m_drvdata = { .init_port = ns16550_omap_init_port, .linux_console_name = "ttyO", .clk_default = 48000000, @@ -561,7 +561,7 @@ static struct of_device_id ns16550_serial_dt_ids[] = { .data = &omap_drvdata, }, { .compatible = "ti,am4372-uart", - .data = &am43xx_drvdata, + .data = &omap_clk48m_drvdata, }, #endif #if IS_ENABLED(CONFIG_MACH_MIPS_XBURST) @@ -584,7 +584,7 @@ static struct of_device_id ns16550_serial_dt_ids[] = { static __maybe_unused struct platform_device_id ns16550_serial_ids[] = { { .name = "omap-uart", - .driver_data = (unsigned long)&omap_drvdata, + .driver_data = (unsigned long)&omap_clk48m_drvdata, }, { /* sentinel */ }, diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c index 62cfc21519..a0e78ce55e 100644 --- a/drivers/soc/imx/gpcv2.c +++ b/drivers/soc/imx/gpcv2.c @@ -483,10 +483,10 @@ again: pd_dev = xzalloc(sizeof(*pd_dev)); pd_dev->device_node = np; + pd_dev->device_node->dev = pd_dev; pd_dev->id = domain_index; pd_dev->parent = dev; pd_dev->priv = domain; - pd_dev->device_node = np; dev_set_name(pd_dev, imx_pgc_domain_id[0].name); ret = platform_device_register(pd_dev); diff --git a/drivers/spi/stm32_spi.c b/drivers/spi/stm32_spi.c index 0cb04a968c..639c4f1740 100644 --- a/drivers/spi/stm32_spi.c +++ b/drivers/spi/stm32_spi.c @@ -11,6 +11,7 @@ #include <init.h> #include <errno.h> #include <linux/reset.h> +#include <linux/spi/spi-mem.h> #include <spi/spi.h> #include <linux/bitops.h> #include <clock.h> @@ -474,6 +475,24 @@ out: return ret; } +static int stm32_spi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) +{ + if (op->data.nbytes > SPI_CR2_TSIZE) + op->data.nbytes = SPI_CR2_TSIZE; + + return 0; +} + +static int stm32_spi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) +{ + return -ENOTSUPP; +} + +static const struct spi_controller_mem_ops stm32_spi_mem_ops = { + .adjust_op_size = stm32_spi_adjust_op_size, + .exec_op = stm32_spi_exec_op, +}; + static int stm32_spi_get_fifo_size(struct stm32_spi_priv *priv) { u32 count = 0; @@ -522,6 +541,7 @@ static int stm32_spi_probe(struct device_d *dev) master->setup = stm32_spi_setup; master->transfer = stm32_spi_transfer; + master->mem_ops = &stm32_spi_mem_ops; master->bus_num = -1; stm32_spi_dt_probe(priv); diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 10c713e833..96c51768f6 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -4,6 +4,9 @@ menuconfig USB_GADGET select POLLER bool "USB gadget support" +config USB_GADGET_DRIVER_ARC_PBL + bool + if USB_GADGET config USB_GADGET_DUALSPEED @@ -16,9 +19,6 @@ config USB_GADGET_DRIVER_ARC default y select USB_GADGET_DUALSPEED -config USB_GADGET_DRIVER_ARC_PBL - bool - config USB_GADGET_DRIVER_AT91 bool prompt "at91 gadget driver" @@ -37,6 +37,7 @@ config USB_GADGET_AUTOSTART bool default y prompt "Automatically start usbgadget on boot" + depends on GLOBALVAR select SYSTEM_PARTITIONS if USB_GADGET_MASS_STORAGE help Enabling this option allows to automatically start a dfu or diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index 102d8714f8..6225e9a313 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c @@ -137,6 +137,12 @@ static int multi_bind_fastboot(struct usb_composite_dev *cdev) return usb_add_function(&config, f_fastboot); } +static bool fastboot_has_exports(struct f_multi_opts *opts) +{ + return !file_list_empty(opts->fastboot_opts.files) || + opts->fastboot_opts.export_bbu; +} + static int multi_bind_ums(struct usb_composite_dev *cdev) { int ret; @@ -179,7 +185,7 @@ static int multi_unbind(struct usb_composite_dev *cdev) usb_put_function_instance(fi_dfu); } - if (gadget_multi_opts->fastboot_opts.files) { + if (fastboot_has_exports(gadget_multi_opts)) { usb_put_function(f_fastboot); usb_put_function_instance(fi_fastboot); } @@ -219,7 +225,7 @@ static int multi_bind(struct usb_composite_dev *cdev) if (ret) return ret; - if (gadget_multi_opts->fastboot_opts.files) { + if (fastboot_has_exports(gadget_multi_opts)) { printf("%s: creating Fastboot function\n", __func__); ret = multi_bind_fastboot(cdev); if (ret) @@ -259,7 +265,7 @@ unbind_dfu: if (gadget_multi_opts->dfu_opts.files) usb_put_function_instance(fi_dfu); unbind_fastboot: - if (gadget_multi_opts->fastboot_opts.files) + if (fastboot_has_exports(gadget_multi_opts)) usb_put_function_instance(fi_fastboot); return ret; @@ -312,8 +318,7 @@ unsigned usb_multi_count_functions(struct f_multi_opts *opts) { unsigned count = 0; - count += !file_list_empty(opts->fastboot_opts.files) || - opts->fastboot_opts.export_bbu; + count += fastboot_has_exports(opts); count += !file_list_empty(opts->dfu_opts.files); count += !file_list_empty(opts->ums_opts.files); count += opts->create_acm; diff --git a/drivers/usb/imx/chipidea-imx.c b/drivers/usb/imx/chipidea-imx.c index bf8b6f1eb8..f71cf80b7d 100644 --- a/drivers/usb/imx/chipidea-imx.c +++ b/drivers/usb/imx/chipidea-imx.c @@ -260,8 +260,6 @@ static int imx_chipidea_probe(struct device_d *dev) * devices which have only one. */ ci->clk = clk_get(dev, NULL); - if (!IS_ERR(ci->clk)) - clk_enable(ci->clk); /* Device trees are using both "phys" and "fsl,usbphy". Prefer the * more modern former one but fall back to the old one. @@ -302,6 +300,14 @@ static int imx_chipidea_probe(struct device_d *dev) ci->data.drvdata = ci; ci->data.usbphy = ci->usbphy; + /* + * Enable the clock after we ensured that all resources are available. + * This is crucial since the phy can be missing which and so the + * usb-controller <-> usb-phy communication is only partly initialized. + * This can trigger strange system hangs at least on i.MX8M SoCs. + */ + clk_enable(ci->clk); + if ((ci->flags & MXC_EHCI_PORTSC_MASK) == MXC_EHCI_MODE_HSIC) imx_chipidea_port_init(ci); diff --git a/drivers/video/stm32_ltdc.c b/drivers/video/stm32_ltdc.c index 645c20b554..9dc35ade61 100644 --- a/drivers/video/stm32_ltdc.c +++ b/drivers/video/stm32_ltdc.c @@ -98,7 +98,7 @@ static void ltdc_set_mode(struct ltdc_fb *priv, val |= GCR_HSPOL; if (mode->sync & FB_SYNC_VERT_HIGH_ACT) val |= GCR_VSPOL; - if (mode->display_flags & DISPLAY_FLAGS_DE_HIGH) + if (mode->display_flags & DISPLAY_FLAGS_DE_LOW) val |= GCR_DEPOL; if (mode->display_flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) val |= GCR_PCPOL; diff --git a/drivers/watchdog/imxwd.c b/drivers/watchdog/imxwd.c index 31ea388c2c..dba92cb46a 100644 --- a/drivers/watchdog/imxwd.c +++ b/drivers/watchdog/imxwd.c @@ -239,18 +239,17 @@ static int imx_wd_probe(struct device_d *dev) priv = xzalloc(sizeof(struct imx_wd)); iores = dev_request_mem_resource(dev, 0); - if (IS_ERR(iores)) { - dev_err(dev, "could not get memory region\n"); - return PTR_ERR(iores); - } + if (IS_ERR(iores)) + return dev_err_probe(dev, PTR_ERR(iores), + "could not get memory region\n"); clk = clk_get(dev, NULL); if (IS_ERR(clk)) - return PTR_ERR(clk); + return dev_err_probe(dev, PTR_ERR(clk), "Failed to get clk\n"); ret = clk_enable(clk); if (ret) - return ret; + return dev_err_probe(dev, ret, "Failed to enable clk\n"); priv->base = IOMEM(iores->start); priv->ops = ops; @@ -272,14 +271,17 @@ static int imx_wd_probe(struct device_d *dev) } ret = watchdog_register(&priv->wd); - if (ret) + if (ret) { + dev_err_probe(dev, ret, "Failed to register watchdog device\n"); goto on_error; + } } if (priv->ops->init) { ret = priv->ops->init(priv); if (ret) { - dev_err(dev, "Failed to init watchdog device %d\n", ret); + dev_err_probe(dev, ret, + "Failed to init watchdog device\n"); goto error_unregister; } } |