greybus: endo: Use a real endo id
[cascardo/linux.git] / drivers / staging / greybus / endo.c
1 /*
2  * Greybus endo code
3  *
4  * Copyright 2015 Google Inc.
5  * Copyright 2014 Linaro Ltd.
6  *
7  * Released under the GPLv2 only.
8  */
9
10 #include "greybus.h"
11
12 /* endo sysfs attributes */
13 static ssize_t serial_number_show(struct device *dev,
14                                   struct device_attribute *attr, char *buf)
15 {
16         struct gb_endo *endo = to_gb_endo(dev);
17
18         return sprintf(buf, "%s", &endo->svc.serial_number[0]);
19 }
20 static DEVICE_ATTR_RO(serial_number);
21
22 static ssize_t version_show(struct device *dev, struct device_attribute *attr,
23                             char *buf)
24 {
25         struct gb_endo *endo = to_gb_endo(dev);
26
27         return sprintf(buf, "%s", &endo->svc.version[0]);
28 }
29 static DEVICE_ATTR_RO(version);
30
31 static struct attribute *endo_attrs[] = {
32         &dev_attr_serial_number.attr,
33         &dev_attr_version.attr,
34         NULL,
35 };
36 static const struct attribute_group endo_group = {
37         .attrs = endo_attrs,
38         .name = "SVC",
39 };
40 static const struct attribute_group *endo_groups[] = {
41         &endo_group,
42         NULL,
43 };
44
45 static void greybus_endo_release(struct device *dev)
46 {
47         struct gb_endo *endo = to_gb_endo(dev);
48
49         kfree(endo);
50 }
51
52 struct device_type greybus_endo_type = {
53         .name =         "greybus_endo",
54         .release =      greybus_endo_release,
55 };
56
57
58 /*
59  * Endo "types" have different module locations, these are tables based on those
60  * types that list the module ids for the different locations.
61  *
62  * List must end with 0x00 in order to properly terminate the list.
63  */
64 static u8 endo_4755[] = {
65         0x01,
66         0x03,
67         0x05,
68         0x06,
69         0x07,
70         0x08,
71         0x0a,
72         0x0c,
73         0x0d,
74         0x0e,
75         0x00,
76 };
77
78
79 static int create_modules(struct gb_endo *endo)
80 {
81         struct gb_module *module;
82         u8 *endo_modules;
83         int i;
84
85         /* Depending on the endo type, create a bunch of different modules */
86         switch (endo->type) {
87         case 0x4755:
88                 endo_modules = &endo_4755[0];
89                 break;
90         default:
91                 dev_err(&endo->dev, "Unknown endo type 0x%04x, aborting!",
92                         endo->type);
93                 return -EINVAL;
94         }
95
96         for (i = 0; endo_modules[i] != 0x00; ++i) {
97                 module = gb_module_create(&endo->dev, endo_modules[i]);
98                 if (!module)
99                         return -EINVAL;
100         }
101
102         return 0;
103 }
104
105 struct gb_endo *gb_endo_create(struct greybus_host_device *hd)
106 {
107         struct gb_endo *endo;
108         int retval;
109
110         endo = kzalloc(sizeof(*endo), GFP_KERNEL);
111         if (!endo)
112                 return NULL;
113
114         endo->dev.parent = hd->parent;
115         endo->dev.bus = &greybus_bus_type;
116         endo->dev.type = &greybus_endo_type;
117         endo->dev.groups = endo_groups;
118         endo->dev.dma_mask = hd->parent->dma_mask;
119         device_initialize(&endo->dev);
120
121         // FIXME - determine endo "type" from the SVC
122         // Also get the version and serial number from the SVC, right now we are
123         // using "fake" numbers.
124         strcpy(&endo->svc.serial_number[0], "042");
125         strcpy(&endo->svc.version[0], "0.0");
126         endo->type = 0x4755;
127
128         dev_set_name(&endo->dev, "endo-0x%04x", endo->type);
129         retval = device_add(&endo->dev);
130         if (retval) {
131                 dev_err(hd->parent, "failed to add endo device of type 0x%04x\n",
132                         endo->type);
133                 put_device(&endo->dev);
134                 kfree(endo);
135                 return NULL;
136         }
137
138         retval = create_modules(endo);
139         if (retval) {
140                 gb_endo_remove(endo);
141                 return NULL;
142         }
143
144         return endo;
145 }
146
147 void gb_endo_remove(struct gb_endo *endo)
148 {
149         if (!endo)
150                 return;
151
152         /* remove all modules for this endo */
153         gb_module_remove_all(endo);
154
155         device_unregister(&endo->dev);
156 }
157