brintos

brintos / linux-shallow public Read only

0
0
Text · 7.2 KiB · 4e2ffef Raw
280 lines · c
1// SPDX-License-Identifier: GPL-2.02// 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		0xc0813#define SC2730_MODULE_EN		0x180814#define SC27XX_EFUSE_EN			BIT(6)15 16/* Efuse controller registers definition */17#define SC27XX_EFUSE_GLB_CTRL		0x018#define SC27XX_EFUSE_DATA_RD		0x419#define SC27XX_EFUSE_DATA_WR		0x820#define SC27XX_EFUSE_BLOCK_INDEX	0xc21#define SC27XX_EFUSE_MODE_CTRL		0x1022#define SC27XX_EFUSE_STATUS		0x1423#define SC27XX_EFUSE_WR_TIMING_CTRL	0x2024#define SC27XX_EFUSE_RD_TIMING_CTRL	0x2425#define SC27XX_EFUSE_EFUSE_DEB_CTRL	0x2826 27/* Mask definition for SC27XX_EFUSE_BLOCK_INDEX register */28#define SC27XX_EFUSE_BLOCK_MASK		GENMASK(4, 0)29 30/* Bits definitions for SC27XX_EFUSE_MODE_CTRL register */31#define SC27XX_EFUSE_PG_START		BIT(0)32#define SC27XX_EFUSE_RD_START		BIT(1)33#define SC27XX_EFUSE_CLR_RDDONE		BIT(2)34 35/* Bits definitions for SC27XX_EFUSE_STATUS register */36#define SC27XX_EFUSE_PGM_BUSY		BIT(0)37#define SC27XX_EFUSE_READ_BUSY		BIT(1)38#define SC27XX_EFUSE_STANDBY		BIT(2)39#define SC27XX_EFUSE_GLOBAL_PROT	BIT(3)40#define SC27XX_EFUSE_RD_DONE		BIT(4)41 42/* Block number and block width (bytes) definitions */43#define SC27XX_EFUSE_BLOCK_MAX		3244#define SC27XX_EFUSE_BLOCK_WIDTH	245 46/* Timeout (ms) for the trylock of hardware spinlocks */47#define SC27XX_EFUSE_HWLOCK_TIMEOUT	500048 49/* Timeout (us) of polling the status */50#define SC27XX_EFUSE_POLL_TIMEOUT	300000051#define SC27XX_EFUSE_POLL_DELAY_US	1000052 53/*54 * Since different PMICs of SC27xx series can have different55 * address , we should save address in the device data structure.56 */57struct sc27xx_efuse_variant_data {58	u32 module_en;59};60 61struct sc27xx_efuse {62	struct device *dev;63	struct regmap *regmap;64	struct hwspinlock *hwlock;65	struct mutex mutex;66	u32 base;67	const struct sc27xx_efuse_variant_data *var_data;68};69 70static const struct sc27xx_efuse_variant_data sc2731_edata = {71	.module_en = SC27XX_MODULE_EN,72};73 74static const struct sc27xx_efuse_variant_data sc2730_edata = {75	.module_en = SC2730_MODULE_EN,76};77 78/*79 * On Spreadtrum platform, we have multi-subsystems will access the unique80 * efuse controller, so we need one hardware spinlock to synchronize between81 * the multiple subsystems.82 */83static int sc27xx_efuse_lock(struct sc27xx_efuse *efuse)84{85	int ret;86 87	mutex_lock(&efuse->mutex);88 89	ret = hwspin_lock_timeout_raw(efuse->hwlock,90				      SC27XX_EFUSE_HWLOCK_TIMEOUT);91	if (ret) {92		dev_err(efuse->dev, "timeout to get the hwspinlock\n");93		mutex_unlock(&efuse->mutex);94		return ret;95	}96 97	return 0;98}99 100static void sc27xx_efuse_unlock(struct sc27xx_efuse *efuse)101{102	hwspin_unlock_raw(efuse->hwlock);103	mutex_unlock(&efuse->mutex);104}105 106static int sc27xx_efuse_poll_status(struct sc27xx_efuse *efuse, u32 bits)107{108	int ret;109	u32 val;110 111	ret = regmap_read_poll_timeout(efuse->regmap,112				       efuse->base + SC27XX_EFUSE_STATUS,113				       val, (val & bits),114				       SC27XX_EFUSE_POLL_DELAY_US,115				       SC27XX_EFUSE_POLL_TIMEOUT);116	if (ret) {117		dev_err(efuse->dev, "timeout to update the efuse status\n");118		return ret;119	}120 121	return 0;122}123 124static int sc27xx_efuse_read(void *context, u32 offset, void *val, size_t bytes)125{126	struct sc27xx_efuse *efuse = context;127	u32 buf, blk_index = offset / SC27XX_EFUSE_BLOCK_WIDTH;128	u32 blk_offset = (offset % SC27XX_EFUSE_BLOCK_WIDTH) * BITS_PER_BYTE;129	int ret;130 131	if (blk_index > SC27XX_EFUSE_BLOCK_MAX ||132	    bytes > SC27XX_EFUSE_BLOCK_WIDTH)133		return -EINVAL;134 135	ret = sc27xx_efuse_lock(efuse);136	if (ret)137		return ret;138 139	/* Enable the efuse controller. */140	ret = regmap_update_bits(efuse->regmap, efuse->var_data->module_en,141				 SC27XX_EFUSE_EN, SC27XX_EFUSE_EN);142	if (ret)143		goto unlock_efuse;144 145	/*146	 * Before reading, we should ensure the efuse controller is in147	 * standby state.148	 */149	ret = sc27xx_efuse_poll_status(efuse, SC27XX_EFUSE_STANDBY);150	if (ret)151		goto disable_efuse;152 153	/* Set the block address to be read. */154	ret = regmap_write(efuse->regmap,155			   efuse->base + SC27XX_EFUSE_BLOCK_INDEX,156			   blk_index & SC27XX_EFUSE_BLOCK_MASK);157	if (ret)158		goto disable_efuse;159 160	/* Start reading process from efuse memory. */161	ret = regmap_update_bits(efuse->regmap,162				 efuse->base + SC27XX_EFUSE_MODE_CTRL,163				 SC27XX_EFUSE_RD_START,164				 SC27XX_EFUSE_RD_START);165	if (ret)166		goto disable_efuse;167 168	/*169	 * Polling the read done status to make sure the reading process170	 * is completed, that means the data can be read out now.171	 */172	ret = sc27xx_efuse_poll_status(efuse, SC27XX_EFUSE_RD_DONE);173	if (ret)174		goto disable_efuse;175 176	/* Read data from efuse memory. */177	ret = regmap_read(efuse->regmap, efuse->base + SC27XX_EFUSE_DATA_RD,178			  &buf);179	if (ret)180		goto disable_efuse;181 182	/* Clear the read done flag. */183	ret = regmap_update_bits(efuse->regmap,184				 efuse->base + SC27XX_EFUSE_MODE_CTRL,185				 SC27XX_EFUSE_CLR_RDDONE,186				 SC27XX_EFUSE_CLR_RDDONE);187 188disable_efuse:189	/* Disable the efuse controller after reading. */190	regmap_update_bits(efuse->regmap, efuse->var_data->module_en, SC27XX_EFUSE_EN, 0);191unlock_efuse:192	sc27xx_efuse_unlock(efuse);193 194	if (!ret) {195		buf >>= blk_offset;196		memcpy(val, &buf, bytes);197	}198 199	return ret;200}201 202static int sc27xx_efuse_probe(struct platform_device *pdev)203{204	struct device_node *np = pdev->dev.of_node;205	struct nvmem_config econfig = { };206	struct nvmem_device *nvmem;207	struct sc27xx_efuse *efuse;208	int ret;209 210	efuse = devm_kzalloc(&pdev->dev, sizeof(*efuse), GFP_KERNEL);211	if (!efuse)212		return -ENOMEM;213 214	efuse->regmap = dev_get_regmap(pdev->dev.parent, NULL);215	if (!efuse->regmap) {216		dev_err(&pdev->dev, "failed to get efuse regmap\n");217		return -ENODEV;218	}219 220	ret = of_property_read_u32(np, "reg", &efuse->base);221	if (ret) {222		dev_err(&pdev->dev, "failed to get efuse base address\n");223		return ret;224	}225 226	ret = of_hwspin_lock_get_id(np, 0);227	if (ret < 0) {228		dev_err(&pdev->dev, "failed to get hwspinlock id\n");229		return ret;230	}231 232	efuse->hwlock = devm_hwspin_lock_request_specific(&pdev->dev, ret);233	if (!efuse->hwlock) {234		dev_err(&pdev->dev, "failed to request hwspinlock\n");235		return -ENXIO;236	}237 238	mutex_init(&efuse->mutex);239	efuse->dev = &pdev->dev;240	efuse->var_data = of_device_get_match_data(&pdev->dev);241 242	econfig.stride = 1;243	econfig.word_size = 1;244	econfig.read_only = true;245	econfig.name = "sc27xx-efuse";246	econfig.size = SC27XX_EFUSE_BLOCK_MAX * SC27XX_EFUSE_BLOCK_WIDTH;247	econfig.reg_read = sc27xx_efuse_read;248	econfig.priv = efuse;249	econfig.dev = &pdev->dev;250	econfig.add_legacy_fixed_of_cells = true;251	nvmem = devm_nvmem_register(&pdev->dev, &econfig);252	if (IS_ERR(nvmem)) {253		dev_err(&pdev->dev, "failed to register nvmem config\n");254		return PTR_ERR(nvmem);255	}256 257	return 0;258}259 260static const struct of_device_id sc27xx_efuse_of_match[] = {261	{ .compatible = "sprd,sc2731-efuse", .data = &sc2731_edata},262	{ .compatible = "sprd,sc2730-efuse", .data = &sc2730_edata},263	{ }264};265MODULE_DEVICE_TABLE(of, sc27xx_efuse_of_match);266 267static struct platform_driver sc27xx_efuse_driver = {268	.probe = sc27xx_efuse_probe,269	.driver = {270		.name = "sc27xx-efuse",271		.of_match_table = sc27xx_efuse_of_match,272	},273};274 275module_platform_driver(sc27xx_efuse_driver);276 277MODULE_AUTHOR("Freeman Liu <freeman.liu@spreadtrum.com>");278MODULE_DESCRIPTION("Spreadtrum SC27xx efuse driver");279MODULE_LICENSE("GPL v2");280