static void hdmi_hpd_work_ext(struct work_struct *work) { int state; struct hdmi_device *hdev = container_of(work, struct hdmi_device, hpd_work_ext.work); state = s5p_v4l2_hpd_read_gpio(); hdmi_hpd_changed(hdev, state); }
static int __devinit hdmi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct resource *res; struct i2c_adapter *phy_adapter; struct hdmi_device *hdmi_dev = NULL; struct hdmi_driver_data *drv_data; int ret; unsigned int irq_type; dev_dbg(dev, "probe start\n"); hdmi_dev = kzalloc(sizeof(*hdmi_dev), GFP_KERNEL); if (!hdmi_dev) { dev_err(dev, "out of memory\n"); ret = -ENOMEM; goto fail; } hdmi_dev->dev = dev; ret = hdmi_resources_init(hdmi_dev); if (ret) goto fail_hdev; /* mapping HDMI registers */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(dev, "get memory resource failed.\n"); ret = -ENXIO; goto fail_init; } hdmi_dev->regs = ioremap(res->start, resource_size(res)); if (hdmi_dev->regs == NULL) { dev_err(dev, "register mapping failed.\n"); ret = -ENXIO; goto fail_hdev; } /* External hpd */ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (res == NULL) { dev_err(dev, "get external interrupt resource failed.\n"); ret = -ENXIO; goto fail_regs; } hdmi_dev->ext_irq = res->start; /* Internal hpd */ res = platform_get_resource(pdev, IORESOURCE_IRQ, 1); if (res == NULL) { dev_err(dev, "get internal interrupt resource failed.\n"); ret = -ENXIO; goto fail_regs; } hdmi_dev->int_irq = res->start; /* workqueue for HPD */ hdmi_dev->hpd_wq = create_workqueue("hdmi-hpd"); if (hdmi_dev->hpd_wq == NULL) ret = -ENXIO; INIT_WORK(&hdmi_dev->hpd_work, s5p_hpd_kobject_uevent); /* setting v4l2 name to prevent WARN_ON in v4l2_device_register */ strlcpy(hdmi_dev->v4l2_dev.name, dev_name(dev), sizeof(hdmi_dev->v4l2_dev.name)); /* passing NULL owner prevents driver from erasing drvdata */ ret = v4l2_device_register(NULL, &hdmi_dev->v4l2_dev); if (ret) { dev_err(dev, "could not register v4l2 device.\n"); goto fail_regs; } drv_data = (struct hdmi_driver_data *) platform_get_device_id(pdev)->driver_data; dev_info(dev, "hdmiphy i2c bus number = %d\n", drv_data->hdmiphy_bus); phy_adapter = i2c_get_adapter(drv_data->hdmiphy_bus); if (phy_adapter == NULL) { dev_err(dev, "adapter request failed\n"); ret = -ENXIO; goto fail_vdev; } hdmi_dev->phy_sd = v4l2_i2c_new_subdev_board(&hdmi_dev->v4l2_dev, phy_adapter, &hdmiphy_info, NULL); /* on failure or not adapter is no longer useful */ i2c_put_adapter(phy_adapter); if (hdmi_dev->phy_sd == NULL) { dev_err(dev, "missing subdev for hdmiphy\n"); ret = -ENODEV; goto fail_vdev; } /* HDMI PHY power off * HDMI PHY is on as default configuration * So, HDMI PHY must be turned off if it's not used */ clk_enable(hdmi_dev->res.hdmiphy); v4l2_subdev_call(hdmi_dev->phy_sd, core, s_power, 0); clk_disable(hdmi_dev->res.hdmiphy); pm_runtime_enable(dev); /* irq setting by TV power on/off status */ if (!pm_runtime_suspended(hdmi_dev->dev)) { hdmi_dev->curr_irq = hdmi_dev->int_irq; irq_type = 0; s5p_v4l2_int_src_hdmi_hpd(); } else { if (s5p_v4l2_hpd_read_gpio()) atomic_set(&hdmi_dev->hpd_state, HPD_HIGH); else atomic_set(&hdmi_dev->hpd_state, HPD_LOW); hdmi_dev->curr_irq = hdmi_dev->ext_irq; irq_type = IRQ_TYPE_EDGE_BOTH; s5p_v4l2_int_src_ext_hpd(); } hdmi_dev->hpd_user_checked = false; ret = request_irq(hdmi_dev->curr_irq, hdmi_irq_handler, irq_type, "hdmi", hdmi_dev); if (ret) { dev_err(dev, "request interrupt failed.\n"); goto fail_vdev; } hdmi_dev->cur_preset = HDMI_DEFAULT_PRESET; /* FIXME: missing fail preset is not supported */ hdmi_dev->cur_conf = hdmi_preset2conf(hdmi_dev->cur_preset); /* default audio configuration : enable audio */ hdmi_dev->audio_enable = 1; hdmi_dev->sample_rate = DEFAULT_SAMPLE_RATE; hdmi_dev->bits_per_sample = DEFAULT_BITS_PER_SAMPLE; hdmi_dev->audio_codec = DEFAULT_AUDIO_CODEC; /* register hdmi subdev as entity */ ret = hdmi_register_entity(hdmi_dev); if (ret) goto fail_irq; hdmi_entity_info_print(hdmi_dev); /* initialize hdcp resource */ ret = hdcp_prepare(hdmi_dev); if (ret) goto fail_irq; dev_info(dev, "probe sucessful\n"); return 0; fail_vdev: v4l2_device_unregister(&hdmi_dev->v4l2_dev); fail_irq: free_irq(hdmi_dev->curr_irq, hdmi_dev); fail_regs: iounmap(hdmi_dev->regs); fail_init: hdmi_resources_cleanup(hdmi_dev); fail_hdev: kfree(hdmi_dev); fail: dev_err(dev, "probe failed\n"); return ret; }