File Index
Files and directories
Sign in
FILE

exynos-chipid.c

File preview with syntax highlighting.

linux-6.19.14/drivers/soc/samsung/exynos-chipid.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (c) 2019 Samsung Electronics Co., Ltd.
  4 *	      http://www.samsung.com/
  5 * Copyright (c) 2020 Krzysztof Kozlowski <krzk@kernel.org>
  6 *
  7 * Exynos - CHIP ID support
  8 * Author: Pankaj Dubey <pankaj.dubey@samsung.com>
  9 * Author: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
 10 * Author: Krzysztof Kozlowski <krzk@kernel.org>
 11 *
 12 * Samsung Exynos SoC Adaptive Supply Voltage and Chip ID support
 13 */
 14
 15#include <linux/array_size.h>
 16#include <linux/device.h>
 17#include <linux/errno.h>
 18#include <linux/mfd/syscon.h>
 19#include <linux/module.h>
 20#include <linux/of.h>
 21#include <linux/platform_device.h>
 22#include <linux/regmap.h>
 23#include <linux/slab.h>
 24#include <linux/soc/samsung/exynos-chipid.h>
 25#include <linux/sys_soc.h>
 26
 27#include "exynos-asv.h"
 28
 29struct exynos_chipid_variant {
 30	unsigned int rev_reg;		/* revision register offset */
 31	unsigned int main_rev_shift;	/* main revision offset in rev_reg */
 32	unsigned int sub_rev_shift;	/* sub revision offset in rev_reg */
 33};
 34
 35struct exynos_chipid_info {
 36	u32 product_id;
 37	u32 revision;
 38};
 39
 40static const struct exynos_soc_id {
 41	const char *name;
 42	unsigned int id;
 43} soc_ids[] = {
 44	/* List ordered by SoC name */
 45	/* Compatible with: samsung,exynos4210-chipid */
 46	{ "EXYNOS3250", 0xE3472000 },
 47	{ "EXYNOS4210", 0x43200000 },	/* EVT0 revision */
 48	{ "EXYNOS4210", 0x43210000 },
 49	{ "EXYNOS4212", 0x43220000 },
 50	{ "EXYNOS4412", 0xE4412000 },
 51	{ "EXYNOS5250", 0x43520000 },
 52	{ "EXYNOS5260", 0xE5260000 },
 53	{ "EXYNOS5410", 0xE5410000 },
 54	{ "EXYNOS5420", 0xE5420000 },
 55	{ "EXYNOS5433", 0xE5433000 },
 56	{ "EXYNOS5440", 0xE5440000 },
 57	{ "EXYNOS5800", 0xE5422000 },
 58	{ "EXYNOS7420", 0xE7420000 },
 59	{ "EXYNOS7870", 0xE7870000 },
 60	{ "EXYNOS8890", 0xE8890000 },
 61	/* Compatible with: samsung,exynos850-chipid */
 62	{ "EXYNOS2200", 0xE9925000 },
 63	{ "EXYNOS7885", 0xE7885000 },
 64	{ "EXYNOS850", 0xE3830000 },
 65	{ "EXYNOS8895", 0xE8895000 },
 66	{ "EXYNOS9610", 0xE9610000 },
 67	{ "EXYNOS9810", 0xE9810000 },
 68	{ "EXYNOS990", 0xE9830000 },
 69	{ "EXYNOSAUTOV9", 0xAAA80000 },
 70	{ "EXYNOSAUTOV920", 0x0A920000 },
 71};
 72
 73static const char *product_id_to_soc_id(unsigned int product_id)
 74{
 75	int i;
 76
 77	for (i = 0; i < ARRAY_SIZE(soc_ids); i++)
 78		if (product_id == soc_ids[i].id)
 79			return soc_ids[i].name;
 80	return NULL;
 81}
 82
 83static int exynos_chipid_get_chipid_info(struct regmap *regmap,
 84		const struct exynos_chipid_variant *data,
 85		struct exynos_chipid_info *soc_info)
 86{
 87	int ret;
 88	unsigned int val, main_rev, sub_rev;
 89
 90	ret = regmap_read(regmap, EXYNOS_CHIPID_REG_PRO_ID, &val);
 91	if (ret < 0)
 92		return ret;
 93	soc_info->product_id = val & EXYNOS_MASK;
 94
 95	if (data->rev_reg != EXYNOS_CHIPID_REG_PRO_ID) {
 96		ret = regmap_read(regmap, data->rev_reg, &val);
 97		if (ret < 0)
 98			return ret;
 99	}
100	main_rev = (val >> data->main_rev_shift) & EXYNOS_REV_PART_MASK;
101	sub_rev = (val >> data->sub_rev_shift) & EXYNOS_REV_PART_MASK;
102	soc_info->revision = (main_rev << EXYNOS_REV_PART_SHIFT) | sub_rev;
103
104	return 0;
105}
106
107static int exynos_chipid_probe(struct platform_device *pdev)
108{
109	const struct exynos_chipid_variant *drv_data;
110	struct exynos_chipid_info soc_info;
111	struct soc_device_attribute *soc_dev_attr;
112	struct device *dev = &pdev->dev;
113	struct soc_device *soc_dev;
114	struct device_node *root;
115	struct regmap *regmap;
116	int ret;
117
118	drv_data = of_device_get_match_data(dev);
119	if (!drv_data)
120		return -EINVAL;
121
122	regmap = device_node_to_regmap(dev->of_node);
123	if (IS_ERR(regmap))
124		return PTR_ERR(regmap);
125
126	ret = exynos_chipid_get_chipid_info(regmap, drv_data, &soc_info);
127	if (ret < 0)
128		return ret;
129
130	soc_dev_attr = devm_kzalloc(dev, sizeof(*soc_dev_attr), GFP_KERNEL);
131	if (!soc_dev_attr)
132		return -ENOMEM;
133
134	soc_dev_attr->family = "Samsung Exynos";
135
136	root = of_find_node_by_path("/");
137	of_property_read_string(root, "model", &soc_dev_attr->machine);
138	of_node_put(root);
139
140	soc_dev_attr->revision = devm_kasprintf(dev, GFP_KERNEL, "%x",
141						soc_info.revision);
142	if (!soc_dev_attr->revision)
143		return -ENOMEM;
144	soc_dev_attr->soc_id = product_id_to_soc_id(soc_info.product_id);
145	if (!soc_dev_attr->soc_id) {
146		pr_err("Unknown SoC\n");
147		return -ENODEV;
148	}
149
150	/* please note that the actual registration will be deferred */
151	soc_dev = soc_device_register(soc_dev_attr);
152	if (IS_ERR(soc_dev))
153		return PTR_ERR(soc_dev);
154
155	ret = exynos_asv_init(dev, regmap);
156	if (ret)
157		goto err;
158
159	platform_set_drvdata(pdev, soc_dev);
160
161	dev_info(dev, "Exynos: CPU[%s] PRO_ID[0x%x] REV[0x%x] Detected\n",
162		 soc_dev_attr->soc_id, soc_info.product_id, soc_info.revision);
163
164	return 0;
165
166err:
167	soc_device_unregister(soc_dev);
168
169	return ret;
170}
171
172static void exynos_chipid_remove(struct platform_device *pdev)
173{
174	struct soc_device *soc_dev = platform_get_drvdata(pdev);
175
176	soc_device_unregister(soc_dev);
177}
178
179static const struct exynos_chipid_variant exynos4210_chipid_drv_data = {
180	.rev_reg	= 0x0,
181	.main_rev_shift	= 4,
182	.sub_rev_shift	= 0,
183};
184
185static const struct exynos_chipid_variant exynos850_chipid_drv_data = {
186	.rev_reg	= 0x10,
187	.main_rev_shift	= 20,
188	.sub_rev_shift	= 16,
189};
190
191static const struct of_device_id exynos_chipid_of_device_ids[] = {
192	{
193		.compatible	= "samsung,exynos4210-chipid",
194		.data		= &exynos4210_chipid_drv_data,
195	}, {
196		.compatible	= "samsung,exynos850-chipid",
197		.data		= &exynos850_chipid_drv_data,
198	},
199	{ }
200};
201MODULE_DEVICE_TABLE(of, exynos_chipid_of_device_ids);
202
203static struct platform_driver exynos_chipid_driver = {
204	.driver = {
205		.name = "exynos-chipid",
206		.of_match_table = exynos_chipid_of_device_ids,
207	},
208	.probe = exynos_chipid_probe,
209	.remove = exynos_chipid_remove,
210};
211module_platform_driver(exynos_chipid_driver);
212
213MODULE_DESCRIPTION("Samsung Exynos ChipID controller and ASV driver");
214MODULE_AUTHOR("Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>");
215MODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>");
216MODULE_AUTHOR("Pankaj Dubey <pankaj.dubey@samsung.com>");
217MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
218MODULE_LICENSE("GPL");
~/ Read-only file preview.