Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.6-rc5 180 lines 4.7 kB view raw
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 38struct rockchip_efuse_chip { 39 struct device *dev; 40 void __iomem *base; 41 struct clk *clk; 42}; 43 44static int rockchip_efuse_write(void *context, const void *data, size_t count) 45{ 46 /* Nothing TBD, Read-Only */ 47 return 0; 48} 49 50static 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 95static 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 102static struct regmap_config rockchip_efuse_regmap_config = { 103 .reg_bits = 32, 104 .reg_stride = 1, 105 .val_bits = 8, 106}; 107 108static struct nvmem_config econfig = { 109 .name = "rockchip-efuse", 110 .owner = THIS_MODULE, 111 .read_only = true, 112}; 113 114static const struct of_device_id rockchip_efuse_match[] = { 115 { .compatible = "rockchip,rockchip-efuse", }, 116 { /* sentinel */}, 117}; 118MODULE_DEVICE_TABLE(of, rockchip_efuse_match); 119 120static 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 162static 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 169static 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 178module_platform_driver(rockchip_efuse_driver); 179MODULE_DESCRIPTION("rockchip_efuse driver"); 180MODULE_LICENSE("GPL v2");