/** * omap_device_build_from_dt - build an omap_device with multiple hwmods * @pdev_name: name of the platform_device driver to use * @pdev_id: this platform_device's connection ID * @oh: ptr to the single omap_hwmod that backs this omap_device * @pdata: platform_data ptr to associate with the platform_device * @pdata_len: amount of memory pointed to by @pdata * * Function for building an omap_device already registered from device-tree * * Returns 0 or PTR_ERR() on error. */ static int omap_device_build_from_dt(struct platform_device *pdev) { struct omap_hwmod **hwmods; struct omap_device *od; struct omap_hwmod *oh; struct device_node *node = pdev->dev.of_node; const char *oh_name; int oh_cnt, i, ret = 0; oh_cnt = of_property_count_strings(node, "ti,hwmods"); if (!oh_cnt || IS_ERR_VALUE(oh_cnt)) { dev_dbg(&pdev->dev, "No 'hwmods' to build omap_device\n"); return -ENODEV; } hwmods = kzalloc(sizeof(struct omap_hwmod *) * oh_cnt, GFP_KERNEL); if (!hwmods) { ret = -ENOMEM; goto odbfd_exit; } for (i = 0; i < oh_cnt; i++) { of_property_read_string_index(node, "ti,hwmods", i, &oh_name); oh = omap_hwmod_lookup(oh_name); if (!oh) { dev_err(&pdev->dev, "Cannot lookup hwmod '%s'\n", oh_name); ret = -EINVAL; goto odbfd_exit1; } hwmods[i] = oh; } od = omap_device_alloc(pdev, hwmods, oh_cnt); if (!od) { dev_err(&pdev->dev, "Cannot allocate omap_device for :%s\n", oh_name); ret = PTR_ERR(od); goto odbfd_exit1; } /* Fix up missing resource names */ for (i = 0; i < pdev->num_resources; i++) { struct resource *r = &pdev->resource[i]; if (r->name == NULL) r->name = dev_name(&pdev->dev); } if (of_get_property(node, "ti,no_idle_on_suspend", NULL)) omap_device_disable_idle_on_suspend(pdev); pdev->dev.pm_domain = &omap_device_pm_domain; odbfd_exit1: kfree(hwmods); odbfd_exit: return ret; }
/** * omap_device_build_ss - build and register an omap_device with multiple hwmods * @pdev_name: name of the platform_device driver to use * @pdev_id: this platform_device's connection ID * @oh: ptr to the single omap_hwmod that backs this omap_device * @pdata: platform_data ptr to associate with the platform_device * @pdata_len: amount of memory pointed to by @pdata * @pm_lats: pointer to a omap_device_pm_latency array for this device * @pm_lats_cnt: ARRAY_SIZE() of @pm_lats * @is_early_device: should the device be registered as an early device or not * * Convenience function for building and registering an omap_device * subsystem record. Subsystem records consist of multiple * omap_hwmods. This function in turn builds and registers a * platform_device record. Returns an ERR_PTR() on error, or passes * along the return value of omap_device_register(). */ struct platform_device *omap_device_build_ss(const char *pdev_name, int pdev_id, struct omap_hwmod **ohs, int oh_cnt, void *pdata, int pdata_len, struct omap_device_pm_latency *pm_lats, int pm_lats_cnt, int is_early_device) { int ret = -ENOMEM; struct platform_device *pdev; struct omap_device *od; pr_debug("omap_device_build_ss: %s\n", pdev_name); if (!ohs || oh_cnt == 0 || !pdev_name) return ERR_PTR(-EINVAL); if (!pdata && pdata_len > 0) return ERR_PTR(-EINVAL); pdev = platform_device_alloc(pdev_name, pdev_id); if (!pdev) { ret = -ENOMEM; goto odbs_exit; } /* Set the dev_name early to allow dev_xxx in omap_device_alloc */ if (pdev->id != -1) dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); else dev_set_name(&pdev->dev, "%s", pdev->name); od = omap_device_alloc(pdev, ohs, oh_cnt, pm_lats, pm_lats_cnt); if (!od) goto odbs_exit1; ret = platform_device_add_data(pdev, pdata, pdata_len); if (ret) goto odbs_exit2; if (is_early_device) ret = omap_early_device_register(pdev); else ret = omap_device_register(pdev); if (ret) goto odbs_exit2; return pdev; odbs_exit2: omap_device_delete(od); odbs_exit1: platform_device_put(pdev); odbs_exit: pr_err("omap_device: %s: build failed (%d)\n", pdev_name, ret); return ERR_PTR(ret); }
static void __init omap_hsmmc_init_one(struct omap2_hsmmc_info *hsmmcinfo, int ctrl_nr) { struct omap_hwmod *oh; struct omap_hwmod *ohs[1]; struct omap_device *od; struct platform_device *pdev; char oh_name[MAX_OMAP_MMC_HWMOD_NAME_LEN]; struct omap_mmc_platform_data *mmc_data; struct omap_mmc_dev_attr *mmc_dev_attr; char *name; int res; mmc_data = kzalloc(sizeof(struct omap_mmc_platform_data), GFP_KERNEL); if (!mmc_data) { pr_err("Cannot allocate memory for mmc device!\n"); return; } res = omap_hsmmc_pdata_init(hsmmcinfo, mmc_data); if (res < 0) goto free_mmc; omap_hsmmc_mux(mmc_data, (ctrl_nr - 1)); name = "omap_hsmmc"; res = snprintf(oh_name, MAX_OMAP_MMC_HWMOD_NAME_LEN, "mmc%d", ctrl_nr); WARN(res >= MAX_OMAP_MMC_HWMOD_NAME_LEN, "String buffer overflow in MMC%d device setup\n", ctrl_nr); oh = omap_hwmod_lookup(oh_name); if (!oh) { pr_err("Could not look up %s\n", oh_name); goto free_name; } ohs[0] = oh; if (oh->dev_attr != NULL) { mmc_dev_attr = oh->dev_attr; mmc_data->controller_flags = mmc_dev_attr->flags; /* * erratum 2.1.1.128 doesn't apply if board has * a transceiver is attached */ if (hsmmcinfo->transceiver) mmc_data->controller_flags &= ~OMAP_HSMMC_BROKEN_MULTIBLOCK_READ; } pdev = platform_device_alloc(name, ctrl_nr - 1); if (!pdev) { pr_err("Could not allocate pdev for %s\n", name); goto free_name; } dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); od = omap_device_alloc(pdev, ohs, 1, NULL, 0); if (IS_ERR(od)) { pr_err("Could not allocate od for %s\n", name); goto put_pdev; } res = platform_device_add_data(pdev, mmc_data, sizeof(struct omap_mmc_platform_data)); if (res) { pr_err("Could not add pdata for %s\n", name); goto put_pdev; } hsmmcinfo->pdev = pdev; if (hsmmcinfo->deferred) goto free_mmc; res = omap_device_register(pdev); if (res) { pr_err("Could not register od for %s\n", name); goto free_od; } goto free_mmc; free_od: omap_device_delete(od); put_pdev: platform_device_put(pdev); free_name: kfree(mmc_data->slots[0].name); free_mmc: kfree(mmc_data); }
/** * omap_device_build_from_dt - build an omap_device with multiple hwmods * @pdev_name: name of the platform_device driver to use * @pdev_id: this platform_device's connection ID * @oh: ptr to the single omap_hwmod that backs this omap_device * @pdata: platform_data ptr to associate with the platform_device * @pdata_len: amount of memory pointed to by @pdata * * Function for building an omap_device already registered from device-tree * * Returns 0 or PTR_ERR() on error. */ static int omap_device_build_from_dt(struct platform_device *pdev) { struct omap_hwmod **hwmods; struct omap_device *od; struct omap_hwmod *oh; struct device_node *node = pdev->dev.of_node; const char *oh_name, *rst_name; int oh_cnt, dstr_cnt, i, ret = 0; bool device_active = false; oh_cnt = of_property_count_strings(node, "ti,hwmods"); if (oh_cnt <= 0) { dev_dbg(&pdev->dev, "No 'hwmods' to build omap_device\n"); return -ENODEV; } hwmods = kzalloc(sizeof(struct omap_hwmod *) * oh_cnt, GFP_KERNEL); if (!hwmods) { ret = -ENOMEM; goto odbfd_exit; } for (i = 0; i < oh_cnt; i++) { of_property_read_string_index(node, "ti,hwmods", i, &oh_name); oh = omap_hwmod_lookup(oh_name); if (!oh) { dev_err(&pdev->dev, "Cannot lookup hwmod '%s'\n", oh_name); ret = -EINVAL; goto odbfd_exit1; } hwmods[i] = oh; if (oh->flags & HWMOD_INIT_NO_IDLE) device_active = true; } od = omap_device_alloc(pdev, hwmods, oh_cnt); if (IS_ERR(od)) { dev_err(&pdev->dev, "Cannot allocate omap_device for :%s\n", oh_name); ret = PTR_ERR(od); goto odbfd_exit1; } /* Fix up missing resource names */ for (i = 0; i < pdev->num_resources; i++) { struct resource *r = &pdev->resource[i]; if (r->name == NULL) r->name = dev_name(&pdev->dev); } pdev->dev.pm_domain = &omap_device_pm_domain; if (device_active) { omap_device_enable(pdev); pm_runtime_set_active(&pdev->dev); } dstr_cnt = of_property_count_strings(node, "ti,deassert-hard-reset"); if (dstr_cnt > 0) { for (i = 0; i < dstr_cnt; i += 2) { of_property_read_string_index( node, "ti,deassert-hard-reset", i, &oh_name); of_property_read_string_index( node, "ti,deassert-hard-reset", i+1, &rst_name); oh = omap_hwmod_lookup(oh_name); if (!oh) { dev_warn(&pdev->dev, "Cannot parse deassert property for '%s'\n", oh_name); break; } omap_hwmod_deassert_hardreset(oh, rst_name); } } odbfd_exit1: kfree(hwmods); odbfd_exit: /* if data/we are at fault.. load up a fail handler */ if (ret) pdev->dev.pm_domain = &omap_device_fail_pm_domain; return ret; }
static void __init omap_hsmmc_init_one(struct omap2_hsmmc_info *hsmmcinfo, int ctrl_nr) { struct omap_hwmod *oh; struct omap_hwmod *ohs[1]; struct omap_device *od; struct platform_device *pdev; char oh_name[MAX_OMAP_MMC_HWMOD_NAME_LEN]; struct omap_hsmmc_platform_data *mmc_data; struct omap_hsmmc_dev_attr *mmc_dev_attr; char *name; int res; mmc_data = kzalloc(sizeof(*mmc_data), GFP_KERNEL); if (!mmc_data) return; res = omap_hsmmc_pdata_init(hsmmcinfo, mmc_data); if (res < 0) goto free_mmc; name = "omap_hsmmc"; res = snprintf(oh_name, MAX_OMAP_MMC_HWMOD_NAME_LEN, "mmc%d", ctrl_nr); WARN(res >= MAX_OMAP_MMC_HWMOD_NAME_LEN, "String buffer overflow in MMC%d device setup\n", ctrl_nr); oh = omap_hwmod_lookup(oh_name); if (!oh) { pr_err("Could not look up %s\n", oh_name); goto free_name; } ohs[0] = oh; if (oh->dev_attr != NULL) { mmc_dev_attr = oh->dev_attr; mmc_data->controller_flags = mmc_dev_attr->flags; } pdev = platform_device_alloc(name, ctrl_nr - 1); if (!pdev) { pr_err("Could not allocate pdev for %s\n", name); goto free_name; } dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); od = omap_device_alloc(pdev, ohs, 1); if (IS_ERR(od)) { pr_err("Could not allocate od for %s\n", name); goto put_pdev; } res = platform_device_add_data(pdev, mmc_data, sizeof(struct omap_hsmmc_platform_data)); if (res) { pr_err("Could not add pdata for %s\n", name); goto put_pdev; } hsmmcinfo->pdev = pdev; res = omap_device_register(pdev); if (res) { pr_err("Could not register od for %s\n", name); goto free_od; } goto free_mmc; free_od: omap_device_delete(od); put_pdev: platform_device_put(pdev); free_name: kfree(mmc_data->name); free_mmc: kfree(mmc_data); }