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/clk.h> 18 #include <linux/delay.h> 19 #include <linux/device.h> 20 #include <linux/io.h> 21 #include <linux/module.h> 22 #include <linux/nvmem-provider.h> 23 #include <linux/slab.h> 24 #include <linux/of.h> 25 #include <linux/platform_device.h> 26 #include <linux/regmap.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_chip { 39 struct device *dev; 40 void __iomem *base; 41 struct clk *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_chip *efuse = context; 56 u8 *buf = val; 57 int ret; 58 59 ret = clk_prepare_enable(efuse->clk); 60 if (ret < 0) { 61 dev_err(efuse->dev, "failed to prepare/enable efuse clk\n"); 62 return ret; 63 } 64 65 writel(EFUSE_LOAD | EFUSE_PGENB, efuse->base + REG_EFUSE_CTRL); 66 udelay(1); 67 while (val_size) { 68 writel(readl(efuse->base + REG_EFUSE_CTRL) & 69 (~(EFUSE_A_MASK << EFUSE_A_SHIFT)), 70 efuse->base + REG_EFUSE_CTRL); 71 writel(readl(efuse->base + REG_EFUSE_CTRL) | 72 ((offset & EFUSE_A_MASK) << EFUSE_A_SHIFT), 73 efuse->base + REG_EFUSE_CTRL); 74 udelay(1); 75 writel(readl(efuse->base + REG_EFUSE_CTRL) | 76 EFUSE_STROBE, efuse->base + REG_EFUSE_CTRL); 77 udelay(1); 78 *buf++ = readb(efuse->base + REG_EFUSE_DOUT); 79 writel(readl(efuse->base + REG_EFUSE_CTRL) & 80 (~EFUSE_STROBE), efuse->base + REG_EFUSE_CTRL); 81 udelay(1); 82 83 val_size -= 1; 84 offset += 1; 85 } 86 87 /* Switch to standby mode */ 88 writel(EFUSE_PGENB | EFUSE_CSB, efuse->base + REG_EFUSE_CTRL); 89 90 clk_disable_unprepare(efuse->clk); 91 92 return 0; 93 } 94 95 static struct regmap_bus rockchip_efuse_bus = { 96 .read = rockchip_efuse_read, 97 .write = rockchip_efuse_write, 98 .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, 99 .val_format_endian_default = REGMAP_ENDIAN_NATIVE, 100 }; 101 102 static struct regmap_config rockchip_efuse_regmap_config = { 103 .reg_bits = 32, 104 .reg_stride = 1, 105 .val_bits = 8, 106 }; 107 108 static struct nvmem_config econfig = { 109 .name = "rockchip-efuse", 110 .owner = THIS_MODULE, 111 .read_only = true, 112 }; 113 114 static const struct of_device_id rockchip_efuse_match[] = { 115 { .compatible = "rockchip,rockchip-efuse", }, 116 { /* sentinel */}, 117 }; 118 MODULE_DEVICE_TABLE(of, rockchip_efuse_match); 119 120 static int rockchip_efuse_probe(struct platform_device *pdev) 121 { 122 struct resource *res; 123 struct nvmem_device *nvmem; 124 struct regmap *regmap; 125 struct rockchip_efuse_chip *efuse; 126 127 efuse = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_efuse_chip), 128 GFP_KERNEL); 129 if (!efuse) 130 return -ENOMEM; 131 132 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 133 efuse->base = devm_ioremap_resource(&pdev->dev, res); 134 if (IS_ERR(efuse->base)) 135 return PTR_ERR(efuse->base); 136 137 efuse->clk = devm_clk_get(&pdev->dev, "pclk_efuse"); 138 if (IS_ERR(efuse->clk)) 139 return PTR_ERR(efuse->clk); 140 141 efuse->dev = &pdev->dev; 142 143 rockchip_efuse_regmap_config.max_register = resource_size(res) - 1; 144 145 regmap = devm_regmap_init(efuse->dev, &rockchip_efuse_bus, 146 efuse, &rockchip_efuse_regmap_config); 147 if (IS_ERR(regmap)) { 148 dev_err(efuse->dev, "regmap init failed\n"); 149 return PTR_ERR(regmap); 150 } 151 152 econfig.dev = efuse->dev; 153 nvmem = nvmem_register(&econfig); 154 if (IS_ERR(nvmem)) 155 return PTR_ERR(nvmem); 156 157 platform_set_drvdata(pdev, nvmem); 158 159 return 0; 160 } 161 162 static int rockchip_efuse_remove(struct platform_device *pdev) 163 { 164 struct nvmem_device *nvmem = platform_get_drvdata(pdev); 165 166 return nvmem_unregister(nvmem); 167 } 168 169 static struct platform_driver rockchip_efuse_driver = { 170 .probe = rockchip_efuse_probe, 171 .remove = rockchip_efuse_remove, 172 .driver = { 173 .name = "rockchip-efuse", 174 .of_match_table = rockchip_efuse_match, 175 }, 176 }; 177 178 module_platform_driver(rockchip_efuse_driver); 179 MODULE_DESCRIPTION("rockchip_efuse driver"); 180 MODULE_LICENSE("GPL v2"); 181