diff options
author | Dominik Sliwa <dominik.sliwa@toradex.com> | 2018-09-11 14:05:49 +0200 |
---|---|---|
committer | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2018-09-27 18:10:23 +0200 |
commit | 78e963c12c168bc82631cacdf3d59770fe973737 (patch) | |
tree | 348ca8ea2ff974404f30edd25256c24356c77cad | |
parent | 030c1155fb13ade4f279df8ae9c33ad49dde8014 (diff) |
apalis-tk1: mfd: k20: add fw_ignore and fw_reload parameters
Parameter fw_ignore disables fw version check.
Parameter fw_reload forces k20 firmware reflash via EzPort.
Signed-off-by: Dominik Sliwa <dominik.sliwa@toradex.com>
Acked-by: Marcel Ziswiler <marcel.ziswiler@toradex.com>
-rw-r--r-- | drivers/mfd/apalis-tk1-k20.c | 214 |
1 files changed, 122 insertions, 92 deletions
diff --git a/drivers/mfd/apalis-tk1-k20.c b/drivers/mfd/apalis-tk1-k20.c index 913be65c33e6..38d52b6d2d88 100644 --- a/drivers/mfd/apalis-tk1-k20.c +++ b/drivers/mfd/apalis-tk1-k20.c @@ -2,7 +2,7 @@ * Copyright 2016-2017 Toradex AG * Dominik Sliwa <dominik.sliwa@toradex.com> * - * based on an driver for MC13xxx by: + * based on a driver for MC13xxx by: * Copyright 2009-2010 Pengutronix * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> * @@ -29,6 +29,16 @@ #include "apalis-tk1-k20-ezp.h" #define APALIS_TK1_K20_MAX_MSG 4 +static unsigned int fw_ignore = 0; +module_param(fw_ignore , uint, 0); +MODULE_PARM_DESC(fw_ignore, "Assume that K20 is running valid fw version. " + "Don't verify, don't erase, don't update"); + +static unsigned int force_fw_reload = 0; +module_param(force_fw_reload , uint, 0); +MODULE_PARM_DESC(force_fw_reload, "Update K20 fw even when the same version" + " is already flashed."); + static const struct spi_device_id apalis_tk1_k20_device_ids[] = { { .name = "apalis-tk1-k20", @@ -142,7 +152,6 @@ static int apalis_tk1_k20_spi_write(void *context, const void *data, uint8_t out_data[APALIS_TK1_K20_MAX_BULK]; int ret; - spi->mode = SPI_MODE_1; if (count == 2) { @@ -704,18 +713,21 @@ static int apalis_tk1_k20_probe_gpios_dt( apalis_tk1_k20->reset_gpio = of_get_named_gpio(np, "rst-gpio", 0); if (apalis_tk1_k20->reset_gpio < 0) return apalis_tk1_k20->reset_gpio; + gpio_request(apalis_tk1_k20->reset_gpio, "apalis-tk1-k20-reset"); gpio_direction_output(apalis_tk1_k20->reset_gpio, 1); apalis_tk1_k20->ezpcs_gpio = of_get_named_gpio(np, "ezport-cs-gpio", 0); if (apalis_tk1_k20->ezpcs_gpio < 0) return apalis_tk1_k20->ezpcs_gpio; + gpio_request(apalis_tk1_k20->ezpcs_gpio, "apalis-tk1-k20-ezpcs"); gpio_direction_output(apalis_tk1_k20->ezpcs_gpio, 1); apalis_tk1_k20->int2_gpio = of_get_named_gpio(np, "int2-gpio", 0); if (apalis_tk1_k20->int2_gpio < 0) return apalis_tk1_k20->int2_gpio; + gpio_request(apalis_tk1_k20->int2_gpio, "apalis-tk1-k20-int2"); gpio_direction_output(apalis_tk1_k20->int2_gpio, 1); @@ -734,13 +746,101 @@ static inline int apalis_tk1_k20_probe_gpios_dt( } #endif +int apalis_tk1_k20_fw_update(struct apalis_tk1_k20_regmap *apalis_tk1_k20, + uint32_t revision) { + int erase_only = 0; + + if ((request_firmware(&fw_entry, "apalis-tk1-k20.bin", apalis_tk1_k20->dev) < 0) + && (revision != APALIS_TK1_K20_FW_VER)) { + dev_err(apalis_tk1_k20->dev, + "Unsupported firmware version %d.%d and no local" \ + " firmware file available.\n", + (revision & 0xF0 >> 8), + (revision & 0x0F)); + return -ENOTSUPP; + } + + if ((fw_entry == NULL) && (revision != APALIS_TK1_K20_FW_VER)) { + dev_err(apalis_tk1_k20->dev, + "Unsupported firmware version %d.%d and no local" \ + " firmware file available.\n", + (revision & 0xF0 >> 8), + (revision & 0x0F)); + return -ENOTSUPP; + } + + if (fw_entry != NULL) { + if (fw_entry->size == 1) + erase_only = 1; + } + + if ((apalis_tk1_k20_get_fw_revision() != APALIS_TK1_K20_FW_VER) && + (revision != APALIS_TK1_K20_FW_VER) && !erase_only && + (fw_entry != NULL)) { + dev_err(apalis_tk1_k20->dev, + "Unsupported firmware version in both the device " \ + "as well as the local firmware file.\n"); + release_firmware(fw_entry); + return -ENOTSUPP; + } + + if ((revision != APALIS_TK1_K20_FW_VER) && !erase_only && + (!apalis_tk1_k20_fw_ezport_status()) && + (fw_entry != NULL)) { + dev_err(apalis_tk1_k20->dev, + "Unsupported firmware version in the device and the " \ + "local firmware file disables the EZ Port.\n"); + release_firmware(fw_entry); + return -ENOTSUPP; + } + + if (((revision != APALIS_TK1_K20_FW_VER) || erase_only + || force_fw_reload) && (fw_entry != NULL)) { + int i = 0; + while (apalis_tk1_k20_enter_ezport(apalis_tk1_k20) < 0 + && i++ < 5) { + msleep(50); + } + if (i >= 5) { + dev_err(apalis_tk1_k20->dev, + "Problem entering EZ port mode.\n"); + release_firmware(fw_entry); + return -EIO; + } + if (apalis_tk1_k20_erase_chip_ezport(apalis_tk1_k20) < 0) { + dev_err(apalis_tk1_k20->dev, + "Problem erasing the chip. Deferring...\n"); + release_firmware(fw_entry); + return -EPROBE_DEFER; + } + if (erase_only) { + dev_err(apalis_tk1_k20->dev, + "Chip fully erased.\n"); + release_firmware(fw_entry); + return -EIO; + } + if (apalis_tk1_k20_flash_chip_ezport(apalis_tk1_k20) < 0) { + dev_err(apalis_tk1_k20->dev, + "Problem flashing new firmware. Deferring...\n"); + release_firmware(fw_entry); + return -EPROBE_DEFER; + } + + return 1; + } + if (fw_entry != NULL) + release_firmware(fw_entry); + + return 0; + +} + int apalis_tk1_k20_dev_init(struct device *dev) { struct apalis_tk1_k20_platform_data *pdata = dev_get_platdata(dev); struct apalis_tk1_k20_regmap *apalis_tk1_k20 = dev_get_drvdata(dev); uint32_t revision = 0x00; int ret, i; - int erase_only = 0; apalis_tk1_k20->dev = dev; @@ -762,99 +862,21 @@ int apalis_tk1_k20_dev_init(struct device *dev) &revision); #ifdef CONFIG_APALIS_TK1_K20_EZP - if ((request_firmware(&fw_entry, "apalis-tk1-k20.bin", dev) < 0) - && (revision != APALIS_TK1_K20_FW_VER)) { - dev_err(apalis_tk1_k20->dev, - "Unsupported firmware version %d.%d and no local" \ - " firmware file available.\n", - (revision & 0xF0 >> 8), - (revision & 0x0F)); - ret = -ENOTSUPP; - goto bad; - } - if ((fw_entry == NULL) && (revision != APALIS_TK1_K20_FW_VER)) { - dev_err(apalis_tk1_k20->dev, - "Unsupported firmware version %d.%d and no local" \ - " firmware file available.\n", - (revision & 0xF0 >> 8), - (revision & 0x0F)); - ret = -ENOTSUPP; - goto bad; - } - - if (fw_entry != NULL) { - if (fw_entry->size == 1) - erase_only = 1; - } - - if ((apalis_tk1_k20_get_fw_revision() != APALIS_TK1_K20_FW_VER) && - (revision != APALIS_TK1_K20_FW_VER) && !erase_only && - (fw_entry != NULL)) { - dev_err(apalis_tk1_k20->dev, - "Unsupported firmware version in both the device " \ - "as well as the local firmware file.\n"); - release_firmware(fw_entry); - ret = -ENOTSUPP; - goto bad; - } - - if ((revision != APALIS_TK1_K20_FW_VER) && !erase_only && - (!apalis_tk1_k20_fw_ezport_status()) && - (fw_entry != NULL)) { - dev_err(apalis_tk1_k20->dev, - "Unsupported firmware version in the device and the " \ - "local firmware file disables the EZ Port.\n"); - release_firmware(fw_entry); - ret = -ENOTSUPP; - goto bad; - } + if (fw_ignore == 0) { + ret = apalis_tk1_k20_fw_update(apalis_tk1_k20, revision); - if (((revision != APALIS_TK1_K20_FW_VER) || erase_only) && - (fw_entry != NULL)) { - i = 0; - while (apalis_tk1_k20_enter_ezport(apalis_tk1_k20) < 0 - && i++ < 5) { - msleep(50); - } - if (i >= 5) { - dev_err(apalis_tk1_k20->dev, - "Problem entering EZ port mode.\n"); - release_firmware(fw_entry); - ret = -EIO; + if (ret < 0) goto bad; - } - if (apalis_tk1_k20_erase_chip_ezport(apalis_tk1_k20) < 0) { - dev_err(apalis_tk1_k20->dev, - "Problem erasing the chip.\n"); - release_firmware(fw_entry); - ret = -EPROBE_DEFER; - goto bad; - } - if (erase_only) { - dev_err(apalis_tk1_k20->dev, - "Chip fully erased.\n"); - release_firmware(fw_entry); - ret = -EIO; - goto bad; - } - if (apalis_tk1_k20_flash_chip_ezport(apalis_tk1_k20) < 0) { - dev_err(apalis_tk1_k20->dev, - "Problem flashing new firmware.\n"); - release_firmware(fw_entry); - ret = -EPROBE_DEFER; - goto bad; - } } - if (fw_entry != NULL) - release_firmware(fw_entry); - - msleep(10); - apalis_tk1_k20_reset_chip(apalis_tk1_k20); - msleep(10); + if (ret) { + msleep(10); + apalis_tk1_k20_reset_chip(apalis_tk1_k20); + msleep(10); - ret = apalis_tk1_k20_reg_read(apalis_tk1_k20, APALIS_TK1_K20_REVREG, - &revision); + ret = apalis_tk1_k20_reg_read(apalis_tk1_k20, APALIS_TK1_K20_REVREG, + &revision); + } #endif /* CONFIG_APALIS_TK1_K20_EZP */ if (ret) { @@ -862,7 +884,7 @@ int apalis_tk1_k20_dev_init(struct device *dev) goto bad; } - if (revision != APALIS_TK1_K20_FW_VER) { + if ((revision != APALIS_TK1_K20_FW_VER) && (fw_ignore == 0)) { dev_err(apalis_tk1_k20->dev, "Unsupported firmware version %d.%d.\n", ((revision & 0xF0) >> 4), (revision & 0x0F)); @@ -870,6 +892,14 @@ int apalis_tk1_k20_dev_init(struct device *dev) goto bad; } + if (fw_ignore == 1) { + dev_err(apalis_tk1_k20->dev, "fw_ignore == 1. Detected " + "firmware %d.%d. Driver expected %d.%d\n", + ((revision & 0xF0) >> 4), (revision & 0x0F), + ((APALIS_TK1_K20_FW_VER & 0xF0) >> 4), + (APALIS_TK1_K20_FW_VER & 0x0F)); + } + for (i = 0; i < ARRAY_SIZE(apalis_tk1_k20->irqs); i++) { apalis_tk1_k20->irqs[i].reg_offset = i / APALIS_TK1_K20_IRQ_PER_REG; |