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