]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/mfd/kempld-core.c
Merge tag 'for_3.16/samsung-clk-fixes' of git://git.kernel.org/pub/scm/linux/kernel...
[karo-tx-linux.git] / drivers / mfd / kempld-core.c
index 07692604e119123a1f9b311b2611c5d0103daa78..f7ff0188603deac34e0c872d642efd4a775e1549 100644 (file)
@@ -86,7 +86,7 @@ enum kempld_cells {
        KEMPLD_UART,
 };
 
-static struct mfd_cell kempld_devs[] = {
+static const struct mfd_cell kempld_devs[] = {
        [KEMPLD_I2C] = {
                .name = "kempld-i2c",
        },
@@ -288,9 +288,38 @@ EXPORT_SYMBOL_GPL(kempld_release_mutex);
  */
 static int kempld_get_info(struct kempld_device_data *pld)
 {
+       int ret;
        struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
+       char major, minor;
+
+       ret = pdata->get_info(pld);
+       if (ret)
+               return ret;
+
+       /* The Kontron PLD firmware version string has the following format:
+        * Pwxy.zzzz
+        *   P:    Fixed
+        *   w:    PLD number    - 1 hex digit
+        *   x:    Major version - 1 alphanumerical digit (0-9A-V)
+        *   y:    Minor version - 1 alphanumerical digit (0-9A-V)
+        *   zzzz: Build number  - 4 zero padded hex digits */
 
-       return pdata->get_info(pld);
+       if (pld->info.major < 10)
+               major = pld->info.major + '0';
+       else
+               major = (pld->info.major - 10) + 'A';
+       if (pld->info.minor < 10)
+               minor = pld->info.minor + '0';
+       else
+               minor = (pld->info.minor - 10) + 'A';
+
+       ret = scnprintf(pld->info.version, sizeof(pld->info.version),
+                       "P%X%c%c.%04X", pld->info.number, major, minor,
+                       pld->info.buildnr);
+       if (ret < 0)
+               return ret;
+
+       return 0;
 }
 
 /*
@@ -307,9 +336,71 @@ static int kempld_register_cells(struct kempld_device_data *pld)
        return pdata->register_cells(pld);
 }
 
+static const char *kempld_get_type_string(struct kempld_device_data *pld)
+{
+       const char *version_type;
+
+       switch (pld->info.type) {
+       case 0:
+               version_type = "release";
+               break;
+       case 1:
+               version_type = "debug";
+               break;
+       case 2:
+               version_type = "custom";
+               break;
+       default:
+               version_type = "unspecified";
+               break;
+       }
+
+       return version_type;
+}
+
+static ssize_t kempld_version_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct kempld_device_data *pld = dev_get_drvdata(dev);
+
+       return scnprintf(buf, PAGE_SIZE, "%s\n", pld->info.version);
+}
+
+static ssize_t kempld_specification_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct kempld_device_data *pld = dev_get_drvdata(dev);
+
+       return scnprintf(buf, PAGE_SIZE, "%d.%d\n", pld->info.spec_major,
+                      pld->info.spec_minor);
+}
+
+static ssize_t kempld_type_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct kempld_device_data *pld = dev_get_drvdata(dev);
+
+       return scnprintf(buf, PAGE_SIZE, "%s\n", kempld_get_type_string(pld));
+}
+
+static DEVICE_ATTR(pld_version, S_IRUGO, kempld_version_show, NULL);
+static DEVICE_ATTR(pld_specification, S_IRUGO, kempld_specification_show,
+                  NULL);
+static DEVICE_ATTR(pld_type, S_IRUGO, kempld_type_show, NULL);
+
+static struct attribute *pld_attributes[] = {
+       &dev_attr_pld_version.attr,
+       &dev_attr_pld_specification.attr,
+       &dev_attr_pld_type.attr,
+       NULL
+};
+
+static const struct attribute_group pld_attr_group = {
+       .attrs = pld_attributes,
+};
+
 static int kempld_detect_device(struct kempld_device_data *pld)
 {
-       char *version_type;
        u8 index_reg;
        int ret;
 
@@ -335,27 +426,19 @@ static int kempld_detect_device(struct kempld_device_data *pld)
        if (ret)
                return ret;
 
-       switch (pld->info.type) {
-       case 0:
-               version_type = "release";
-               break;
-       case 1:
-               version_type = "debug";
-               break;
-       case 2:
-               version_type = "custom";
-               break;
-       default:
-               version_type = "unspecified";
-       }
+       dev_info(pld->dev, "Found Kontron PLD - %s (%s), spec %d.%d\n",
+                pld->info.version, kempld_get_type_string(pld),
+                pld->info.spec_major, pld->info.spec_minor);
+
+       ret = sysfs_create_group(&pld->dev->kobj, &pld_attr_group);
+       if (ret)
+               return ret;
 
-       dev_info(pld->dev, "Found Kontron PLD %d\n", pld->info.number);
-       dev_info(pld->dev, "%s version %d.%d build %d, specification %d.%d\n",
-                version_type, pld->info.major, pld->info.minor,
-                pld->info.buildnr, pld->info.spec_major,
-                pld->info.spec_minor);
+       ret = kempld_register_cells(pld);
+       if (ret)
+               sysfs_remove_group(&pld->dev->kobj, &pld_attr_group);
 
-       return kempld_register_cells(pld);
+       return ret;
 }
 
 static int kempld_probe(struct platform_device *pdev)
@@ -399,6 +482,8 @@ static int kempld_remove(struct platform_device *pdev)
        struct kempld_device_data *pld = platform_get_drvdata(pdev);
        struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
 
+       sysfs_remove_group(&pld->dev->kobj, &pld_attr_group);
+
        mfd_remove_devices(&pdev->dev);
        pdata->release_hardware_mutex(pld);