145 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2014 Linaro Ltd.4 *5 * Author: Linus Walleij <linus.walleij@linaro.org>6 */7#include <linux/device.h>8#include <linux/init.h>9#include <linux/io.h>10#include <linux/slab.h>11#include <linux/sys_soc.h>12#include <linux/platform_device.h>13#include <linux/mfd/syscon.h>14#include <linux/regmap.h>15#include <linux/of.h>16 17/* System ID in syscon */18#define REALVIEW_SYS_ID_OFFSET 0x0019 20static const struct of_device_id realview_soc_of_match[] = {21 { .compatible = "arm,realview-eb-soc", },22 { .compatible = "arm,realview-pb1176-soc", },23 { .compatible = "arm,realview-pb11mp-soc", },24 { .compatible = "arm,realview-pba8-soc", },25 { .compatible = "arm,realview-pbx-soc", },26 { }27};28 29static u32 realview_coreid;30 31static const char *realview_arch_str(u32 id)32{33 switch ((id >> 8) & 0xf) {34 case 0x04:35 return "AHB";36 case 0x05:37 return "Multi-layer AXI";38 default:39 return "Unknown";40 }41}42 43static ssize_t44manufacturer_show(struct device *dev, struct device_attribute *attr, char *buf)45{46 return sprintf(buf, "%02x\n", realview_coreid >> 24);47}48 49static DEVICE_ATTR_RO(manufacturer);50 51static ssize_t52board_show(struct device *dev, struct device_attribute *attr, char *buf)53{54 return sprintf(buf, "HBI-%03x\n", ((realview_coreid >> 16) & 0xfff));55}56 57static DEVICE_ATTR_RO(board);58 59static ssize_t60fpga_show(struct device *dev, struct device_attribute *attr, char *buf)61{62 return sprintf(buf, "%s\n", realview_arch_str(realview_coreid));63}64 65static DEVICE_ATTR_RO(fpga);66 67static ssize_t68build_show(struct device *dev, struct device_attribute *attr, char *buf)69{70 return sprintf(buf, "%02x\n", (realview_coreid & 0xFF));71}72 73static DEVICE_ATTR_RO(build);74 75static struct attribute *realview_attrs[] = {76 &dev_attr_manufacturer.attr,77 &dev_attr_board.attr,78 &dev_attr_fpga.attr,79 &dev_attr_build.attr,80 NULL81};82 83ATTRIBUTE_GROUPS(realview);84 85static void realview_soc_socdev_release(void *data)86{87 struct soc_device *soc_dev = data;88 89 soc_device_unregister(soc_dev);90}91 92static int realview_soc_probe(struct platform_device *pdev)93{94 struct regmap *syscon_regmap;95 struct soc_device *soc_dev;96 struct soc_device_attribute *soc_dev_attr;97 struct device_node *np = pdev->dev.of_node;98 int ret;99 100 syscon_regmap = syscon_regmap_lookup_by_phandle(np, "regmap");101 if (IS_ERR(syscon_regmap))102 return PTR_ERR(syscon_regmap);103 104 soc_dev_attr = devm_kzalloc(&pdev->dev, sizeof(*soc_dev_attr), GFP_KERNEL);105 if (!soc_dev_attr)106 return -ENOMEM;107 108 ret = of_property_read_string(np, "compatible",109 &soc_dev_attr->soc_id);110 if (ret)111 return -EINVAL;112 113 soc_dev_attr->machine = "RealView";114 soc_dev_attr->family = "Versatile";115 soc_dev_attr->custom_attr_group = realview_groups[0];116 soc_dev = soc_device_register(soc_dev_attr);117 if (IS_ERR(soc_dev))118 return -ENODEV;119 120 ret = devm_add_action_or_reset(&pdev->dev, realview_soc_socdev_release,121 soc_dev);122 if (ret)123 return ret;124 125 ret = regmap_read(syscon_regmap, REALVIEW_SYS_ID_OFFSET,126 &realview_coreid);127 if (ret)128 return -ENODEV;129 130 dev_info(&pdev->dev, "RealView Syscon Core ID: 0x%08x, HBI-%03x\n",131 realview_coreid,132 ((realview_coreid >> 16) & 0xfff));133 /* FIXME: add attributes for SoC to sysfs */134 return 0;135}136 137static struct platform_driver realview_soc_driver = {138 .probe = realview_soc_probe,139 .driver = {140 .name = "realview-soc",141 .of_match_table = realview_soc_of_match,142 },143};144builtin_platform_driver(realview_soc_driver);145