static int stih_cec_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct resource *res; struct stih_cec *cec; int ret; cec = devm_kzalloc(dev, sizeof(*cec), GFP_KERNEL); if (!cec) return -ENOMEM; cec->dev = dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); cec->regs = devm_ioremap_resource(dev, res); if (IS_ERR(cec->regs)) return PTR_ERR(cec->regs); cec->irq = platform_get_irq(pdev, 0); if (cec->irq < 0) return cec->irq; ret = devm_request_threaded_irq(dev, cec->irq, stih_cec_irq_handler, stih_cec_irq_handler_thread, 0, pdev->name, cec); if (ret) return ret; cec->clk = devm_clk_get(dev, "cec-clk"); if (IS_ERR(cec->clk)) { dev_err(dev, "Cannot get cec clock\n"); return PTR_ERR(cec->clk); } cec->adap = cec_allocate_adapter(&sti_cec_adap_ops, cec, CEC_NAME, CEC_CAP_LOG_ADDRS | CEC_CAP_PASSTHROUGH | CEC_CAP_PHYS_ADDR | CEC_CAP_TRANSMIT, 1, &pdev->dev); ret = PTR_ERR_OR_ZERO(cec->adap); if (ret) return ret; ret = cec_register_adapter(cec->adap); if (ret) { cec_delete_adapter(cec->adap); return ret; } platform_set_drvdata(pdev, cec); return 0; }
static int cros_ec_cec_probe(struct platform_device *pdev) { struct cros_ec_dev *ec_dev = dev_get_drvdata(pdev->dev.parent); struct cros_ec_device *cros_ec = ec_dev->ec_dev; struct cros_ec_cec *cros_ec_cec; int ret; cros_ec_cec = devm_kzalloc(&pdev->dev, sizeof(*cros_ec_cec), GFP_KERNEL); if (!cros_ec_cec) return -ENOMEM; platform_set_drvdata(pdev, cros_ec_cec); cros_ec_cec->cros_ec = cros_ec; ret = cros_ec_cec_get_notifier(&pdev->dev, &cros_ec_cec->notify); if (ret) return ret; ret = device_init_wakeup(&pdev->dev, 1); if (ret) { dev_err(&pdev->dev, "failed to initialize wakeup\n"); return ret; } cros_ec_cec->adap = cec_allocate_adapter(&cros_ec_cec_ops, cros_ec_cec, DRV_NAME, CEC_CAP_DEFAULTS, 1); if (IS_ERR(cros_ec_cec->adap)) return PTR_ERR(cros_ec_cec->adap); /* Get CEC events from the EC. */ cros_ec_cec->notifier.notifier_call = cros_ec_cec_event; ret = blocking_notifier_chain_register(&cros_ec->event_notifier, &cros_ec_cec->notifier); if (ret) { dev_err(&pdev->dev, "failed to register notifier\n"); cec_delete_adapter(cros_ec_cec->adap); return ret; } ret = cec_register_adapter(cros_ec_cec->adap, &pdev->dev); if (ret < 0) { cec_delete_adapter(cros_ec_cec->adap); return ret; } cec_register_cec_notifier(cros_ec_cec->adap, cros_ec_cec->notify); return 0; }
static int rain_connect(struct serio *serio, struct serio_driver *drv) { u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_PHYS_ADDR | CEC_CAP_MONITOR_ALL; struct rain *rain; int err = -ENOMEM; struct cec_log_addrs log_addrs = {}; u16 pa = CEC_PHYS_ADDR_INVALID; rain = kzalloc(sizeof(*rain), GFP_KERNEL); if (!rain) return -ENOMEM; rain->serio = serio; rain->adap = cec_allocate_adapter(&rain_cec_adap_ops, rain, dev_name(&serio->dev), caps, 1); err = PTR_ERR_OR_ZERO(rain->adap); if (err < 0) goto free_device; rain->dev = &serio->dev; serio_set_drvdata(serio, rain); INIT_WORK(&rain->work, rain_irq_work_handler); mutex_init(&rain->write_lock); spin_lock_init(&rain->buf_lock); err = serio_open(serio, drv); if (err) goto delete_adap; err = rain_setup(rain, serio, &log_addrs, &pa); if (err) goto close_serio; err = cec_register_adapter(rain->adap, &serio->dev); if (err < 0) goto close_serio; rain->dev = &rain->adap->devnode.dev; return 0; close_serio: serio_close(serio); delete_adap: cec_delete_adapter(rain->adap); serio_set_drvdata(serio, NULL); free_device: kfree(rain); return err; }
static int sun4i_hdmi_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); struct drm_device *drm = data; struct sun4i_drv *drv = drm->dev_private; struct sun4i_hdmi *hdmi; struct resource *res; u32 reg; int ret; hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); if (!hdmi) return -ENOMEM; dev_set_drvdata(dev, hdmi); hdmi->dev = dev; hdmi->drv = drv; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); hdmi->base = devm_ioremap_resource(dev, res); if (IS_ERR(hdmi->base)) { dev_err(dev, "Couldn't map the HDMI encoder registers\n"); return PTR_ERR(hdmi->base); } hdmi->bus_clk = devm_clk_get(dev, "ahb"); if (IS_ERR(hdmi->bus_clk)) { dev_err(dev, "Couldn't get the HDMI bus clock\n"); return PTR_ERR(hdmi->bus_clk); } clk_prepare_enable(hdmi->bus_clk); hdmi->mod_clk = devm_clk_get(dev, "mod"); if (IS_ERR(hdmi->mod_clk)) { dev_err(dev, "Couldn't get the HDMI mod clock\n"); ret = PTR_ERR(hdmi->mod_clk); goto err_disable_bus_clk; } clk_prepare_enable(hdmi->mod_clk); hdmi->pll0_clk = devm_clk_get(dev, "pll-0"); if (IS_ERR(hdmi->pll0_clk)) { dev_err(dev, "Couldn't get the HDMI PLL 0 clock\n"); ret = PTR_ERR(hdmi->pll0_clk); goto err_disable_mod_clk; } hdmi->pll1_clk = devm_clk_get(dev, "pll-1"); if (IS_ERR(hdmi->pll1_clk)) { dev_err(dev, "Couldn't get the HDMI PLL 1 clock\n"); ret = PTR_ERR(hdmi->pll1_clk); goto err_disable_mod_clk; } ret = sun4i_tmds_create(hdmi); if (ret) { dev_err(dev, "Couldn't create the TMDS clock\n"); goto err_disable_mod_clk; } writel(SUN4I_HDMI_CTRL_ENABLE, hdmi->base + SUN4I_HDMI_CTRL_REG); writel(SUN4I_HDMI_PAD_CTRL0_TXEN | SUN4I_HDMI_PAD_CTRL0_CKEN | SUN4I_HDMI_PAD_CTRL0_PWENG | SUN4I_HDMI_PAD_CTRL0_PWEND | SUN4I_HDMI_PAD_CTRL0_PWENC | SUN4I_HDMI_PAD_CTRL0_LDODEN | SUN4I_HDMI_PAD_CTRL0_LDOCEN | SUN4I_HDMI_PAD_CTRL0_BIASEN, hdmi->base + SUN4I_HDMI_PAD_CTRL0_REG); /* * We can't just initialize the register there, we need to * protect the clock bits that have already been read out and * cached by the clock framework. */ reg = readl(hdmi->base + SUN4I_HDMI_PAD_CTRL1_REG); reg &= SUN4I_HDMI_PAD_CTRL1_HALVE_CLK; reg |= SUN4I_HDMI_PAD_CTRL1_REG_AMP(6) | SUN4I_HDMI_PAD_CTRL1_REG_EMP(2) | SUN4I_HDMI_PAD_CTRL1_REG_DENCK | SUN4I_HDMI_PAD_CTRL1_REG_DEN | SUN4I_HDMI_PAD_CTRL1_EMPCK_OPT | SUN4I_HDMI_PAD_CTRL1_EMP_OPT | SUN4I_HDMI_PAD_CTRL1_AMPCK_OPT | SUN4I_HDMI_PAD_CTRL1_AMP_OPT; writel(reg, hdmi->base + SUN4I_HDMI_PAD_CTRL1_REG); reg = readl(hdmi->base + SUN4I_HDMI_PLL_CTRL_REG); reg &= SUN4I_HDMI_PLL_CTRL_DIV_MASK; reg |= SUN4I_HDMI_PLL_CTRL_VCO_S(8) | SUN4I_HDMI_PLL_CTRL_CS(7) | SUN4I_HDMI_PLL_CTRL_CP_S(15) | SUN4I_HDMI_PLL_CTRL_S(7) | SUN4I_HDMI_PLL_CTRL_VCO_GAIN(4) | SUN4I_HDMI_PLL_CTRL_SDIV2 | SUN4I_HDMI_PLL_CTRL_LDO2_EN | SUN4I_HDMI_PLL_CTRL_LDO1_EN | SUN4I_HDMI_PLL_CTRL_HV_IS_33 | SUN4I_HDMI_PLL_CTRL_BWS | SUN4I_HDMI_PLL_CTRL_PLL_EN; writel(reg, hdmi->base + SUN4I_HDMI_PLL_CTRL_REG); ret = sun4i_hdmi_i2c_create(dev, hdmi); if (ret) { dev_err(dev, "Couldn't create the HDMI I2C adapter\n"); goto err_disable_mod_clk; } drm_encoder_helper_add(&hdmi->encoder, &sun4i_hdmi_helper_funcs); ret = drm_encoder_init(drm, &hdmi->encoder, &sun4i_hdmi_funcs, DRM_MODE_ENCODER_TMDS, NULL); if (ret) { dev_err(dev, "Couldn't initialise the HDMI encoder\n"); goto err_del_i2c_adapter; } hdmi->encoder.possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); if (!hdmi->encoder.possible_crtcs) { ret = -EPROBE_DEFER; goto err_del_i2c_adapter; } #ifdef CONFIG_DRM_SUN4I_HDMI_CEC hdmi->cec_adap = cec_pin_allocate_adapter(&sun4i_hdmi_cec_pin_ops, hdmi, "sun4i", CEC_CAP_TRANSMIT | CEC_CAP_LOG_ADDRS | CEC_CAP_PASSTHROUGH | CEC_CAP_RC); ret = PTR_ERR_OR_ZERO(hdmi->cec_adap); if (ret < 0) goto err_cleanup_connector; writel(readl(hdmi->base + SUN4I_HDMI_CEC) & ~SUN4I_HDMI_CEC_TX, hdmi->base + SUN4I_HDMI_CEC); #endif drm_connector_helper_add(&hdmi->connector, &sun4i_hdmi_connector_helper_funcs); ret = drm_connector_init(drm, &hdmi->connector, &sun4i_hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA); if (ret) { dev_err(dev, "Couldn't initialise the HDMI connector\n"); goto err_cleanup_connector; } /* There is no HPD interrupt, so we need to poll the controller */ hdmi->connector.polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; ret = cec_register_adapter(hdmi->cec_adap, dev); if (ret < 0) goto err_cleanup_connector; drm_mode_connector_attach_encoder(&hdmi->connector, &hdmi->encoder); return 0; err_cleanup_connector: cec_delete_adapter(hdmi->cec_adap); drm_encoder_cleanup(&hdmi->encoder); err_del_i2c_adapter: i2c_del_adapter(hdmi->i2c); err_disable_mod_clk: clk_disable_unprepare(hdmi->mod_clk); err_disable_bus_clk: clk_disable_unprepare(hdmi->bus_clk); return ret; }
/* * A new EDID is set. If there is no CEC adapter, then create one. If * there was a CEC adapter, then check if the CEC adapter properties * were unchanged and just update the CEC physical address. Otherwise * unregister the old CEC adapter and create a new one. */ void drm_dp_cec_set_edid(struct drm_dp_aux *aux, const struct edid *edid) { u32 cec_caps = CEC_CAP_DEFAULTS | CEC_CAP_NEEDS_HPD; unsigned int num_las = 1; u8 cap; /* No transfer function was set, so not a DP connector */ if (!aux->transfer) return; #ifndef CONFIG_MEDIA_CEC_RC /* * CEC_CAP_RC is part of CEC_CAP_DEFAULTS, but it is stripped by * cec_allocate_adapter() if CONFIG_MEDIA_CEC_RC is undefined. * * Do this here as well to ensure the tests against cec_caps are * correct. */ cec_caps &= ~CEC_CAP_RC; #endif cancel_delayed_work_sync(&aux->cec.unregister_work); mutex_lock(&aux->cec.lock); if (!drm_dp_cec_cap(aux, &cap)) { /* CEC is not supported, unregister any existing adapter */ cec_unregister_adapter(aux->cec.adap); aux->cec.adap = NULL; goto unlock; } if (cap & DP_CEC_SNOOPING_CAPABLE) cec_caps |= CEC_CAP_MONITOR_ALL; if (cap & DP_CEC_MULTIPLE_LA_CAPABLE) num_las = CEC_MAX_LOG_ADDRS; if (aux->cec.adap) { if (aux->cec.adap->capabilities == cec_caps && aux->cec.adap->available_log_addrs == num_las) { /* Unchanged, so just set the phys addr */ cec_s_phys_addr_from_edid(aux->cec.adap, edid); goto unlock; } /* * The capabilities changed, so unregister the old * adapter first. */ cec_unregister_adapter(aux->cec.adap); } /* Create a new adapter */ aux->cec.adap = cec_allocate_adapter(&drm_dp_cec_adap_ops, aux, aux->cec.name, cec_caps, num_las); if (IS_ERR(aux->cec.adap)) { aux->cec.adap = NULL; goto unlock; } if (cec_register_adapter(aux->cec.adap, aux->cec.parent)) { cec_delete_adapter(aux->cec.adap); aux->cec.adap = NULL; } else { /* * Update the phys addr for the new CEC adapter. When called * from drm_dp_cec_register_connector() edid == NULL, so in * that case the phys addr is just invalidated. */ cec_s_phys_addr_from_edid(aux->cec.adap, edid); } unlock: mutex_unlock(&aux->cec.lock); }
static int meson_ao_cec_probe(struct platform_device *pdev) { struct meson_ao_cec_device *ao_cec; struct device *hdmi_dev; struct resource *res; int ret, irq; hdmi_dev = cec_notifier_parse_hdmi_phandle(&pdev->dev); if (IS_ERR(hdmi_dev)) return PTR_ERR(hdmi_dev); ao_cec = devm_kzalloc(&pdev->dev, sizeof(*ao_cec), GFP_KERNEL); if (!ao_cec) return -ENOMEM; spin_lock_init(&ao_cec->cec_reg_lock); ao_cec->notify = cec_notifier_get(hdmi_dev); if (!ao_cec->notify) return -ENOMEM; ao_cec->adap = cec_allocate_adapter(&meson_ao_cec_ops, ao_cec, "meson_ao_cec", CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT | CEC_CAP_RC | CEC_CAP_PASSTHROUGH, 1); /* Use 1 for now */ if (IS_ERR(ao_cec->adap)) { ret = PTR_ERR(ao_cec->adap); goto out_probe_notify; } ao_cec->adap->owner = THIS_MODULE; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ao_cec->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(ao_cec->base)) { ret = PTR_ERR(ao_cec->base); goto out_probe_adapter; } irq = platform_get_irq(pdev, 0); ret = devm_request_threaded_irq(&pdev->dev, irq, meson_ao_cec_irq, meson_ao_cec_irq_thread, 0, NULL, ao_cec); if (ret) { dev_err(&pdev->dev, "irq request failed\n"); goto out_probe_adapter; } ao_cec->core = devm_clk_get(&pdev->dev, "core"); if (IS_ERR(ao_cec->core)) { dev_err(&pdev->dev, "core clock request failed\n"); ret = PTR_ERR(ao_cec->core); goto out_probe_adapter; } ret = clk_prepare_enable(ao_cec->core); if (ret) { dev_err(&pdev->dev, "core clock enable failed\n"); goto out_probe_adapter; } ret = clk_set_rate(ao_cec->core, CEC_CLK_RATE); if (ret) { dev_err(&pdev->dev, "core clock set rate failed\n"); goto out_probe_clk; } device_reset_optional(&pdev->dev); ao_cec->pdev = pdev; platform_set_drvdata(pdev, ao_cec); ret = cec_register_adapter(ao_cec->adap, &pdev->dev); if (ret < 0) { cec_notifier_put(ao_cec->notify); goto out_probe_clk; } /* Setup Hardware */ writel_relaxed(CEC_GEN_CNTL_RESET, ao_cec->base + CEC_GEN_CNTL_REG); cec_register_cec_notifier(ao_cec->adap, ao_cec->notify); return 0; out_probe_clk: clk_disable_unprepare(ao_cec->core); out_probe_adapter: cec_delete_adapter(ao_cec->adap); out_probe_notify: cec_notifier_put(ao_cec->notify); dev_err(&pdev->dev, "CEC controller registration failed\n"); return ret; }
static int tegra_cec_probe(struct platform_device *pdev) { struct platform_device *hdmi_dev; struct device_node *np; struct tegra_cec *cec; struct resource *res; int ret = 0; np = of_parse_phandle(pdev->dev.of_node, "hdmi-phandle", 0); if (!np) { dev_err(&pdev->dev, "Failed to find hdmi node in device tree\n"); return -ENODEV; } hdmi_dev = of_find_device_by_node(np); if (hdmi_dev == NULL) return -EPROBE_DEFER; cec = devm_kzalloc(&pdev->dev, sizeof(struct tegra_cec), GFP_KERNEL); if (!cec) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "Unable to allocate resources for device\n"); return -EBUSY; } if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res), pdev->name)) { dev_err(&pdev->dev, "Unable to request mem region for device\n"); return -EBUSY; } cec->tegra_cec_irq = platform_get_irq(pdev, 0); if (cec->tegra_cec_irq <= 0) return -EBUSY; cec->cec_base = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res)); if (!cec->cec_base) { dev_err(&pdev->dev, "Unable to grab IOs for device\n"); return -EBUSY; } cec->clk = devm_clk_get(&pdev->dev, "cec"); if (IS_ERR_OR_NULL(cec->clk)) { dev_err(&pdev->dev, "Can't get clock for CEC\n"); return -ENOENT; } clk_prepare_enable(cec->clk); /* set context info. */ cec->dev = &pdev->dev; platform_set_drvdata(pdev, cec); ret = devm_request_threaded_irq(&pdev->dev, cec->tegra_cec_irq, tegra_cec_irq_handler, tegra_cec_irq_thread_handler, 0, "cec_irq", &pdev->dev); if (ret) { dev_err(&pdev->dev, "Unable to request interrupt for device\n"); goto clk_error; } cec->notifier = cec_notifier_get(&hdmi_dev->dev); if (!cec->notifier) { ret = -ENOMEM; goto clk_error; } cec->adap = cec_allocate_adapter(&tegra_cec_ops, cec, TEGRA_CEC_NAME, CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL, CEC_MAX_LOG_ADDRS); if (IS_ERR(cec->adap)) { ret = -ENOMEM; dev_err(&pdev->dev, "Couldn't create cec adapter\n"); goto cec_error; } ret = cec_register_adapter(cec->adap, &pdev->dev); if (ret) { dev_err(&pdev->dev, "Couldn't register device\n"); goto cec_error; } cec_register_cec_notifier(cec->adap, cec->notifier); return 0; cec_error: if (cec->notifier) cec_notifier_put(cec->notifier); cec_delete_adapter(cec->adap); clk_error: clk_disable_unprepare(cec->clk); return ret; }
static int s5p_cec_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np; struct platform_device *hdmi_dev; struct resource *res; struct s5p_cec_dev *cec; int ret; np = of_parse_phandle(pdev->dev.of_node, "hdmi-phandle", 0); if (!np) { dev_err(&pdev->dev, "Failed to find hdmi node in device tree\n"); return -ENODEV; } hdmi_dev = of_find_device_by_node(np); if (hdmi_dev == NULL) return -EPROBE_DEFER; cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL); if (!cec) return -ENOMEM; cec->dev = dev; cec->irq = platform_get_irq(pdev, 0); if (cec->irq < 0) return cec->irq; ret = devm_request_threaded_irq(dev, cec->irq, s5p_cec_irq_handler, s5p_cec_irq_handler_thread, 0, pdev->name, cec); if (ret) return ret; cec->clk = devm_clk_get(dev, "hdmicec"); if (IS_ERR(cec->clk)) return PTR_ERR(cec->clk); cec->pmu = syscon_regmap_lookup_by_phandle(dev->of_node, "samsung,syscon-phandle"); if (IS_ERR(cec->pmu)) return -EPROBE_DEFER; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); cec->reg = devm_ioremap_resource(dev, res); if (IS_ERR(cec->reg)) return PTR_ERR(cec->reg); cec->notifier = cec_notifier_get(&hdmi_dev->dev); if (cec->notifier == NULL) return -ENOMEM; cec->adap = cec_allocate_adapter(&s5p_cec_adap_ops, cec, CEC_NAME, CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT | CEC_CAP_PASSTHROUGH | CEC_CAP_RC, 1); ret = PTR_ERR_OR_ZERO(cec->adap); if (ret) return ret; ret = cec_register_adapter(cec->adap, &pdev->dev); if (ret) goto err_delete_adapter; cec_register_cec_notifier(cec->adap, cec->notifier); platform_set_drvdata(pdev, cec); pm_runtime_enable(dev); dev_dbg(dev, "successfuly probed\n"); return 0; err_delete_adapter: cec_delete_adapter(cec->adap); return ret; }