Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * drivers/mfd/mfd-core.c
0004  *
0005  * core MFD support
0006  * Copyright (c) 2006 Ian Molton
0007  * Copyright (c) 2007,2008 Dmitry Baryshkov
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      * MFD child device gets its ACPI handle either from the ACPI device
0093      * directly under the parent that matches the either _HID or _CID, or
0094      * _ADR or it will use the parent handle if is no ID is given.
0095      *
0096      * Note that use of _ADR is a grey area in the ACPI specification,
0097      * though at least Intel Galileo Gen 2 is using it to distinguish
0098      * the children devices.
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     /* Skip if OF node has previously been allocated to a device */
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         /* No of_reg defined - allocate first free compatible match */
0141         goto allocate_of_node;
0142 
0143     /* We only care about each node's first defined address */
0144     reg = of_get_address(np, 0, NULL, NULL);
0145     if (!reg)
0146         /* OF node does not contatin a 'reg' property to match to */
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         /* No match */
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                 /* Ignore 'disabled' devices error free */
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         /* Find out base to use */
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                 /* Unable to create mappings for IRQ ranges. */
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  * mfd_add_devices - register child devices
0331  *
0332  * @parent: Pointer to parent device.
0333  * @id:     Can be PLATFORM_DEVID_AUTO to let the Platform API take care
0334  *      of device numbering, or will be added to a device's cell_id.
0335  * @cells:  Array of (struct mfd_cell)s describing child devices.
0336  * @n_devs: Number of child devices to register.
0337  * @mem_base:   Parent register range resource for child devices.
0338  * @irq_base:   Base of the range of virtual interrupt numbers allocated for
0339  *      this MFD device. Unused if @domain is specified.
0340  * @domain: Interrupt domain to create mappings for hardware interrupts.
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  * devm_mfd_add_devices - Resource managed version of mfd_add_devices()
0415  *
0416  * Returns 0 on success or an appropriate negative error number on failure.
0417  * All child-devices of the MFD will automatically be removed when it gets
0418  * unbinded.
0419  *
0420  * @dev:    Pointer to parent device.
0421  * @id:     Can be PLATFORM_DEVID_AUTO to let the Platform API take care
0422  *      of device numbering, or will be added to a device's cell_id.
0423  * @cells:  Array of (struct mfd_cell)s describing child devices.
0424  * @n_devs: Number of child devices to register.
0425  * @mem_base:   Parent register range resource for child devices.
0426  * @irq_base:   Base of the range of virtual interrupt numbers allocated for
0427  *      this MFD device. Unused if @domain is specified.
0428  * @domain: Interrupt domain to create mappings for hardware interrupts.
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");