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; }
static int hdmi_probe(struct platform_device *pdev) { struct s5p_hdmi_platdata *pdata = NULL; 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; dev_info(dev, "probe start\n"); hdmi_dev = devm_kzalloc(&pdev->dev, sizeof(struct hdmi_device), GFP_KERNEL); if (!hdmi_dev) { dev_err(&pdev->dev, "no memory for hdmi device\n"); return -ENOMEM; } hdmi_dev->dev = dev; hdmi_dev->pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!hdmi_dev->pdata) { dev_err(&pdev->dev, "no memory for state\n"); return -ENOMEM; } /* store platform data ptr to mixer context */ if (dev->of_node) { of_property_read_u32(dev->of_node, "ip_ver", &hdmi_dev->pdata->ip_ver); pdata = hdmi_dev->pdata; } else { hdmi_dev->pdata = dev->platform_data; pdata = hdmi_dev->pdata; } dev_info(dev, "HDMI ip version %d\n", pdata->ip_ver); /* mapping HDMI registers */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "get hdmi memory resource failed.\n"); return -ENXIO; } hdmi_dev->regs = devm_request_and_ioremap(&pdev->dev, res); if (hdmi_dev->regs == NULL) { dev_err(dev, "failed to claim register region for hdmi\n"); return -ENOENT; } /* mapping HDMIPHY_APB registers */ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (!res) { dev_err(dev, "get hdmiphy memory resource failed.\n"); return -ENXIO; } hdmi_dev->phy_regs = devm_request_and_ioremap(&pdev->dev, res); if (hdmi_dev->phy_regs == NULL) { dev_err(dev, "failed to claim register region for hdmiphy\n"); return -ENOENT; } /* Internal hpd */ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res) { dev_err(dev, "get internal interrupt resource failed.\n"); return -ENXIO; } ret = devm_request_irq(dev, res->start, hdmi_irq_handler, 0, "hdmi-int", hdmi_dev); if (ret) { dev_err(dev, "request int interrupt failed.\n"); return ret; } else { hdmi_dev->int_irq = res->start; disable_irq(hdmi_dev->int_irq); dev_info(dev, "success request hdmi-int irq\n"); } /* 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; } INIT_WORK(&hdmi_dev->hpd_work, hdmi_hpd_work); INIT_DELAYED_WORK(&hdmi_dev->hpd_work_ext, hdmi_hpd_work_ext); /* setting the clocks */ ret = hdmi_resources_init(hdmi_dev); if (ret) goto fail_vdev; /* setting the GPIO */ ret = hdmi_set_gpio(hdmi_dev); if (ret) { dev_err(dev, "failed to get GPIO\n"); goto fail_clk; } /* register the switch device for HPD */ hdmi_dev->hpd_switch.name = "hdmi"; ret = switch_dev_register(&hdmi_dev->hpd_switch); if (ret) { dev_err(dev, "request switch class failed.\n"); goto fail_gpio; } dev_info(dev, "success register switch device\n"); /* External hpd */ hdmi_dev->ext_irq = gpio_to_irq(hdmi_dev->res.gpio_hpd); ret = devm_request_irq(dev, hdmi_dev->ext_irq, hdmi_irq_handler_ext, IRQ_TYPE_EDGE_BOTH, "hdmi-ext", hdmi_dev); if (ret) { dev_err(dev, "request ext interrupt failed.\n"); goto fail_switch; } else { dev_info(dev, "success request hdmi-ext irq\n"); } mutex_init(&hdmi_dev->mutex); if (soc_is_exynos5250()) { 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_mutex; } 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_mutex; } } hdmi_dev->cur_timings = hdmi_conf[HDMI_DEFAULT_TIMINGS_IDX].dv_timings; /* FIXME: missing fail preset is not supported */ hdmi_dev->cur_conf = hdmi_conf[HDMI_DEFAULT_TIMINGS_IDX].conf; /* default audio configuration : disable audio */ hdmi_dev->audio_enable = 0; hdmi_dev->audio_channel_count = 2; hdmi_dev->sample_rate = DEFAULT_SAMPLE_RATE; hdmi_dev->color_range = HDMI_RGB709_0_255; hdmi_dev->bits_per_sample = DEFAULT_BITS_PER_SAMPLE; hdmi_dev->audio_codec = DEFAULT_AUDIO_CODEC; /* hdmi audio master clock */ ret = hdmi_get_audio_master(hdmi_dev); if (ret) { hdmi_dev->audio_master_clk = 0; dev_warn(dev, "failed to get audio master information\n"); } /* default aspect ratio is 16:9 */ hdmi_dev->aspect = HDMI_ASPECT_RATIO_16_9; /* default HDMI streaming is stoped */ hdmi_dev->streaming = HDMI_STOP; /* register hdmi subdev as entity */ ret = hdmi_register_entity(hdmi_dev); if (ret) goto fail_mutex; hdmi_entity_info_print(hdmi_dev); pm_runtime_enable(dev); /* initialize hdcp resource */ ret = hdcp_prepare(hdmi_dev); if (ret) goto fail_mutex; /* work after booting */ queue_delayed_work(system_nrt_wq, &hdmi_dev->hpd_work_ext, msecs_to_jiffies(1500)); /* TODO : Check the PHY power off is implemented at pm_domains * If not, PHY power off should be applied at here */ dev_info(dev, "probe sucessful\n"); hdmi_debugfs_init(hdmi_dev); return 0; fail_mutex: mutex_destroy(&hdmi_dev->mutex); fail_switch: switch_dev_unregister(&hdmi_dev->hpd_switch); fail_gpio: gpio_free(hdmi_dev->res.gpio_hpd); gpio_free(hdmi_dev->res.gpio_ls); gpio_free(hdmi_dev->res.gpio_dcdc); fail_clk: hdmi_resources_cleanup(hdmi_dev); fail_vdev: v4l2_device_unregister(&hdmi_dev->v4l2_dev); fail: dev_err(dev, "probe failed\n"); return ret; }