197fb5e8dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 24ab11996SSrinivas Kandagatla /* 34ab11996SSrinivas Kandagatla * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org> 44ab11996SSrinivas Kandagatla */ 54ab11996SSrinivas Kandagatla 693b4e49fSRavi Kumar Bokka #include <linux/clk.h> 74ab11996SSrinivas Kandagatla #include <linux/device.h> 893b4e49fSRavi Kumar Bokka #include <linux/io.h> 993b4e49fSRavi Kumar Bokka #include <linux/iopoll.h> 1093b4e49fSRavi Kumar Bokka #include <linux/kernel.h> 114ab11996SSrinivas Kandagatla #include <linux/module.h> 12ac316725SRandy Dunlap #include <linux/mod_devicetable.h> 134ab11996SSrinivas Kandagatla #include <linux/nvmem-provider.h> 144ab11996SSrinivas Kandagatla #include <linux/platform_device.h> 15044ee8f8SEvan Green #include <linux/property.h> 1693b4e49fSRavi Kumar Bokka #include <linux/regulator/consumer.h> 174ab11996SSrinivas Kandagatla 1893b4e49fSRavi Kumar Bokka /* Blow timer clock frequency in Mhz */ 1993b4e49fSRavi Kumar Bokka #define QFPROM_BLOW_TIMER_OFFSET 0x03c 2093b4e49fSRavi Kumar Bokka 2193b4e49fSRavi Kumar Bokka /* Amount of time required to hold charge to blow fuse in micro-seconds */ 2293b4e49fSRavi Kumar Bokka #define QFPROM_FUSE_BLOW_POLL_US 100 2393b4e49fSRavi Kumar Bokka #define QFPROM_FUSE_BLOW_TIMEOUT_US 1000 2493b4e49fSRavi Kumar Bokka 2593b4e49fSRavi Kumar Bokka #define QFPROM_BLOW_STATUS_OFFSET 0x048 2693b4e49fSRavi Kumar Bokka #define QFPROM_BLOW_STATUS_BUSY 0x1 2793b4e49fSRavi Kumar Bokka #define QFPROM_BLOW_STATUS_READY 0x0 2893b4e49fSRavi Kumar Bokka 2993b4e49fSRavi Kumar Bokka #define QFPROM_ACCEL_OFFSET 0x044 3093b4e49fSRavi Kumar Bokka 3193b4e49fSRavi Kumar Bokka #define QFPROM_VERSION_OFFSET 0x0 3293b4e49fSRavi Kumar Bokka #define QFPROM_MAJOR_VERSION_SHIFT 28 3393b4e49fSRavi Kumar Bokka #define QFPROM_MAJOR_VERSION_MASK GENMASK(31, QFPROM_MAJOR_VERSION_SHIFT) 3493b4e49fSRavi Kumar Bokka #define QFPROM_MINOR_VERSION_SHIFT 16 3593b4e49fSRavi Kumar Bokka #define QFPROM_MINOR_VERSION_MASK GENMASK(27, QFPROM_MINOR_VERSION_SHIFT) 3693b4e49fSRavi Kumar Bokka 3793b4e49fSRavi Kumar Bokka static bool read_raw_data; 3893b4e49fSRavi Kumar Bokka module_param(read_raw_data, bool, 0644); 3993b4e49fSRavi Kumar Bokka MODULE_PARM_DESC(read_raw_data, "Read raw instead of corrected data"); 4093b4e49fSRavi Kumar Bokka 4193b4e49fSRavi Kumar Bokka /** 4293b4e49fSRavi Kumar Bokka * struct qfprom_soc_data - config that varies from SoC to SoC. 4393b4e49fSRavi Kumar Bokka * 4493b4e49fSRavi Kumar Bokka * @accel_value: Should contain qfprom accel value. 4593b4e49fSRavi Kumar Bokka * @qfprom_blow_timer_value: The timer value of qfprom when doing efuse blow. 4693b4e49fSRavi Kumar Bokka * @qfprom_blow_set_freq: The frequency required to set when we start the 4793b4e49fSRavi Kumar Bokka * fuse blowing. 485a1bea2aSRajendra Nayak * @qfprom_blow_uV: LDO voltage to be set when doing efuse blow 4993b4e49fSRavi Kumar Bokka */ 5093b4e49fSRavi Kumar Bokka struct qfprom_soc_data { 5193b4e49fSRavi Kumar Bokka u32 accel_value; 5293b4e49fSRavi Kumar Bokka u32 qfprom_blow_timer_value; 5393b4e49fSRavi Kumar Bokka u32 qfprom_blow_set_freq; 545a1bea2aSRajendra Nayak int qfprom_blow_uV; 55ec3672b8SMasahiro Yamada }; 56ec3672b8SMasahiro Yamada 5793b4e49fSRavi Kumar Bokka /** 5893b4e49fSRavi Kumar Bokka * struct qfprom_priv - structure holding qfprom attributes 5993b4e49fSRavi Kumar Bokka * 6093b4e49fSRavi Kumar Bokka * @qfpraw: iomapped memory space for qfprom-efuse raw address space. 6193b4e49fSRavi Kumar Bokka * @qfpconf: iomapped memory space for qfprom-efuse configuration address 6293b4e49fSRavi Kumar Bokka * space. 6393b4e49fSRavi Kumar Bokka * @qfpcorrected: iomapped memory space for qfprom corrected address space. 6493b4e49fSRavi Kumar Bokka * @qfpsecurity: iomapped memory space for qfprom security control space. 6593b4e49fSRavi Kumar Bokka * @dev: qfprom device structure. 6693b4e49fSRavi Kumar Bokka * @secclk: Clock supply. 6793b4e49fSRavi Kumar Bokka * @vcc: Regulator supply. 6893b4e49fSRavi Kumar Bokka * @soc_data: Data that for things that varies from SoC to SoC. 6993b4e49fSRavi Kumar Bokka */ 7093b4e49fSRavi Kumar Bokka struct qfprom_priv { 7193b4e49fSRavi Kumar Bokka void __iomem *qfpraw; 7293b4e49fSRavi Kumar Bokka void __iomem *qfpconf; 7393b4e49fSRavi Kumar Bokka void __iomem *qfpcorrected; 7493b4e49fSRavi Kumar Bokka void __iomem *qfpsecurity; 7593b4e49fSRavi Kumar Bokka struct device *dev; 7693b4e49fSRavi Kumar Bokka struct clk *secclk; 7793b4e49fSRavi Kumar Bokka struct regulator *vcc; 7893b4e49fSRavi Kumar Bokka const struct qfprom_soc_data *soc_data; 7993b4e49fSRavi Kumar Bokka }; 8093b4e49fSRavi Kumar Bokka 8193b4e49fSRavi Kumar Bokka /** 8293b4e49fSRavi Kumar Bokka * struct qfprom_touched_values - saved values to restore after blowing 8393b4e49fSRavi Kumar Bokka * 8493b4e49fSRavi Kumar Bokka * @clk_rate: The rate the clock was at before blowing. 8593b4e49fSRavi Kumar Bokka * @accel_val: The value of the accel reg before blowing. 8693b4e49fSRavi Kumar Bokka * @timer_val: The value of the timer before blowing. 8793b4e49fSRavi Kumar Bokka */ 8893b4e49fSRavi Kumar Bokka struct qfprom_touched_values { 8993b4e49fSRavi Kumar Bokka unsigned long clk_rate; 9093b4e49fSRavi Kumar Bokka u32 accel_val; 9193b4e49fSRavi Kumar Bokka u32 timer_val; 9293b4e49fSRavi Kumar Bokka }; 9393b4e49fSRavi Kumar Bokka 9493b4e49fSRavi Kumar Bokka /** 95044ee8f8SEvan Green * struct qfprom_soc_compatible_data - Data matched against the SoC 96044ee8f8SEvan Green * compatible string. 97044ee8f8SEvan Green * 98044ee8f8SEvan Green * @keepout: Array of keepout regions for this SoC. 99044ee8f8SEvan Green * @nkeepout: Number of elements in the keepout array. 100044ee8f8SEvan Green */ 101044ee8f8SEvan Green struct qfprom_soc_compatible_data { 102044ee8f8SEvan Green const struct nvmem_keepout *keepout; 103044ee8f8SEvan Green unsigned int nkeepout; 104044ee8f8SEvan Green }; 105044ee8f8SEvan Green 106044ee8f8SEvan Green static const struct nvmem_keepout sc7180_qfprom_keepout[] = { 107044ee8f8SEvan Green {.start = 0x128, .end = 0x148}, 108044ee8f8SEvan Green {.start = 0x220, .end = 0x228} 109044ee8f8SEvan Green }; 110044ee8f8SEvan Green 111044ee8f8SEvan Green static const struct qfprom_soc_compatible_data sc7180_qfprom = { 112044ee8f8SEvan Green .keepout = sc7180_qfprom_keepout, 113044ee8f8SEvan Green .nkeepout = ARRAY_SIZE(sc7180_qfprom_keepout) 114044ee8f8SEvan Green }; 115044ee8f8SEvan Green 1165a1bea2aSRajendra Nayak static const struct nvmem_keepout sc7280_qfprom_keepout[] = { 1175a1bea2aSRajendra Nayak {.start = 0x128, .end = 0x148}, 1185a1bea2aSRajendra Nayak {.start = 0x238, .end = 0x248} 1195a1bea2aSRajendra Nayak }; 1205a1bea2aSRajendra Nayak 1215a1bea2aSRajendra Nayak static const struct qfprom_soc_compatible_data sc7280_qfprom = { 1225a1bea2aSRajendra Nayak .keepout = sc7280_qfprom_keepout, 1235a1bea2aSRajendra Nayak .nkeepout = ARRAY_SIZE(sc7280_qfprom_keepout) 1245a1bea2aSRajendra Nayak }; 125c813bb37SRajendra Nayak 126044ee8f8SEvan Green /** 12793b4e49fSRavi Kumar Bokka * qfprom_disable_fuse_blowing() - Undo enabling of fuse blowing. 12893b4e49fSRavi Kumar Bokka * @priv: Our driver data. 12993b4e49fSRavi Kumar Bokka * @old: The data that was stashed from before fuse blowing. 13093b4e49fSRavi Kumar Bokka * 13193b4e49fSRavi Kumar Bokka * Resets the value of the blow timer, accel register and the clock 13293b4e49fSRavi Kumar Bokka * and voltage settings. 13393b4e49fSRavi Kumar Bokka * 13493b4e49fSRavi Kumar Bokka * Prints messages if there are errors but doesn't return an error code 13593b4e49fSRavi Kumar Bokka * since there's not much we can do upon failure. 13693b4e49fSRavi Kumar Bokka */ 13793b4e49fSRavi Kumar Bokka static void qfprom_disable_fuse_blowing(const struct qfprom_priv *priv, 13893b4e49fSRavi Kumar Bokka const struct qfprom_touched_values *old) 13993b4e49fSRavi Kumar Bokka { 14093b4e49fSRavi Kumar Bokka int ret; 14193b4e49fSRavi Kumar Bokka 1429ec4f4b0SRavi Kumar Bokka /* 1439ec4f4b0SRavi Kumar Bokka * This may be a shared rail and may be able to run at a lower rate 1449ec4f4b0SRavi Kumar Bokka * when we're not blowing fuses. At the moment, the regulator framework 1459ec4f4b0SRavi Kumar Bokka * applies voltage constraints even on disabled rails, so remove our 1469ec4f4b0SRavi Kumar Bokka * constraints and allow the rail to be adjusted by other users. 1479ec4f4b0SRavi Kumar Bokka */ 1489ec4f4b0SRavi Kumar Bokka ret = regulator_set_voltage(priv->vcc, 0, INT_MAX); 1499ec4f4b0SRavi Kumar Bokka if (ret) 1509ec4f4b0SRavi Kumar Bokka dev_warn(priv->dev, "Failed to set 0 voltage (ignoring)\n"); 1519ec4f4b0SRavi Kumar Bokka 15293b4e49fSRavi Kumar Bokka ret = regulator_disable(priv->vcc); 15393b4e49fSRavi Kumar Bokka if (ret) 15493b4e49fSRavi Kumar Bokka dev_warn(priv->dev, "Failed to disable regulator (ignoring)\n"); 15593b4e49fSRavi Kumar Bokka 15693b4e49fSRavi Kumar Bokka ret = clk_set_rate(priv->secclk, old->clk_rate); 15793b4e49fSRavi Kumar Bokka if (ret) 15893b4e49fSRavi Kumar Bokka dev_warn(priv->dev, 15993b4e49fSRavi Kumar Bokka "Failed to set clock rate for disable (ignoring)\n"); 16093b4e49fSRavi Kumar Bokka 16193b4e49fSRavi Kumar Bokka clk_disable_unprepare(priv->secclk); 16293b4e49fSRavi Kumar Bokka 16393b4e49fSRavi Kumar Bokka writel(old->timer_val, priv->qfpconf + QFPROM_BLOW_TIMER_OFFSET); 16493b4e49fSRavi Kumar Bokka writel(old->accel_val, priv->qfpconf + QFPROM_ACCEL_OFFSET); 16593b4e49fSRavi Kumar Bokka } 16693b4e49fSRavi Kumar Bokka 16793b4e49fSRavi Kumar Bokka /** 16893b4e49fSRavi Kumar Bokka * qfprom_enable_fuse_blowing() - Enable fuse blowing. 16993b4e49fSRavi Kumar Bokka * @priv: Our driver data. 17093b4e49fSRavi Kumar Bokka * @old: We'll stash stuff here to use when disabling. 17193b4e49fSRavi Kumar Bokka * 17293b4e49fSRavi Kumar Bokka * Sets the value of the blow timer, accel register and the clock 17393b4e49fSRavi Kumar Bokka * and voltage settings. 17493b4e49fSRavi Kumar Bokka * 17593b4e49fSRavi Kumar Bokka * Prints messages if there are errors so caller doesn't need to. 17693b4e49fSRavi Kumar Bokka * 17793b4e49fSRavi Kumar Bokka * Return: 0 or -err. 17893b4e49fSRavi Kumar Bokka */ 17993b4e49fSRavi Kumar Bokka static int qfprom_enable_fuse_blowing(const struct qfprom_priv *priv, 18093b4e49fSRavi Kumar Bokka struct qfprom_touched_values *old) 18193b4e49fSRavi Kumar Bokka { 18293b4e49fSRavi Kumar Bokka int ret; 1835a1bea2aSRajendra Nayak int qfprom_blow_uV = priv->soc_data->qfprom_blow_uV; 18493b4e49fSRavi Kumar Bokka 18593b4e49fSRavi Kumar Bokka ret = clk_prepare_enable(priv->secclk); 18693b4e49fSRavi Kumar Bokka if (ret) { 18793b4e49fSRavi Kumar Bokka dev_err(priv->dev, "Failed to enable clock\n"); 18893b4e49fSRavi Kumar Bokka return ret; 18993b4e49fSRavi Kumar Bokka } 19093b4e49fSRavi Kumar Bokka 19193b4e49fSRavi Kumar Bokka old->clk_rate = clk_get_rate(priv->secclk); 19293b4e49fSRavi Kumar Bokka ret = clk_set_rate(priv->secclk, priv->soc_data->qfprom_blow_set_freq); 19393b4e49fSRavi Kumar Bokka if (ret) { 19493b4e49fSRavi Kumar Bokka dev_err(priv->dev, "Failed to set clock rate for enable\n"); 19593b4e49fSRavi Kumar Bokka goto err_clk_prepared; 19693b4e49fSRavi Kumar Bokka } 19793b4e49fSRavi Kumar Bokka 1989ec4f4b0SRavi Kumar Bokka /* 199*989f77e3SDouglas Anderson * Hardware requires a minimum voltage for fuse blowing. 200*989f77e3SDouglas Anderson * This may be a shared rail so don't specify a maximum. 201*989f77e3SDouglas Anderson * Regulator constraints will cap to the actual maximum. 2029ec4f4b0SRavi Kumar Bokka */ 2035a1bea2aSRajendra Nayak ret = regulator_set_voltage(priv->vcc, qfprom_blow_uV, INT_MAX); 2049ec4f4b0SRavi Kumar Bokka if (ret) { 2055a1bea2aSRajendra Nayak dev_err(priv->dev, "Failed to set %duV\n", qfprom_blow_uV); 2069ec4f4b0SRavi Kumar Bokka goto err_clk_rate_set; 2079ec4f4b0SRavi Kumar Bokka } 2089ec4f4b0SRavi Kumar Bokka 20993b4e49fSRavi Kumar Bokka ret = regulator_enable(priv->vcc); 21093b4e49fSRavi Kumar Bokka if (ret) { 21193b4e49fSRavi Kumar Bokka dev_err(priv->dev, "Failed to enable regulator\n"); 21293b4e49fSRavi Kumar Bokka goto err_clk_rate_set; 21393b4e49fSRavi Kumar Bokka } 21493b4e49fSRavi Kumar Bokka 21593b4e49fSRavi Kumar Bokka old->timer_val = readl(priv->qfpconf + QFPROM_BLOW_TIMER_OFFSET); 21693b4e49fSRavi Kumar Bokka old->accel_val = readl(priv->qfpconf + QFPROM_ACCEL_OFFSET); 21793b4e49fSRavi Kumar Bokka writel(priv->soc_data->qfprom_blow_timer_value, 21893b4e49fSRavi Kumar Bokka priv->qfpconf + QFPROM_BLOW_TIMER_OFFSET); 21993b4e49fSRavi Kumar Bokka writel(priv->soc_data->accel_value, 22093b4e49fSRavi Kumar Bokka priv->qfpconf + QFPROM_ACCEL_OFFSET); 22193b4e49fSRavi Kumar Bokka 22293b4e49fSRavi Kumar Bokka return 0; 22393b4e49fSRavi Kumar Bokka 22493b4e49fSRavi Kumar Bokka err_clk_rate_set: 22593b4e49fSRavi Kumar Bokka clk_set_rate(priv->secclk, old->clk_rate); 22693b4e49fSRavi Kumar Bokka err_clk_prepared: 22793b4e49fSRavi Kumar Bokka clk_disable_unprepare(priv->secclk); 22893b4e49fSRavi Kumar Bokka return ret; 22993b4e49fSRavi Kumar Bokka } 23093b4e49fSRavi Kumar Bokka 23193b4e49fSRavi Kumar Bokka /** 23293b4e49fSRavi Kumar Bokka * qfprom_efuse_reg_write() - Write to fuses. 23393b4e49fSRavi Kumar Bokka * @context: Our driver data. 23493b4e49fSRavi Kumar Bokka * @reg: The offset to write at. 23593b4e49fSRavi Kumar Bokka * @_val: Pointer to data to write. 23693b4e49fSRavi Kumar Bokka * @bytes: The number of bytes to write. 23793b4e49fSRavi Kumar Bokka * 23893b4e49fSRavi Kumar Bokka * Writes to fuses. WARNING: THIS IS PERMANENT. 23993b4e49fSRavi Kumar Bokka * 24093b4e49fSRavi Kumar Bokka * Return: 0 or -err. 24193b4e49fSRavi Kumar Bokka */ 24293b4e49fSRavi Kumar Bokka static int qfprom_reg_write(void *context, unsigned int reg, void *_val, 24393b4e49fSRavi Kumar Bokka size_t bytes) 24493b4e49fSRavi Kumar Bokka { 24593b4e49fSRavi Kumar Bokka struct qfprom_priv *priv = context; 24693b4e49fSRavi Kumar Bokka struct qfprom_touched_values old; 24793b4e49fSRavi Kumar Bokka int words = bytes / 4; 24893b4e49fSRavi Kumar Bokka u32 *value = _val; 24993b4e49fSRavi Kumar Bokka u32 blow_status; 25093b4e49fSRavi Kumar Bokka int ret; 25193b4e49fSRavi Kumar Bokka int i; 25293b4e49fSRavi Kumar Bokka 25393b4e49fSRavi Kumar Bokka dev_dbg(priv->dev, 25493b4e49fSRavi Kumar Bokka "Writing to raw qfprom region : %#010x of size: %zu\n", 25593b4e49fSRavi Kumar Bokka reg, bytes); 25693b4e49fSRavi Kumar Bokka 25793b4e49fSRavi Kumar Bokka /* 25893b4e49fSRavi Kumar Bokka * The hardware only allows us to write word at a time, but we can 25993b4e49fSRavi Kumar Bokka * read byte at a time. Until the nvmem framework allows a separate 26093b4e49fSRavi Kumar Bokka * word_size and stride for reading vs. writing, we'll enforce here. 26193b4e49fSRavi Kumar Bokka */ 26293b4e49fSRavi Kumar Bokka if (bytes % 4) { 26393b4e49fSRavi Kumar Bokka dev_err(priv->dev, 26493b4e49fSRavi Kumar Bokka "%zu is not an integral number of words\n", bytes); 26593b4e49fSRavi Kumar Bokka return -EINVAL; 26693b4e49fSRavi Kumar Bokka } 26793b4e49fSRavi Kumar Bokka if (reg % 4) { 26893b4e49fSRavi Kumar Bokka dev_err(priv->dev, 26993b4e49fSRavi Kumar Bokka "Invalid offset: %#x. Must be word aligned\n", reg); 27093b4e49fSRavi Kumar Bokka return -EINVAL; 27193b4e49fSRavi Kumar Bokka } 27293b4e49fSRavi Kumar Bokka 27393b4e49fSRavi Kumar Bokka ret = qfprom_enable_fuse_blowing(priv, &old); 27493b4e49fSRavi Kumar Bokka if (ret) 27593b4e49fSRavi Kumar Bokka return ret; 27693b4e49fSRavi Kumar Bokka 27793b4e49fSRavi Kumar Bokka ret = readl_relaxed_poll_timeout( 27893b4e49fSRavi Kumar Bokka priv->qfpconf + QFPROM_BLOW_STATUS_OFFSET, 27993b4e49fSRavi Kumar Bokka blow_status, blow_status == QFPROM_BLOW_STATUS_READY, 28093b4e49fSRavi Kumar Bokka QFPROM_FUSE_BLOW_POLL_US, QFPROM_FUSE_BLOW_TIMEOUT_US); 28193b4e49fSRavi Kumar Bokka 28293b4e49fSRavi Kumar Bokka if (ret) { 28393b4e49fSRavi Kumar Bokka dev_err(priv->dev, 28493b4e49fSRavi Kumar Bokka "Timeout waiting for initial ready; aborting.\n"); 28593b4e49fSRavi Kumar Bokka goto exit_enabled_fuse_blowing; 28693b4e49fSRavi Kumar Bokka } 28793b4e49fSRavi Kumar Bokka 28893b4e49fSRavi Kumar Bokka for (i = 0; i < words; i++) 28993b4e49fSRavi Kumar Bokka writel(value[i], priv->qfpraw + reg + (i * 4)); 29093b4e49fSRavi Kumar Bokka 29193b4e49fSRavi Kumar Bokka ret = readl_relaxed_poll_timeout( 29293b4e49fSRavi Kumar Bokka priv->qfpconf + QFPROM_BLOW_STATUS_OFFSET, 29393b4e49fSRavi Kumar Bokka blow_status, blow_status == QFPROM_BLOW_STATUS_READY, 29493b4e49fSRavi Kumar Bokka QFPROM_FUSE_BLOW_POLL_US, QFPROM_FUSE_BLOW_TIMEOUT_US); 29593b4e49fSRavi Kumar Bokka 29693b4e49fSRavi Kumar Bokka /* Give an error, but not much we can do in this case */ 29793b4e49fSRavi Kumar Bokka if (ret) 29893b4e49fSRavi Kumar Bokka dev_err(priv->dev, "Timeout waiting for finish.\n"); 29993b4e49fSRavi Kumar Bokka 30093b4e49fSRavi Kumar Bokka exit_enabled_fuse_blowing: 30193b4e49fSRavi Kumar Bokka qfprom_disable_fuse_blowing(priv, &old); 30293b4e49fSRavi Kumar Bokka 30393b4e49fSRavi Kumar Bokka return ret; 30493b4e49fSRavi Kumar Bokka } 30593b4e49fSRavi Kumar Bokka 306382c62f7SSrinivas Kandagatla static int qfprom_reg_read(void *context, 307382c62f7SSrinivas Kandagatla unsigned int reg, void *_val, size_t bytes) 308382c62f7SSrinivas Kandagatla { 309ec3672b8SMasahiro Yamada struct qfprom_priv *priv = context; 31001d0d2c4SVivek Gautam u8 *val = _val; 31101d0d2c4SVivek Gautam int i = 0, words = bytes; 31293b4e49fSRavi Kumar Bokka void __iomem *base = priv->qfpcorrected; 31393b4e49fSRavi Kumar Bokka 31493b4e49fSRavi Kumar Bokka if (read_raw_data && priv->qfpraw) 31593b4e49fSRavi Kumar Bokka base = priv->qfpraw; 3164ab11996SSrinivas Kandagatla 317382c62f7SSrinivas Kandagatla while (words--) 31893b4e49fSRavi Kumar Bokka *val++ = readb(base + reg + i++); 319382c62f7SSrinivas Kandagatla 320382c62f7SSrinivas Kandagatla return 0; 321382c62f7SSrinivas Kandagatla } 322382c62f7SSrinivas Kandagatla 32393b4e49fSRavi Kumar Bokka static const struct qfprom_soc_data qfprom_7_8_data = { 32493b4e49fSRavi Kumar Bokka .accel_value = 0xD10, 32593b4e49fSRavi Kumar Bokka .qfprom_blow_timer_value = 25, 32693b4e49fSRavi Kumar Bokka .qfprom_blow_set_freq = 4800000, 3275a1bea2aSRajendra Nayak .qfprom_blow_uV = 1800000, 3285a1bea2aSRajendra Nayak }; 3295a1bea2aSRajendra Nayak 3305a1bea2aSRajendra Nayak static const struct qfprom_soc_data qfprom_7_15_data = { 3315a1bea2aSRajendra Nayak .accel_value = 0xD08, 3325a1bea2aSRajendra Nayak .qfprom_blow_timer_value = 24, 3335a1bea2aSRajendra Nayak .qfprom_blow_set_freq = 4800000, 3345a1bea2aSRajendra Nayak .qfprom_blow_uV = 1900000, 33593b4e49fSRavi Kumar Bokka }; 33693b4e49fSRavi Kumar Bokka 33793b4e49fSRavi Kumar Bokka static int qfprom_probe(struct platform_device *pdev) 33893b4e49fSRavi Kumar Bokka { 33993b4e49fSRavi Kumar Bokka struct nvmem_config econfig = { 340382c62f7SSrinivas Kandagatla .name = "qfprom", 34101d0d2c4SVivek Gautam .stride = 1, 342382c62f7SSrinivas Kandagatla .word_size = 1, 3433f07c658SSrinivas Kandagatla .id = NVMEM_DEVID_AUTO, 344382c62f7SSrinivas Kandagatla .reg_read = qfprom_reg_read, 345382c62f7SSrinivas Kandagatla }; 3464ab11996SSrinivas Kandagatla struct device *dev = &pdev->dev; 3474ab11996SSrinivas Kandagatla struct resource *res; 3484ab11996SSrinivas Kandagatla struct nvmem_device *nvmem; 349044ee8f8SEvan Green const struct qfprom_soc_compatible_data *soc_data; 350ec3672b8SMasahiro Yamada struct qfprom_priv *priv; 35193b4e49fSRavi Kumar Bokka int ret; 352ec3672b8SMasahiro Yamada 353ec3672b8SMasahiro Yamada priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 354ec3672b8SMasahiro Yamada if (!priv) 355ec3672b8SMasahiro Yamada return -ENOMEM; 3564ab11996SSrinivas Kandagatla 35793b4e49fSRavi Kumar Bokka /* The corrected section is always provided */ 3584ab11996SSrinivas Kandagatla res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 35993b4e49fSRavi Kumar Bokka priv->qfpcorrected = devm_ioremap_resource(dev, res); 36093b4e49fSRavi Kumar Bokka if (IS_ERR(priv->qfpcorrected)) 36193b4e49fSRavi Kumar Bokka return PTR_ERR(priv->qfpcorrected); 3624ab11996SSrinivas Kandagatla 363382c62f7SSrinivas Kandagatla econfig.size = resource_size(res); 3644ab11996SSrinivas Kandagatla econfig.dev = dev; 365ec3672b8SMasahiro Yamada econfig.priv = priv; 366382c62f7SSrinivas Kandagatla 36793b4e49fSRavi Kumar Bokka priv->dev = dev; 368044ee8f8SEvan Green soc_data = device_get_match_data(dev); 369044ee8f8SEvan Green if (soc_data) { 370044ee8f8SEvan Green econfig.keepout = soc_data->keepout; 371044ee8f8SEvan Green econfig.nkeepout = soc_data->nkeepout; 372044ee8f8SEvan Green } 37393b4e49fSRavi Kumar Bokka 37493b4e49fSRavi Kumar Bokka /* 37593b4e49fSRavi Kumar Bokka * If more than one region is provided then the OS has the ability 37693b4e49fSRavi Kumar Bokka * to write. 37793b4e49fSRavi Kumar Bokka */ 37893b4e49fSRavi Kumar Bokka res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 37993b4e49fSRavi Kumar Bokka if (res) { 38093b4e49fSRavi Kumar Bokka u32 version; 38193b4e49fSRavi Kumar Bokka int major_version, minor_version; 38293b4e49fSRavi Kumar Bokka 38393b4e49fSRavi Kumar Bokka priv->qfpraw = devm_ioremap_resource(dev, res); 38493b4e49fSRavi Kumar Bokka if (IS_ERR(priv->qfpraw)) 38593b4e49fSRavi Kumar Bokka return PTR_ERR(priv->qfpraw); 38693b4e49fSRavi Kumar Bokka res = platform_get_resource(pdev, IORESOURCE_MEM, 2); 38793b4e49fSRavi Kumar Bokka priv->qfpconf = devm_ioremap_resource(dev, res); 38893b4e49fSRavi Kumar Bokka if (IS_ERR(priv->qfpconf)) 38993b4e49fSRavi Kumar Bokka return PTR_ERR(priv->qfpconf); 39093b4e49fSRavi Kumar Bokka res = platform_get_resource(pdev, IORESOURCE_MEM, 3); 39193b4e49fSRavi Kumar Bokka priv->qfpsecurity = devm_ioremap_resource(dev, res); 39293b4e49fSRavi Kumar Bokka if (IS_ERR(priv->qfpsecurity)) 39393b4e49fSRavi Kumar Bokka return PTR_ERR(priv->qfpsecurity); 39493b4e49fSRavi Kumar Bokka 39593b4e49fSRavi Kumar Bokka version = readl(priv->qfpsecurity + QFPROM_VERSION_OFFSET); 39693b4e49fSRavi Kumar Bokka major_version = (version & QFPROM_MAJOR_VERSION_MASK) >> 39793b4e49fSRavi Kumar Bokka QFPROM_MAJOR_VERSION_SHIFT; 39893b4e49fSRavi Kumar Bokka minor_version = (version & QFPROM_MINOR_VERSION_MASK) >> 39993b4e49fSRavi Kumar Bokka QFPROM_MINOR_VERSION_SHIFT; 40093b4e49fSRavi Kumar Bokka 40193b4e49fSRavi Kumar Bokka if (major_version == 7 && minor_version == 8) 40293b4e49fSRavi Kumar Bokka priv->soc_data = &qfprom_7_8_data; 403c813bb37SRajendra Nayak else if (major_version == 7 && minor_version == 15) 4045a1bea2aSRajendra Nayak priv->soc_data = &qfprom_7_15_data; 40593b4e49fSRavi Kumar Bokka 40693b4e49fSRavi Kumar Bokka priv->vcc = devm_regulator_get(&pdev->dev, "vcc"); 40793b4e49fSRavi Kumar Bokka if (IS_ERR(priv->vcc)) 40893b4e49fSRavi Kumar Bokka return PTR_ERR(priv->vcc); 40993b4e49fSRavi Kumar Bokka 41093b4e49fSRavi Kumar Bokka priv->secclk = devm_clk_get(dev, "core"); 41193b4e49fSRavi Kumar Bokka if (IS_ERR(priv->secclk)) { 41293b4e49fSRavi Kumar Bokka ret = PTR_ERR(priv->secclk); 41393b4e49fSRavi Kumar Bokka if (ret != -EPROBE_DEFER) 41493b4e49fSRavi Kumar Bokka dev_err(dev, "Error getting clock: %d\n", ret); 41593b4e49fSRavi Kumar Bokka return ret; 41693b4e49fSRavi Kumar Bokka } 41793b4e49fSRavi Kumar Bokka 41893b4e49fSRavi Kumar Bokka /* Only enable writing if we have SoC data. */ 41993b4e49fSRavi Kumar Bokka if (priv->soc_data) 42093b4e49fSRavi Kumar Bokka econfig.reg_write = qfprom_reg_write; 42193b4e49fSRavi Kumar Bokka } 42293b4e49fSRavi Kumar Bokka 423e5692efeSAndrey Smirnov nvmem = devm_nvmem_register(dev, &econfig); 4244ab11996SSrinivas Kandagatla 425e5692efeSAndrey Smirnov return PTR_ERR_OR_ZERO(nvmem); 4264ab11996SSrinivas Kandagatla } 4274ab11996SSrinivas Kandagatla 4284ab11996SSrinivas Kandagatla static const struct of_device_id qfprom_of_match[] = { 4294ab11996SSrinivas Kandagatla { .compatible = "qcom,qfprom",}, 430044ee8f8SEvan Green { .compatible = "qcom,sc7180-qfprom", .data = &sc7180_qfprom}, 4315a1bea2aSRajendra Nayak { .compatible = "qcom,sc7280-qfprom", .data = &sc7280_qfprom}, 4324ab11996SSrinivas Kandagatla {/* sentinel */}, 4334ab11996SSrinivas Kandagatla }; 4344ab11996SSrinivas Kandagatla MODULE_DEVICE_TABLE(of, qfprom_of_match); 4354ab11996SSrinivas Kandagatla 4364ab11996SSrinivas Kandagatla static struct platform_driver qfprom_driver = { 4374ab11996SSrinivas Kandagatla .probe = qfprom_probe, 4384ab11996SSrinivas Kandagatla .driver = { 4394ab11996SSrinivas Kandagatla .name = "qcom,qfprom", 4404ab11996SSrinivas Kandagatla .of_match_table = qfprom_of_match, 4414ab11996SSrinivas Kandagatla }, 4424ab11996SSrinivas Kandagatla }; 4434ab11996SSrinivas Kandagatla module_platform_driver(qfprom_driver); 4444ab11996SSrinivas Kandagatla MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org>"); 4454ab11996SSrinivas Kandagatla MODULE_DESCRIPTION("Qualcomm QFPROM driver"); 4464ab11996SSrinivas Kandagatla MODULE_LICENSE("GPL v2"); 447