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 27 #define EFUSE_A_SHIFT 6 28 #define EFUSE_A_MASK 0x3ff 29 #define EFUSE_PGENB BIT(3) 30 #define EFUSE_LOAD BIT(2) 31 #define EFUSE_STROBE BIT(1) 32 #define EFUSE_CSB BIT(0) 33 34 #define REG_EFUSE_CTRL 0x0000 35 #define REG_EFUSE_DOUT 0x0004 36 37 struct rockchip_efuse_chip { 38 struct device *dev; 39 void __iomem *base; 40 struct clk *clk; 41 }; 42 43 static int rockchip_efuse_read(void *context, unsigned int offset, 44 void *val, size_t bytes) 45 { 46 struct rockchip_efuse_chip *efuse = context; 47 u8 *buf = val; 48 int ret; 49 50 ret = clk_prepare_enable(efuse->clk); 51 if (ret < 0) { 52 dev_err(efuse->dev, "failed to prepare/enable efuse clk\n"); 53 return ret; 54 } 55 56 writel(EFUSE_LOAD | EFUSE_PGENB, efuse->base + REG_EFUSE_CTRL); 57 udelay(1); 58 while (bytes--) { 59 writel(readl(efuse->base + REG_EFUSE_CTRL) & 60 (~(EFUSE_A_MASK << EFUSE_A_SHIFT)), 61 efuse->base + REG_EFUSE_CTRL); 62 writel(readl(efuse->base + REG_EFUSE_CTRL) | 63 ((offset++ & EFUSE_A_MASK) << EFUSE_A_SHIFT), 64 efuse->base + REG_EFUSE_CTRL); 65 udelay(1); 66 writel(readl(efuse->base + REG_EFUSE_CTRL) | 67 EFUSE_STROBE, efuse->base + REG_EFUSE_CTRL); 68 udelay(1); 69 *buf++ = readb(efuse->base + REG_EFUSE_DOUT); 70 writel(readl(efuse->base + REG_EFUSE_CTRL) & 71 (~EFUSE_STROBE), efuse->base + REG_EFUSE_CTRL); 72 udelay(1); 73 } 74 75 /* Switch to standby mode */ 76 writel(EFUSE_PGENB | EFUSE_CSB, efuse->base + REG_EFUSE_CTRL); 77 78 clk_disable_unprepare(efuse->clk); 79 80 return 0; 81 } 82 83 static struct nvmem_config econfig = { 84 .name = "rockchip-efuse", 85 .owner = THIS_MODULE, 86 .stride = 1, 87 .word_size = 1, 88 .read_only = true, 89 }; 90 91 static const struct of_device_id rockchip_efuse_match[] = { 92 { .compatible = "rockchip,rockchip-efuse", }, 93 { /* sentinel */}, 94 }; 95 MODULE_DEVICE_TABLE(of, rockchip_efuse_match); 96 97 static int rockchip_efuse_probe(struct platform_device *pdev) 98 { 99 struct resource *res; 100 struct nvmem_device *nvmem; 101 struct rockchip_efuse_chip *efuse; 102 103 efuse = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_efuse_chip), 104 GFP_KERNEL); 105 if (!efuse) 106 return -ENOMEM; 107 108 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 109 efuse->base = devm_ioremap_resource(&pdev->dev, res); 110 if (IS_ERR(efuse->base)) 111 return PTR_ERR(efuse->base); 112 113 efuse->clk = devm_clk_get(&pdev->dev, "pclk_efuse"); 114 if (IS_ERR(efuse->clk)) 115 return PTR_ERR(efuse->clk); 116 117 efuse->dev = &pdev->dev; 118 econfig.size = resource_size(res); 119 econfig.reg_read = rockchip_efuse_read; 120 econfig.priv = efuse; 121 econfig.dev = efuse->dev; 122 nvmem = nvmem_register(&econfig); 123 if (IS_ERR(nvmem)) 124 return PTR_ERR(nvmem); 125 126 platform_set_drvdata(pdev, nvmem); 127 128 return 0; 129 } 130 131 static int rockchip_efuse_remove(struct platform_device *pdev) 132 { 133 struct nvmem_device *nvmem = platform_get_drvdata(pdev); 134 135 return nvmem_unregister(nvmem); 136 } 137 138 static struct platform_driver rockchip_efuse_driver = { 139 .probe = rockchip_efuse_probe, 140 .remove = rockchip_efuse_remove, 141 .driver = { 142 .name = "rockchip-efuse", 143 .of_match_table = rockchip_efuse_match, 144 }, 145 }; 146 147 module_platform_driver(rockchip_efuse_driver); 148 MODULE_DESCRIPTION("rockchip_efuse driver"); 149 MODULE_LICENSE("GPL v2"); 150