0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/kernel.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/acpi.h>
0013 #include <linux/list.h>
0014 #include <linux/property.h>
0015 #include <linux/mfd/core.h>
0016 #include <linux/pm_runtime.h>
0017 #include <linux/slab.h>
0018 #include <linux/module.h>
0019 #include <linux/irqdomain.h>
0020 #include <linux/of.h>
0021 #include <linux/of_address.h>
0022 #include <linux/regulator/consumer.h>
0023
0024 static LIST_HEAD(mfd_of_node_list);
0025
0026 struct mfd_of_node_entry {
0027 struct list_head list;
0028 struct device *dev;
0029 struct device_node *np;
0030 };
0031
0032 static struct device_type mfd_dev_type = {
0033 .name = "mfd_device",
0034 };
0035
0036 int mfd_cell_enable(struct platform_device *pdev)
0037 {
0038 const struct mfd_cell *cell = mfd_get_cell(pdev);
0039
0040 if (!cell->enable) {
0041 dev_dbg(&pdev->dev, "No .enable() call-back registered\n");
0042 return 0;
0043 }
0044
0045 return cell->enable(pdev);
0046 }
0047 EXPORT_SYMBOL(mfd_cell_enable);
0048
0049 int mfd_cell_disable(struct platform_device *pdev)
0050 {
0051 const struct mfd_cell *cell = mfd_get_cell(pdev);
0052
0053 if (!cell->disable) {
0054 dev_dbg(&pdev->dev, "No .disable() call-back registered\n");
0055 return 0;
0056 }
0057
0058 return cell->disable(pdev);
0059 }
0060 EXPORT_SYMBOL(mfd_cell_disable);
0061
0062 #if IS_ENABLED(CONFIG_ACPI)
0063 struct match_ids_walk_data {
0064 struct acpi_device_id *ids;
0065 struct acpi_device *adev;
0066 };
0067
0068 static int match_device_ids(struct acpi_device *adev, void *data)
0069 {
0070 struct match_ids_walk_data *wd = data;
0071
0072 if (!acpi_match_device_ids(adev, wd->ids)) {
0073 wd->adev = adev;
0074 return 1;
0075 }
0076
0077 return 0;
0078 }
0079
0080 static void mfd_acpi_add_device(const struct mfd_cell *cell,
0081 struct platform_device *pdev)
0082 {
0083 const struct mfd_cell_acpi_match *match = cell->acpi_match;
0084 struct acpi_device *adev = NULL;
0085 struct acpi_device *parent;
0086
0087 parent = ACPI_COMPANION(pdev->dev.parent);
0088 if (!parent)
0089 return;
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100 if (match) {
0101 if (match->pnpid) {
0102 struct acpi_device_id ids[2] = {};
0103 struct match_ids_walk_data wd = {
0104 .adev = NULL,
0105 .ids = ids,
0106 };
0107
0108 strlcpy(ids[0].id, match->pnpid, sizeof(ids[0].id));
0109 acpi_dev_for_each_child(parent, match_device_ids, &wd);
0110 adev = wd.adev;
0111 } else {
0112 adev = acpi_find_child_device(parent, match->adr, false);
0113 }
0114 }
0115
0116 ACPI_COMPANION_SET(&pdev->dev, adev ?: parent);
0117 }
0118 #else
0119 static inline void mfd_acpi_add_device(const struct mfd_cell *cell,
0120 struct platform_device *pdev)
0121 {
0122 }
0123 #endif
0124
0125 static int mfd_match_of_node_to_dev(struct platform_device *pdev,
0126 struct device_node *np,
0127 const struct mfd_cell *cell)
0128 {
0129 #if IS_ENABLED(CONFIG_OF)
0130 struct mfd_of_node_entry *of_entry;
0131 const __be32 *reg;
0132 u64 of_node_addr;
0133
0134
0135 list_for_each_entry(of_entry, &mfd_of_node_list, list)
0136 if (of_entry->np == np)
0137 return -EAGAIN;
0138
0139 if (!cell->use_of_reg)
0140
0141 goto allocate_of_node;
0142
0143
0144 reg = of_get_address(np, 0, NULL, NULL);
0145 if (!reg)
0146
0147 return -EAGAIN;
0148
0149 of_node_addr = of_read_number(reg, of_n_addr_cells(np));
0150
0151 if (cell->of_reg != of_node_addr)
0152
0153 return -EAGAIN;
0154
0155 allocate_of_node:
0156 of_entry = kzalloc(sizeof(*of_entry), GFP_KERNEL);
0157 if (!of_entry)
0158 return -ENOMEM;
0159
0160 of_entry->dev = &pdev->dev;
0161 of_entry->np = np;
0162 list_add_tail(&of_entry->list, &mfd_of_node_list);
0163
0164 pdev->dev.of_node = np;
0165 pdev->dev.fwnode = &np->fwnode;
0166 #endif
0167 return 0;
0168 }
0169
0170 static int mfd_add_device(struct device *parent, int id,
0171 const struct mfd_cell *cell,
0172 struct resource *mem_base,
0173 int irq_base, struct irq_domain *domain)
0174 {
0175 struct resource *res;
0176 struct platform_device *pdev;
0177 struct device_node *np = NULL;
0178 struct mfd_of_node_entry *of_entry, *tmp;
0179 int ret = -ENOMEM;
0180 int platform_id;
0181 int r;
0182
0183 if (id == PLATFORM_DEVID_AUTO)
0184 platform_id = id;
0185 else
0186 platform_id = id + cell->id;
0187
0188 pdev = platform_device_alloc(cell->name, platform_id);
0189 if (!pdev)
0190 goto fail_alloc;
0191
0192 pdev->mfd_cell = kmemdup(cell, sizeof(*cell), GFP_KERNEL);
0193 if (!pdev->mfd_cell)
0194 goto fail_device;
0195
0196 res = kcalloc(cell->num_resources, sizeof(*res), GFP_KERNEL);
0197 if (!res)
0198 goto fail_device;
0199
0200 pdev->dev.parent = parent;
0201 pdev->dev.type = &mfd_dev_type;
0202 pdev->dev.dma_mask = parent->dma_mask;
0203 pdev->dev.dma_parms = parent->dma_parms;
0204 pdev->dev.coherent_dma_mask = parent->coherent_dma_mask;
0205
0206 ret = regulator_bulk_register_supply_alias(
0207 &pdev->dev, cell->parent_supplies,
0208 parent, cell->parent_supplies,
0209 cell->num_parent_supplies);
0210 if (ret < 0)
0211 goto fail_res;
0212
0213 if (IS_ENABLED(CONFIG_OF) && parent->of_node && cell->of_compatible) {
0214 for_each_child_of_node(parent->of_node, np) {
0215 if (of_device_is_compatible(np, cell->of_compatible)) {
0216
0217 if (!of_device_is_available(np)) {
0218 of_node_put(np);
0219 ret = 0;
0220 goto fail_alias;
0221 }
0222
0223 ret = mfd_match_of_node_to_dev(pdev, np, cell);
0224 if (ret == -EAGAIN)
0225 continue;
0226 of_node_put(np);
0227 if (ret)
0228 goto fail_alias;
0229
0230 break;
0231 }
0232 }
0233
0234 if (!pdev->dev.of_node)
0235 pr_warn("%s: Failed to locate of_node [id: %d]\n",
0236 cell->name, platform_id);
0237 }
0238
0239 mfd_acpi_add_device(cell, pdev);
0240
0241 if (cell->pdata_size) {
0242 ret = platform_device_add_data(pdev,
0243 cell->platform_data, cell->pdata_size);
0244 if (ret)
0245 goto fail_of_entry;
0246 }
0247
0248 if (cell->swnode) {
0249 ret = device_add_software_node(&pdev->dev, cell->swnode);
0250 if (ret)
0251 goto fail_of_entry;
0252 }
0253
0254 for (r = 0; r < cell->num_resources; r++) {
0255 res[r].name = cell->resources[r].name;
0256 res[r].flags = cell->resources[r].flags;
0257
0258
0259 if ((cell->resources[r].flags & IORESOURCE_MEM) && mem_base) {
0260 res[r].parent = mem_base;
0261 res[r].start = mem_base->start +
0262 cell->resources[r].start;
0263 res[r].end = mem_base->start +
0264 cell->resources[r].end;
0265 } else if (cell->resources[r].flags & IORESOURCE_IRQ) {
0266 if (domain) {
0267
0268 WARN_ON(cell->resources[r].start !=
0269 cell->resources[r].end);
0270 res[r].start = res[r].end = irq_create_mapping(
0271 domain, cell->resources[r].start);
0272 } else {
0273 res[r].start = irq_base +
0274 cell->resources[r].start;
0275 res[r].end = irq_base +
0276 cell->resources[r].end;
0277 }
0278 } else {
0279 res[r].parent = cell->resources[r].parent;
0280 res[r].start = cell->resources[r].start;
0281 res[r].end = cell->resources[r].end;
0282 }
0283
0284 if (!cell->ignore_resource_conflicts) {
0285 if (has_acpi_companion(&pdev->dev)) {
0286 ret = acpi_check_resource_conflict(&res[r]);
0287 if (ret)
0288 goto fail_res_conflict;
0289 }
0290 }
0291 }
0292
0293 ret = platform_device_add_resources(pdev, res, cell->num_resources);
0294 if (ret)
0295 goto fail_res_conflict;
0296
0297 ret = platform_device_add(pdev);
0298 if (ret)
0299 goto fail_res_conflict;
0300
0301 if (cell->pm_runtime_no_callbacks)
0302 pm_runtime_no_callbacks(&pdev->dev);
0303
0304 kfree(res);
0305
0306 return 0;
0307
0308 fail_res_conflict:
0309 if (cell->swnode)
0310 device_remove_software_node(&pdev->dev);
0311 fail_of_entry:
0312 list_for_each_entry_safe(of_entry, tmp, &mfd_of_node_list, list)
0313 if (of_entry->dev == &pdev->dev) {
0314 list_del(&of_entry->list);
0315 kfree(of_entry);
0316 }
0317 fail_alias:
0318 regulator_bulk_unregister_supply_alias(&pdev->dev,
0319 cell->parent_supplies,
0320 cell->num_parent_supplies);
0321 fail_res:
0322 kfree(res);
0323 fail_device:
0324 platform_device_put(pdev);
0325 fail_alloc:
0326 return ret;
0327 }
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342 int mfd_add_devices(struct device *parent, int id,
0343 const struct mfd_cell *cells, int n_devs,
0344 struct resource *mem_base,
0345 int irq_base, struct irq_domain *domain)
0346 {
0347 int i;
0348 int ret;
0349
0350 for (i = 0; i < n_devs; i++) {
0351 ret = mfd_add_device(parent, id, cells + i, mem_base,
0352 irq_base, domain);
0353 if (ret)
0354 goto fail;
0355 }
0356
0357 return 0;
0358
0359 fail:
0360 if (i)
0361 mfd_remove_devices(parent);
0362
0363 return ret;
0364 }
0365 EXPORT_SYMBOL(mfd_add_devices);
0366
0367 static int mfd_remove_devices_fn(struct device *dev, void *data)
0368 {
0369 struct platform_device *pdev;
0370 const struct mfd_cell *cell;
0371 int *level = data;
0372
0373 if (dev->type != &mfd_dev_type)
0374 return 0;
0375
0376 pdev = to_platform_device(dev);
0377 cell = mfd_get_cell(pdev);
0378
0379 if (level && cell->level > *level)
0380 return 0;
0381
0382 if (cell->swnode)
0383 device_remove_software_node(&pdev->dev);
0384
0385 regulator_bulk_unregister_supply_alias(dev, cell->parent_supplies,
0386 cell->num_parent_supplies);
0387
0388 platform_device_unregister(pdev);
0389 return 0;
0390 }
0391
0392 void mfd_remove_devices_late(struct device *parent)
0393 {
0394 int level = MFD_DEP_LEVEL_HIGH;
0395
0396 device_for_each_child_reverse(parent, &level, mfd_remove_devices_fn);
0397 }
0398 EXPORT_SYMBOL(mfd_remove_devices_late);
0399
0400 void mfd_remove_devices(struct device *parent)
0401 {
0402 int level = MFD_DEP_LEVEL_NORMAL;
0403
0404 device_for_each_child_reverse(parent, &level, mfd_remove_devices_fn);
0405 }
0406 EXPORT_SYMBOL(mfd_remove_devices);
0407
0408 static void devm_mfd_dev_release(struct device *dev, void *res)
0409 {
0410 mfd_remove_devices(dev);
0411 }
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430 int devm_mfd_add_devices(struct device *dev, int id,
0431 const struct mfd_cell *cells, int n_devs,
0432 struct resource *mem_base,
0433 int irq_base, struct irq_domain *domain)
0434 {
0435 struct device **ptr;
0436 int ret;
0437
0438 ptr = devres_alloc(devm_mfd_dev_release, sizeof(*ptr), GFP_KERNEL);
0439 if (!ptr)
0440 return -ENOMEM;
0441
0442 ret = mfd_add_devices(dev, id, cells, n_devs, mem_base,
0443 irq_base, domain);
0444 if (ret < 0) {
0445 devres_free(ptr);
0446 return ret;
0447 }
0448
0449 *ptr = dev;
0450 devres_add(dev, ptr);
0451
0452 return ret;
0453 }
0454 EXPORT_SYMBOL(devm_mfd_add_devices);
0455
0456 MODULE_LICENSE("GPL");
0457 MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov");