root/drivers/base/soc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. soc_device_to_device
  2. soc_attribute_mode
  3. soc_info_get
  4. soc_release
  5. soc_device_register
  6. soc_device_unregister
  7. soc_bus_register
  8. soc_device_match_attr
  9. soc_device_match_one
  10. soc_device_match

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright (C) ST-Ericsson SA 2011
   4  *
   5  * Author: Lee Jones <lee.jones@linaro.org> for ST-Ericsson.
   6  */
   7 
   8 #include <linux/sysfs.h>
   9 #include <linux/init.h>
  10 #include <linux/stat.h>
  11 #include <linux/slab.h>
  12 #include <linux/idr.h>
  13 #include <linux/spinlock.h>
  14 #include <linux/sys_soc.h>
  15 #include <linux/err.h>
  16 #include <linux/glob.h>
  17 
  18 static DEFINE_IDA(soc_ida);
  19 
  20 static ssize_t soc_info_get(struct device *dev,
  21                             struct device_attribute *attr,
  22                             char *buf);
  23 
  24 struct soc_device {
  25         struct device dev;
  26         struct soc_device_attribute *attr;
  27         int soc_dev_num;
  28 };
  29 
  30 static struct bus_type soc_bus_type = {
  31         .name  = "soc",
  32 };
  33 
  34 static DEVICE_ATTR(machine,  S_IRUGO, soc_info_get,  NULL);
  35 static DEVICE_ATTR(family,   S_IRUGO, soc_info_get,  NULL);
  36 static DEVICE_ATTR(serial_number, S_IRUGO, soc_info_get,  NULL);
  37 static DEVICE_ATTR(soc_id,   S_IRUGO, soc_info_get,  NULL);
  38 static DEVICE_ATTR(revision, S_IRUGO, soc_info_get,  NULL);
  39 
  40 struct device *soc_device_to_device(struct soc_device *soc_dev)
  41 {
  42         return &soc_dev->dev;
  43 }
  44 
  45 static umode_t soc_attribute_mode(struct kobject *kobj,
  46                                 struct attribute *attr,
  47                                 int index)
  48 {
  49         struct device *dev = container_of(kobj, struct device, kobj);
  50         struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
  51 
  52         if ((attr == &dev_attr_machine.attr)
  53             && (soc_dev->attr->machine != NULL))
  54                 return attr->mode;
  55         if ((attr == &dev_attr_family.attr)
  56             && (soc_dev->attr->family != NULL))
  57                 return attr->mode;
  58         if ((attr == &dev_attr_revision.attr)
  59             && (soc_dev->attr->revision != NULL))
  60                 return attr->mode;
  61         if ((attr == &dev_attr_serial_number.attr)
  62             && (soc_dev->attr->serial_number != NULL))
  63                 return attr->mode;
  64         if ((attr == &dev_attr_soc_id.attr)
  65             && (soc_dev->attr->soc_id != NULL))
  66                 return attr->mode;
  67 
  68         /* Unknown or unfilled attribute. */
  69         return 0;
  70 }
  71 
  72 static ssize_t soc_info_get(struct device *dev,
  73                             struct device_attribute *attr,
  74                             char *buf)
  75 {
  76         struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
  77 
  78         if (attr == &dev_attr_machine)
  79                 return sprintf(buf, "%s\n", soc_dev->attr->machine);
  80         if (attr == &dev_attr_family)
  81                 return sprintf(buf, "%s\n", soc_dev->attr->family);
  82         if (attr == &dev_attr_revision)
  83                 return sprintf(buf, "%s\n", soc_dev->attr->revision);
  84         if (attr == &dev_attr_serial_number)
  85                 return sprintf(buf, "%s\n", soc_dev->attr->serial_number);
  86         if (attr == &dev_attr_soc_id)
  87                 return sprintf(buf, "%s\n", soc_dev->attr->soc_id);
  88 
  89         return -EINVAL;
  90 
  91 }
  92 
  93 static struct attribute *soc_attr[] = {
  94         &dev_attr_machine.attr,
  95         &dev_attr_family.attr,
  96         &dev_attr_serial_number.attr,
  97         &dev_attr_soc_id.attr,
  98         &dev_attr_revision.attr,
  99         NULL,
 100 };
 101 
 102 static const struct attribute_group soc_attr_group = {
 103         .attrs = soc_attr,
 104         .is_visible = soc_attribute_mode,
 105 };
 106 
 107 static const struct attribute_group *soc_attr_groups[] = {
 108         &soc_attr_group,
 109         NULL,
 110 };
 111 
 112 static void soc_release(struct device *dev)
 113 {
 114         struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
 115 
 116         kfree(soc_dev);
 117 }
 118 
 119 static struct soc_device_attribute *early_soc_dev_attr;
 120 
 121 struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr)
 122 {
 123         struct soc_device *soc_dev;
 124         int ret;
 125 
 126         if (!soc_bus_type.p) {
 127                 if (early_soc_dev_attr)
 128                         return ERR_PTR(-EBUSY);
 129                 early_soc_dev_attr = soc_dev_attr;
 130                 return NULL;
 131         }
 132 
 133         soc_dev = kzalloc(sizeof(*soc_dev), GFP_KERNEL);
 134         if (!soc_dev) {
 135                 ret = -ENOMEM;
 136                 goto out1;
 137         }
 138 
 139         /* Fetch a unique (reclaimable) SOC ID. */
 140         ret = ida_simple_get(&soc_ida, 0, 0, GFP_KERNEL);
 141         if (ret < 0)
 142                 goto out2;
 143         soc_dev->soc_dev_num = ret;
 144 
 145         soc_dev->attr = soc_dev_attr;
 146         soc_dev->dev.bus = &soc_bus_type;
 147         soc_dev->dev.groups = soc_attr_groups;
 148         soc_dev->dev.release = soc_release;
 149 
 150         dev_set_name(&soc_dev->dev, "soc%d", soc_dev->soc_dev_num);
 151 
 152         ret = device_register(&soc_dev->dev);
 153         if (ret)
 154                 goto out3;
 155 
 156         return soc_dev;
 157 
 158 out3:
 159         ida_simple_remove(&soc_ida, soc_dev->soc_dev_num);
 160         put_device(&soc_dev->dev);
 161         soc_dev = NULL;
 162 out2:
 163         kfree(soc_dev);
 164 out1:
 165         return ERR_PTR(ret);
 166 }
 167 EXPORT_SYMBOL_GPL(soc_device_register);
 168 
 169 /* Ensure soc_dev->attr is freed prior to calling soc_device_unregister. */
 170 void soc_device_unregister(struct soc_device *soc_dev)
 171 {
 172         ida_simple_remove(&soc_ida, soc_dev->soc_dev_num);
 173 
 174         device_unregister(&soc_dev->dev);
 175         early_soc_dev_attr = NULL;
 176 }
 177 EXPORT_SYMBOL_GPL(soc_device_unregister);
 178 
 179 static int __init soc_bus_register(void)
 180 {
 181         int ret;
 182 
 183         ret = bus_register(&soc_bus_type);
 184         if (ret)
 185                 return ret;
 186 
 187         if (early_soc_dev_attr)
 188                 return PTR_ERR(soc_device_register(early_soc_dev_attr));
 189 
 190         return 0;
 191 }
 192 core_initcall(soc_bus_register);
 193 
 194 static int soc_device_match_attr(const struct soc_device_attribute *attr,
 195                                  const struct soc_device_attribute *match)
 196 {
 197         if (match->machine &&
 198             (!attr->machine || !glob_match(match->machine, attr->machine)))
 199                 return 0;
 200 
 201         if (match->family &&
 202             (!attr->family || !glob_match(match->family, attr->family)))
 203                 return 0;
 204 
 205         if (match->revision &&
 206             (!attr->revision || !glob_match(match->revision, attr->revision)))
 207                 return 0;
 208 
 209         if (match->soc_id &&
 210             (!attr->soc_id || !glob_match(match->soc_id, attr->soc_id)))
 211                 return 0;
 212 
 213         return 1;
 214 }
 215 
 216 static int soc_device_match_one(struct device *dev, void *arg)
 217 {
 218         struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
 219 
 220         return soc_device_match_attr(soc_dev->attr, arg);
 221 }
 222 
 223 /*
 224  * soc_device_match - identify the SoC in the machine
 225  * @matches: zero-terminated array of possible matches
 226  *
 227  * returns the first matching entry of the argument array, or NULL
 228  * if none of them match.
 229  *
 230  * This function is meant as a helper in place of of_match_node()
 231  * in cases where either no device tree is available or the information
 232  * in a device node is insufficient to identify a particular variant
 233  * by its compatible strings or other properties. For new devices,
 234  * the DT binding should always provide unique compatible strings
 235  * that allow the use of of_match_node() instead.
 236  *
 237  * The calling function can use the .data entry of the
 238  * soc_device_attribute to pass a structure or function pointer for
 239  * each entry.
 240  */
 241 const struct soc_device_attribute *soc_device_match(
 242         const struct soc_device_attribute *matches)
 243 {
 244         int ret = 0;
 245 
 246         if (!matches)
 247                 return NULL;
 248 
 249         while (!ret) {
 250                 if (!(matches->machine || matches->family ||
 251                       matches->revision || matches->soc_id))
 252                         break;
 253                 ret = bus_for_each_dev(&soc_bus_type, NULL, (void *)matches,
 254                                        soc_device_match_one);
 255                 if (ret < 0 && early_soc_dev_attr)
 256                         ret = soc_device_match_attr(early_soc_dev_attr,
 257                                                     matches);
 258                 if (ret < 0)
 259                         return NULL;
 260                 if (!ret)
 261                         matches++;
 262                 else
 263                         return matches;
 264         }
 265         return NULL;
 266 }
 267 EXPORT_SYMBOL_GPL(soc_device_match);

/* [<][>][^][v][top][bottom][index][help] */