root/drivers/nvmem/lpc18xx_eeprom.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lpc18xx_eeprom_writel
  2. lpc18xx_eeprom_readl
  3. lpc18xx_eeprom_busywait_until_prog
  4. lpc18xx_eeprom_gather_write
  5. lpc18xx_eeprom_read
  6. lpc18xx_eeprom_probe
  7. lpc18xx_eeprom_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * NXP LPC18xx/LPC43xx EEPROM memory NVMEM driver
   4  *
   5  * Copyright (c) 2015 Ariel D'Alessandro <ariel@vanguardiasur.com>
   6  */
   7 
   8 #include <linux/clk.h>
   9 #include <linux/device.h>
  10 #include <linux/delay.h>
  11 #include <linux/err.h>
  12 #include <linux/io.h>
  13 #include <linux/module.h>
  14 #include <linux/mod_devicetable.h>
  15 #include <linux/nvmem-provider.h>
  16 #include <linux/platform_device.h>
  17 #include <linux/reset.h>
  18 
  19 /* Registers */
  20 #define LPC18XX_EEPROM_AUTOPROG                 0x00c
  21 #define LPC18XX_EEPROM_AUTOPROG_WORD            0x1
  22 
  23 #define LPC18XX_EEPROM_CLKDIV                   0x014
  24 
  25 #define LPC18XX_EEPROM_PWRDWN                   0x018
  26 #define LPC18XX_EEPROM_PWRDWN_NO                0x0
  27 #define LPC18XX_EEPROM_PWRDWN_YES               0x1
  28 
  29 #define LPC18XX_EEPROM_INTSTAT                  0xfe0
  30 #define LPC18XX_EEPROM_INTSTAT_END_OF_PROG      BIT(2)
  31 
  32 #define LPC18XX_EEPROM_INTSTATCLR               0xfe8
  33 #define LPC18XX_EEPROM_INTSTATCLR_PROG_CLR_ST   BIT(2)
  34 
  35 /* Fixed page size (bytes) */
  36 #define LPC18XX_EEPROM_PAGE_SIZE                0x80
  37 
  38 /* EEPROM device requires a ~1500 kHz clock (min 800 kHz, max 1600 kHz) */
  39 #define LPC18XX_EEPROM_CLOCK_HZ                 1500000
  40 
  41 /* EEPROM requires 3 ms of erase/program time between each writing */
  42 #define LPC18XX_EEPROM_PROGRAM_TIME             3
  43 
  44 struct lpc18xx_eeprom_dev {
  45         struct clk *clk;
  46         void __iomem *reg_base;
  47         void __iomem *mem_base;
  48         struct nvmem_device *nvmem;
  49         unsigned reg_bytes;
  50         unsigned val_bytes;
  51         int size;
  52 };
  53 
  54 static inline void lpc18xx_eeprom_writel(struct lpc18xx_eeprom_dev *eeprom,
  55                                          u32 reg, u32 val)
  56 {
  57         writel(val, eeprom->reg_base + reg);
  58 }
  59 
  60 static inline u32 lpc18xx_eeprom_readl(struct lpc18xx_eeprom_dev *eeprom,
  61                                        u32 reg)
  62 {
  63         return readl(eeprom->reg_base + reg);
  64 }
  65 
  66 static int lpc18xx_eeprom_busywait_until_prog(struct lpc18xx_eeprom_dev *eeprom)
  67 {
  68         unsigned long end;
  69         u32 val;
  70 
  71         /* Wait until EEPROM program operation has finished */
  72         end = jiffies + msecs_to_jiffies(LPC18XX_EEPROM_PROGRAM_TIME * 10);
  73 
  74         while (time_is_after_jiffies(end)) {
  75                 val = lpc18xx_eeprom_readl(eeprom, LPC18XX_EEPROM_INTSTAT);
  76 
  77                 if (val & LPC18XX_EEPROM_INTSTAT_END_OF_PROG) {
  78                         lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_INTSTATCLR,
  79                                         LPC18XX_EEPROM_INTSTATCLR_PROG_CLR_ST);
  80                         return 0;
  81                 }
  82 
  83                 usleep_range(LPC18XX_EEPROM_PROGRAM_TIME * USEC_PER_MSEC,
  84                              (LPC18XX_EEPROM_PROGRAM_TIME + 1) * USEC_PER_MSEC);
  85         }
  86 
  87         return -ETIMEDOUT;
  88 }
  89 
  90 static int lpc18xx_eeprom_gather_write(void *context, unsigned int reg,
  91                                        void *val, size_t bytes)
  92 {
  93         struct lpc18xx_eeprom_dev *eeprom = context;
  94         unsigned int offset = reg;
  95         int ret;
  96 
  97         /*
  98          * The last page contains the EEPROM initialization data and is not
  99          * writable.
 100          */
 101         if ((reg > eeprom->size - LPC18XX_EEPROM_PAGE_SIZE) ||
 102                         (reg + bytes > eeprom->size - LPC18XX_EEPROM_PAGE_SIZE))
 103                 return -EINVAL;
 104 
 105 
 106         lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN,
 107                               LPC18XX_EEPROM_PWRDWN_NO);
 108 
 109         /* Wait 100 us while the EEPROM wakes up */
 110         usleep_range(100, 200);
 111 
 112         while (bytes) {
 113                 writel(*(u32 *)val, eeprom->mem_base + offset);
 114                 ret = lpc18xx_eeprom_busywait_until_prog(eeprom);
 115                 if (ret < 0)
 116                         return ret;
 117 
 118                 bytes -= eeprom->val_bytes;
 119                 val += eeprom->val_bytes;
 120                 offset += eeprom->val_bytes;
 121         }
 122 
 123         lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN,
 124                               LPC18XX_EEPROM_PWRDWN_YES);
 125 
 126         return 0;
 127 }
 128 
 129 static int lpc18xx_eeprom_read(void *context, unsigned int offset,
 130                                void *val, size_t bytes)
 131 {
 132         struct lpc18xx_eeprom_dev *eeprom = context;
 133 
 134         lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN,
 135                               LPC18XX_EEPROM_PWRDWN_NO);
 136 
 137         /* Wait 100 us while the EEPROM wakes up */
 138         usleep_range(100, 200);
 139 
 140         while (bytes) {
 141                 *(u32 *)val = readl(eeprom->mem_base + offset);
 142                 bytes -= eeprom->val_bytes;
 143                 val += eeprom->val_bytes;
 144                 offset += eeprom->val_bytes;
 145         }
 146 
 147         lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN,
 148                               LPC18XX_EEPROM_PWRDWN_YES);
 149 
 150         return 0;
 151 }
 152 
 153 
 154 static struct nvmem_config lpc18xx_nvmem_config = {
 155         .name = "lpc18xx-eeprom",
 156         .stride = 4,
 157         .word_size = 4,
 158         .reg_read = lpc18xx_eeprom_read,
 159         .reg_write = lpc18xx_eeprom_gather_write,
 160 };
 161 
 162 static int lpc18xx_eeprom_probe(struct platform_device *pdev)
 163 {
 164         struct lpc18xx_eeprom_dev *eeprom;
 165         struct device *dev = &pdev->dev;
 166         struct reset_control *rst;
 167         unsigned long clk_rate;
 168         struct resource *res;
 169         int ret;
 170 
 171         eeprom = devm_kzalloc(dev, sizeof(*eeprom), GFP_KERNEL);
 172         if (!eeprom)
 173                 return -ENOMEM;
 174 
 175         res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg");
 176         eeprom->reg_base = devm_ioremap_resource(dev, res);
 177         if (IS_ERR(eeprom->reg_base))
 178                 return PTR_ERR(eeprom->reg_base);
 179 
 180         res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem");
 181         eeprom->mem_base = devm_ioremap_resource(dev, res);
 182         if (IS_ERR(eeprom->mem_base))
 183                 return PTR_ERR(eeprom->mem_base);
 184 
 185         eeprom->clk = devm_clk_get(&pdev->dev, "eeprom");
 186         if (IS_ERR(eeprom->clk)) {
 187                 dev_err(&pdev->dev, "failed to get eeprom clock\n");
 188                 return PTR_ERR(eeprom->clk);
 189         }
 190 
 191         ret = clk_prepare_enable(eeprom->clk);
 192         if (ret < 0) {
 193                 dev_err(dev, "failed to prepare/enable eeprom clk: %d\n", ret);
 194                 return ret;
 195         }
 196 
 197         rst = devm_reset_control_get_exclusive(dev, NULL);
 198         if (IS_ERR(rst)) {
 199                 dev_err(dev, "failed to get reset: %ld\n", PTR_ERR(rst));
 200                 ret = PTR_ERR(rst);
 201                 goto err_clk;
 202         }
 203 
 204         ret = reset_control_assert(rst);
 205         if (ret < 0) {
 206                 dev_err(dev, "failed to assert reset: %d\n", ret);
 207                 goto err_clk;
 208         }
 209 
 210         eeprom->val_bytes = 4;
 211         eeprom->reg_bytes = 4;
 212 
 213         /*
 214          * Clock rate is generated by dividing the system bus clock by the
 215          * division factor, contained in the divider register (minus 1 encoded).
 216          */
 217         clk_rate = clk_get_rate(eeprom->clk);
 218         clk_rate = DIV_ROUND_UP(clk_rate, LPC18XX_EEPROM_CLOCK_HZ) - 1;
 219         lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_CLKDIV, clk_rate);
 220 
 221         /*
 222          * Writing a single word to the page will start the erase/program cycle
 223          * automatically
 224          */
 225         lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_AUTOPROG,
 226                               LPC18XX_EEPROM_AUTOPROG_WORD);
 227 
 228         lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN,
 229                               LPC18XX_EEPROM_PWRDWN_YES);
 230 
 231         eeprom->size = resource_size(res);
 232         lpc18xx_nvmem_config.size = resource_size(res);
 233         lpc18xx_nvmem_config.dev = dev;
 234         lpc18xx_nvmem_config.priv = eeprom;
 235 
 236         eeprom->nvmem = devm_nvmem_register(dev, &lpc18xx_nvmem_config);
 237         if (IS_ERR(eeprom->nvmem)) {
 238                 ret = PTR_ERR(eeprom->nvmem);
 239                 goto err_clk;
 240         }
 241 
 242         platform_set_drvdata(pdev, eeprom);
 243 
 244         return 0;
 245 
 246 err_clk:
 247         clk_disable_unprepare(eeprom->clk);
 248 
 249         return ret;
 250 }
 251 
 252 static int lpc18xx_eeprom_remove(struct platform_device *pdev)
 253 {
 254         struct lpc18xx_eeprom_dev *eeprom = platform_get_drvdata(pdev);
 255 
 256         clk_disable_unprepare(eeprom->clk);
 257 
 258         return 0;
 259 }
 260 
 261 static const struct of_device_id lpc18xx_eeprom_of_match[] = {
 262         { .compatible = "nxp,lpc1857-eeprom" },
 263         { },
 264 };
 265 MODULE_DEVICE_TABLE(of, lpc18xx_eeprom_of_match);
 266 
 267 static struct platform_driver lpc18xx_eeprom_driver = {
 268         .probe = lpc18xx_eeprom_probe,
 269         .remove = lpc18xx_eeprom_remove,
 270         .driver = {
 271                 .name = "lpc18xx-eeprom",
 272                 .of_match_table = lpc18xx_eeprom_of_match,
 273         },
 274 };
 275 
 276 module_platform_driver(lpc18xx_eeprom_driver);
 277 
 278 MODULE_AUTHOR("Ariel D'Alessandro <ariel@vanguardiasur.com.ar>");
 279 MODULE_DESCRIPTION("NXP LPC18xx EEPROM memory Driver");
 280 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */