Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0
  2// Copyright (C) 2018 Spreadtrum Communications Inc.
  3
  4#include <linux/hwspinlock.h>
  5#include <linux/module.h>
  6#include <linux/of.h>
  7#include <linux/platform_device.h>
  8#include <linux/regmap.h>
  9#include <linux/nvmem-provider.h>
 10
 11/* PMIC global registers definition */
 12#define SC27XX_MODULE_EN		0xc08
 13#define SC27XX_EFUSE_EN			BIT(6)
 14
 15/* Efuse controller registers definition */
 16#define SC27XX_EFUSE_GLB_CTRL		0x0
 17#define SC27XX_EFUSE_DATA_RD		0x4
 18#define SC27XX_EFUSE_DATA_WR		0x8
 19#define SC27XX_EFUSE_BLOCK_INDEX	0xc
 20#define SC27XX_EFUSE_MODE_CTRL		0x10
 21#define SC27XX_EFUSE_STATUS		0x14
 22#define SC27XX_EFUSE_WR_TIMING_CTRL	0x20
 23#define SC27XX_EFUSE_RD_TIMING_CTRL	0x24
 24#define SC27XX_EFUSE_EFUSE_DEB_CTRL	0x28
 25
 26/* Mask definition for SC27XX_EFUSE_BLOCK_INDEX register */
 27#define SC27XX_EFUSE_BLOCK_MASK		GENMASK(4, 0)
 28
 29/* Bits definitions for SC27XX_EFUSE_MODE_CTRL register */
 30#define SC27XX_EFUSE_PG_START		BIT(0)
 31#define SC27XX_EFUSE_RD_START		BIT(1)
 32#define SC27XX_EFUSE_CLR_RDDONE		BIT(2)
 33
 34/* Bits definitions for SC27XX_EFUSE_STATUS register */
 35#define SC27XX_EFUSE_PGM_BUSY		BIT(0)
 36#define SC27XX_EFUSE_READ_BUSY		BIT(1)
 37#define SC27XX_EFUSE_STANDBY		BIT(2)
 38#define SC27XX_EFUSE_GLOBAL_PROT	BIT(3)
 39#define SC27XX_EFUSE_RD_DONE		BIT(4)
 40
 41/* Block number and block width (bytes) definitions */
 42#define SC27XX_EFUSE_BLOCK_MAX		32
 43#define SC27XX_EFUSE_BLOCK_WIDTH	2
 44
 45/* Timeout (ms) for the trylock of hardware spinlocks */
 46#define SC27XX_EFUSE_HWLOCK_TIMEOUT	5000
 47
 48/* Timeout (us) of polling the status */
 49#define SC27XX_EFUSE_POLL_TIMEOUT	3000000
 50#define SC27XX_EFUSE_POLL_DELAY_US	10000
 51
 52struct sc27xx_efuse {
 53	struct device *dev;
 54	struct regmap *regmap;
 55	struct hwspinlock *hwlock;
 56	struct mutex mutex;
 57	u32 base;
 58};
 59
 60/*
 61 * On Spreadtrum platform, we have multi-subsystems will access the unique
 62 * efuse controller, so we need one hardware spinlock to synchronize between
 63 * the multiple subsystems.
 64 */
 65static int sc27xx_efuse_lock(struct sc27xx_efuse *efuse)
 66{
 67	int ret;
 68
 69	mutex_lock(&efuse->mutex);
 70
 71	ret = hwspin_lock_timeout_raw(efuse->hwlock,
 72				      SC27XX_EFUSE_HWLOCK_TIMEOUT);
 73	if (ret) {
 74		dev_err(efuse->dev, "timeout to get the hwspinlock\n");
 75		mutex_unlock(&efuse->mutex);
 76		return ret;
 77	}
 78
 79	return 0;
 80}
 81
 82static void sc27xx_efuse_unlock(struct sc27xx_efuse *efuse)
 83{
 84	hwspin_unlock_raw(efuse->hwlock);
 85	mutex_unlock(&efuse->mutex);
 86}
 87
 88static int sc27xx_efuse_poll_status(struct sc27xx_efuse *efuse, u32 bits)
 89{
 90	int ret;
 91	u32 val;
 92
 93	ret = regmap_read_poll_timeout(efuse->regmap,
 94				       efuse->base + SC27XX_EFUSE_STATUS,
 95				       val, (val & bits),
 96				       SC27XX_EFUSE_POLL_DELAY_US,
 97				       SC27XX_EFUSE_POLL_TIMEOUT);
 98	if (ret) {
 99		dev_err(efuse->dev, "timeout to update the efuse status\n");
100		return ret;
101	}
102
103	return 0;
104}
105
106static int sc27xx_efuse_read(void *context, u32 offset, void *val, size_t bytes)
107{
108	struct sc27xx_efuse *efuse = context;
109	u32 buf, blk_index = offset / SC27XX_EFUSE_BLOCK_WIDTH;
110	u32 blk_offset = (offset % SC27XX_EFUSE_BLOCK_WIDTH) * BITS_PER_BYTE;
111	int ret;
112
113	if (blk_index > SC27XX_EFUSE_BLOCK_MAX ||
114	    bytes > SC27XX_EFUSE_BLOCK_WIDTH)
115		return -EINVAL;
116
117	ret = sc27xx_efuse_lock(efuse);
118	if (ret)
119		return ret;
120
121	/* Enable the efuse controller. */
122	ret = regmap_update_bits(efuse->regmap, SC27XX_MODULE_EN,
123				 SC27XX_EFUSE_EN, SC27XX_EFUSE_EN);
124	if (ret)
125		goto unlock_efuse;
126
127	/*
128	 * Before reading, we should ensure the efuse controller is in
129	 * standby state.
130	 */
131	ret = sc27xx_efuse_poll_status(efuse, SC27XX_EFUSE_STANDBY);
132	if (ret)
133		goto disable_efuse;
134
135	/* Set the block address to be read. */
136	ret = regmap_write(efuse->regmap,
137			   efuse->base + SC27XX_EFUSE_BLOCK_INDEX,
138			   blk_index & SC27XX_EFUSE_BLOCK_MASK);
139	if (ret)
140		goto disable_efuse;
141
142	/* Start reading process from efuse memory. */
143	ret = regmap_update_bits(efuse->regmap,
144				 efuse->base + SC27XX_EFUSE_MODE_CTRL,
145				 SC27XX_EFUSE_RD_START,
146				 SC27XX_EFUSE_RD_START);
147	if (ret)
148		goto disable_efuse;
149
150	/*
151	 * Polling the read done status to make sure the reading process
152	 * is completed, that means the data can be read out now.
153	 */
154	ret = sc27xx_efuse_poll_status(efuse, SC27XX_EFUSE_RD_DONE);
155	if (ret)
156		goto disable_efuse;
157
158	/* Read data from efuse memory. */
159	ret = regmap_read(efuse->regmap, efuse->base + SC27XX_EFUSE_DATA_RD,
160			  &buf);
161	if (ret)
162		goto disable_efuse;
163
164	/* Clear the read done flag. */
165	ret = regmap_update_bits(efuse->regmap,
166				 efuse->base + SC27XX_EFUSE_MODE_CTRL,
167				 SC27XX_EFUSE_CLR_RDDONE,
168				 SC27XX_EFUSE_CLR_RDDONE);
169
170disable_efuse:
171	/* Disable the efuse controller after reading. */
172	regmap_update_bits(efuse->regmap, SC27XX_MODULE_EN, SC27XX_EFUSE_EN, 0);
173unlock_efuse:
174	sc27xx_efuse_unlock(efuse);
175
176	if (!ret) {
177		buf >>= blk_offset;
178		memcpy(val, &buf, bytes);
179	}
180
181	return ret;
182}
183
184static int sc27xx_efuse_probe(struct platform_device *pdev)
185{
186	struct device_node *np = pdev->dev.of_node;
187	struct nvmem_config econfig = { };
188	struct nvmem_device *nvmem;
189	struct sc27xx_efuse *efuse;
190	int ret;
191
192	efuse = devm_kzalloc(&pdev->dev, sizeof(*efuse), GFP_KERNEL);
193	if (!efuse)
194		return -ENOMEM;
195
196	efuse->regmap = dev_get_regmap(pdev->dev.parent, NULL);
197	if (!efuse->regmap) {
198		dev_err(&pdev->dev, "failed to get efuse regmap\n");
199		return -ENODEV;
200	}
201
202	ret = of_property_read_u32(np, "reg", &efuse->base);
203	if (ret) {
204		dev_err(&pdev->dev, "failed to get efuse base address\n");
205		return ret;
206	}
207
208	ret = of_hwspin_lock_get_id(np, 0);
209	if (ret < 0) {
210		dev_err(&pdev->dev, "failed to get hwspinlock id\n");
211		return ret;
212	}
213
214	efuse->hwlock = hwspin_lock_request_specific(ret);
215	if (!efuse->hwlock) {
216		dev_err(&pdev->dev, "failed to request hwspinlock\n");
217		return -ENXIO;
218	}
219
220	mutex_init(&efuse->mutex);
221	efuse->dev = &pdev->dev;
222	platform_set_drvdata(pdev, efuse);
223
224	econfig.stride = 1;
225	econfig.word_size = 1;
226	econfig.read_only = true;
227	econfig.name = "sc27xx-efuse";
228	econfig.size = SC27XX_EFUSE_BLOCK_MAX * SC27XX_EFUSE_BLOCK_WIDTH;
229	econfig.reg_read = sc27xx_efuse_read;
230	econfig.priv = efuse;
231	econfig.dev = &pdev->dev;
232	nvmem = devm_nvmem_register(&pdev->dev, &econfig);
233	if (IS_ERR(nvmem)) {
234		dev_err(&pdev->dev, "failed to register nvmem config\n");
235		hwspin_lock_free(efuse->hwlock);
236		return PTR_ERR(nvmem);
237	}
238
239	return 0;
240}
241
242static int sc27xx_efuse_remove(struct platform_device *pdev)
243{
244	struct sc27xx_efuse *efuse = platform_get_drvdata(pdev);
245
246	hwspin_lock_free(efuse->hwlock);
247	return 0;
248}
249
250static const struct of_device_id sc27xx_efuse_of_match[] = {
251	{ .compatible = "sprd,sc2731-efuse" },
252	{ }
253};
254
255static struct platform_driver sc27xx_efuse_driver = {
256	.probe = sc27xx_efuse_probe,
257	.remove = sc27xx_efuse_remove,
258	.driver = {
259		.name = "sc27xx-efuse",
260		.of_match_table = sc27xx_efuse_of_match,
261	},
262};
263
264module_platform_driver(sc27xx_efuse_driver);
265
266MODULE_AUTHOR("Freeman Liu <freeman.liu@spreadtrum.com>");
267MODULE_DESCRIPTION("Spreadtrum SC27xx efuse driver");
268MODULE_LICENSE("GPL v2");