/** * 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 int _omap_device_notifier_call(struct notifier_block *nb, unsigned long event, void *dev) { struct platform_device *pdev = to_platform_device(dev); switch (event) { case BUS_NOTIFY_ADD_DEVICE: if (pdev->dev.of_node) omap_device_build_from_dt(pdev); break; case BUS_NOTIFY_DEL_DEVICE: if (pdev->archdata.od) omap_device_delete(pdev->archdata.od); break; } return NOTIFY_DONE; }
static int _omap_device_notifier_call(struct notifier_block *nb, unsigned long event, void *dev) { struct platform_device *pdev = to_platform_device(dev); struct omap_device *od; int err; switch (event) { case BUS_NOTIFY_REMOVED_DEVICE: if (pdev->archdata.od) omap_device_delete(pdev->archdata.od); break; case BUS_NOTIFY_UNBOUND_DRIVER: od = to_omap_device(pdev); if (od && (od->_state == OMAP_DEVICE_STATE_ENABLED)) { dev_info(dev, "enabled after unload, idling\n"); err = omap_device_idle(pdev); if (err) dev_err(dev, "failed to idle\n"); } break; case BUS_NOTIFY_BIND_DRIVER: od = to_omap_device(pdev); if (od && (od->_state == OMAP_DEVICE_STATE_ENABLED) && pm_runtime_status_suspended(dev)) { od->_driver_status = BUS_NOTIFY_BIND_DRIVER; pm_runtime_set_active(dev); } break; case BUS_NOTIFY_ADD_DEVICE: if (pdev->dev.of_node) omap_device_build_from_dt(pdev); omap_auxdata_legacy_init(dev); /* fall through */ default: od = to_omap_device(pdev); if (od) od->_driver_status = event; } return NOTIFY_DONE; }
static int _omap_device_notifier_call(struct notifier_block *nb, unsigned long event, void *dev) { struct platform_device *pdev = to_platform_device(dev); struct omap_device *od; switch (event) { case BUS_NOTIFY_DEL_DEVICE: if (pdev->archdata.od) omap_device_delete(pdev->archdata.od); break; case BUS_NOTIFY_ADD_DEVICE: if (pdev->dev.of_node) omap_device_build_from_dt(pdev); /* fall through */ default: od = to_omap_device(pdev); if (od) od->_driver_status = event; } return NOTIFY_DONE; }
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); }
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); }