1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Nuvoton WPCM450 SoC Identification 4 * 5 * Copyright (C) 2022 Jonathan Neuschäfer 6 */ 7 8 #include <linux/mfd/syscon.h> 9 #include <linux/of.h> 10 #include <linux/regmap.h> 11 #include <linux/slab.h> 12 #include <linux/sys_soc.h> 13 14 #define GCR_PDID 0 15 #define PDID_CHIP(x) ((x) & 0x00ffffff) 16 #define CHIP_WPCM450 0x926450 17 #define PDID_REV(x) ((x) >> 24) 18 19 struct revision { 20 u8 number; 21 const char *name; 22 }; 23 24 static const struct revision revisions[] __initconst = { 25 { 0x00, "Z1" }, 26 { 0x03, "Z2" }, 27 { 0x04, "Z21" }, 28 { 0x08, "A1" }, 29 { 0x09, "A2" }, 30 { 0x0a, "A3" }, 31 {} 32 }; 33 34 static const char * __init get_revision(unsigned int rev) 35 { 36 int i; 37 38 for (i = 0; revisions[i].name; i++) 39 if (revisions[i].number == rev) 40 return revisions[i].name; 41 return NULL; 42 } 43 44 static struct soc_device_attribute *wpcm450_attr; 45 static struct soc_device *wpcm450_soc; 46 47 static int __init wpcm450_soc_init(void) 48 { 49 struct soc_device_attribute *attr; 50 struct soc_device *soc; 51 const char *revision; 52 struct regmap *gcr; 53 u32 pdid; 54 int ret; 55 56 if (!of_machine_is_compatible("nuvoton,wpcm450")) 57 return 0; 58 59 gcr = syscon_regmap_lookup_by_compatible("nuvoton,wpcm450-gcr"); 60 if (IS_ERR(gcr)) 61 return PTR_ERR(gcr); 62 ret = regmap_read(gcr, GCR_PDID, &pdid); 63 if (ret) 64 return ret; 65 66 if (PDID_CHIP(pdid) != CHIP_WPCM450) { 67 pr_warn("Unknown chip ID in GCR.PDID: 0x%06x\n", PDID_CHIP(pdid)); 68 return -ENODEV; 69 } 70 71 revision = get_revision(PDID_REV(pdid)); 72 if (!revision) { 73 pr_warn("Unknown chip revision in GCR.PDID: 0x%02x\n", PDID_REV(pdid)); 74 return -ENODEV; 75 } 76 77 attr = kzalloc(sizeof(*attr), GFP_KERNEL); 78 if (!attr) 79 return -ENOMEM; 80 81 attr->family = "Nuvoton NPCM"; 82 attr->soc_id = "WPCM450"; 83 attr->revision = revision; 84 soc = soc_device_register(attr); 85 if (IS_ERR(soc)) { 86 kfree(attr); 87 pr_warn("Could not register SoC device\n"); 88 return PTR_ERR(soc); 89 } 90 91 wpcm450_soc = soc; 92 wpcm450_attr = attr; 93 return 0; 94 } 95 module_init(wpcm450_soc_init); 96 97 static void __exit wpcm450_soc_exit(void) 98 { 99 if (wpcm450_soc) { 100 soc_device_unregister(wpcm450_soc); 101 wpcm450_soc = NULL; 102 kfree(wpcm450_attr); 103 } 104 } 105 module_exit(wpcm450_soc_exit); 106 107 MODULE_LICENSE("GPL"); 108 MODULE_AUTHOR("Jonathan Neuschäfer"); 109 MODULE_DESCRIPTION("Nuvoton WPCM450 SoC Identification driver"); 110