1 /* 2 * Rockchip eFuse Driver 3 * 4 * Copyright (c) 2015 Rockchip Electronics Co. Ltd. 5 * Author: Caesar Wang <wxt@rock-chips.com> 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of version 2 of the GNU General Public License as 9 * published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14 * more details. 15 */ 16 17 #include <linux/platform_device.h> 18 #include <linux/nvmem-provider.h> 19 #include <linux/slab.h> 20 #include <linux/regmap.h> 21 #include <linux/device.h> 22 #include <linux/io.h> 23 #include <linux/module.h> 24 #include <linux/delay.h> 25 #include <linux/of.h> 26 #include <linux/clk.h> 27 28 #define EFUSE_A_SHIFT 6 29 #define EFUSE_A_MASK 0x3ff 30 #define EFUSE_PGENB BIT(3) 31 #define EFUSE_LOAD BIT(2) 32 #define EFUSE_STROBE BIT(1) 33 #define EFUSE_CSB BIT(0) 34 35 #define REG_EFUSE_CTRL 0x0000 36 #define REG_EFUSE_DOUT 0x0004 37 38 struct rockchip_efuse_context { 39 struct device *dev; 40 void __iomem *base; 41 struct clk *efuse_clk; 42 }; 43 44 static int rockchip_efuse_write(void *context, const void *data, size_t count) 45 { 46 /* Nothing TBD, Read-Only */ 47 return 0; 48 } 49 50 static int rockchip_efuse_read(void *context, 51 const void *reg, size_t reg_size, 52 void *val, size_t val_size) 53 { 54 unsigned int offset = *(u32 *)reg; 55 struct rockchip_efuse_context *_context = context; 56 void __iomem *base = _context->base; 57 struct clk *clk = _context->efuse_clk; 58 u8 *buf = val; 59 int ret; 60 61 ret = clk_prepare_enable(clk); 62 if (ret < 0) { 63 dev_err(_context->dev, "failed to prepare/enable efuse clk\n"); 64 return ret; 65 } 66 67 writel(EFUSE_LOAD | EFUSE_PGENB, base + REG_EFUSE_CTRL); 68 udelay(1); 69 while (val_size) { 70 writel(readl(base + REG_EFUSE_CTRL) & 71 (~(EFUSE_A_MASK << EFUSE_A_SHIFT)), 72 base + REG_EFUSE_CTRL); 73 writel(readl(base + REG_EFUSE_CTRL) | 74 ((offset & EFUSE_A_MASK) << EFUSE_A_SHIFT), 75 base + REG_EFUSE_CTRL); 76 udelay(1); 77 writel(readl(base + REG_EFUSE_CTRL) | 78 EFUSE_STROBE, base + REG_EFUSE_CTRL); 79 udelay(1); 80 *buf++ = readb(base + REG_EFUSE_DOUT); 81 writel(readl(base + REG_EFUSE_CTRL) & 82 (~EFUSE_STROBE), base + REG_EFUSE_CTRL); 83 udelay(1); 84 85 val_size -= 1; 86 offset += 1; 87 } 88 89 /* Switch to standby mode */ 90 writel(EFUSE_PGENB | EFUSE_CSB, base + REG_EFUSE_CTRL); 91 92 clk_disable_unprepare(clk); 93 94 return 0; 95 } 96 97 static struct regmap_bus rockchip_efuse_bus = { 98 .read = rockchip_efuse_read, 99 .write = rockchip_efuse_write, 100 .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, 101 .val_format_endian_default = REGMAP_ENDIAN_NATIVE, 102 }; 103 104 static struct regmap_config rockchip_efuse_regmap_config = { 105 .reg_bits = 32, 106 .reg_stride = 1, 107 .val_bits = 8, 108 }; 109 110 static struct nvmem_config econfig = { 111 .name = "rockchip-efuse", 112 .owner = THIS_MODULE, 113 .read_only = true, 114 }; 115 116 static const struct of_device_id rockchip_efuse_match[] = { 117 { .compatible = "rockchip,rockchip-efuse",}, 118 { /* sentinel */}, 119 }; 120 MODULE_DEVICE_TABLE(of, rockchip_efuse_match); 121 122 static int rockchip_efuse_probe(struct platform_device *pdev) 123 { 124 struct device *dev = &pdev->dev; 125 struct resource *res; 126 struct nvmem_device *nvmem; 127 struct regmap *regmap; 128 void __iomem *base; 129 struct clk *clk; 130 struct rockchip_efuse_context *context; 131 132 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 133 base = devm_ioremap_resource(dev, res); 134 if (IS_ERR(base)) 135 return PTR_ERR(base); 136 137 context = devm_kzalloc(dev, sizeof(struct rockchip_efuse_context), 138 GFP_KERNEL); 139 if (IS_ERR(context)) 140 return PTR_ERR(context); 141 142 clk = devm_clk_get(dev, "pclk_efuse"); 143 if (IS_ERR(clk)) 144 return PTR_ERR(clk); 145 146 context->dev = dev; 147 context->base = base; 148 context->efuse_clk = clk; 149 150 rockchip_efuse_regmap_config.max_register = resource_size(res) - 1; 151 152 regmap = devm_regmap_init(dev, &rockchip_efuse_bus, 153 context, &rockchip_efuse_regmap_config); 154 if (IS_ERR(regmap)) { 155 dev_err(dev, "regmap init failed\n"); 156 return PTR_ERR(regmap); 157 } 158 econfig.dev = dev; 159 nvmem = nvmem_register(&econfig); 160 if (IS_ERR(nvmem)) 161 return PTR_ERR(nvmem); 162 163 platform_set_drvdata(pdev, nvmem); 164 165 return 0; 166 } 167 168 static int rockchip_efuse_remove(struct platform_device *pdev) 169 { 170 struct nvmem_device *nvmem = platform_get_drvdata(pdev); 171 172 return nvmem_unregister(nvmem); 173 } 174 175 static struct platform_driver rockchip_efuse_driver = { 176 .probe = rockchip_efuse_probe, 177 .remove = rockchip_efuse_remove, 178 .driver = { 179 .name = "rockchip-efuse", 180 .of_match_table = rockchip_efuse_match, 181 }, 182 }; 183 184 module_platform_driver(rockchip_efuse_driver); 185 MODULE_DESCRIPTION("rockchip_efuse driver"); 186 MODULE_LICENSE("GPL v2"); 187