|
@@ -1,8 +1,8 @@
|
|
|
/*
|
|
|
* Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver
|
|
|
*
|
|
|
- * Copyright (C) 2011 Samsung Electronics Co., Ltd.
|
|
|
- * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com>
|
|
|
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd.
|
|
|
+ * Sylwester Nawrocki, <s.nawrocki@samsung.com>
|
|
|
*
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
@@ -100,7 +100,6 @@ enum {
|
|
|
* @pads: CSIS pads array
|
|
|
* @sd: v4l2_subdev associated with CSIS device instance
|
|
|
* @pdev: CSIS platform device
|
|
|
- * @regs_res: requested I/O register memory resource
|
|
|
* @regs: mmaped I/O registers memory
|
|
|
* @clock: CSIS clocks
|
|
|
* @irq: requested s5p-mipi-csis irq number
|
|
@@ -113,7 +112,6 @@ struct csis_state {
|
|
|
struct media_pad pads[CSIS_PADS_NUM];
|
|
|
struct v4l2_subdev sd;
|
|
|
struct platform_device *pdev;
|
|
|
- struct resource *regs_res;
|
|
|
void __iomem *regs;
|
|
|
struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES];
|
|
|
struct clk *clock[NUM_CSIS_CLOCKS];
|
|
@@ -490,12 +488,11 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev)
|
|
|
{
|
|
|
struct s5p_platform_mipi_csis *pdata;
|
|
|
struct resource *mem_res;
|
|
|
- struct resource *regs_res;
|
|
|
struct csis_state *state;
|
|
|
int ret = -ENOMEM;
|
|
|
int i;
|
|
|
|
|
|
- state = kzalloc(sizeof(*state), GFP_KERNEL);
|
|
|
+ state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL);
|
|
|
if (!state)
|
|
|
return -ENOMEM;
|
|
|
|
|
@@ -505,52 +502,27 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev)
|
|
|
pdata = pdev->dev.platform_data;
|
|
|
if (pdata == NULL || pdata->phy_enable == NULL) {
|
|
|
dev_err(&pdev->dev, "Platform data not fully specified\n");
|
|
|
- goto e_free;
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
|
|
|
if ((pdev->id == 1 && pdata->lanes > CSIS1_MAX_LANES) ||
|
|
|
pdata->lanes > CSIS0_MAX_LANES) {
|
|
|
- ret = -EINVAL;
|
|
|
dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n",
|
|
|
pdata->lanes);
|
|
|
- goto e_free;
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
|
|
|
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
|
- if (!mem_res) {
|
|
|
- dev_err(&pdev->dev, "Failed to get IO memory region\n");
|
|
|
- goto e_free;
|
|
|
- }
|
|
|
-
|
|
|
- regs_res = request_mem_region(mem_res->start, resource_size(mem_res),
|
|
|
- pdev->name);
|
|
|
- if (!regs_res) {
|
|
|
- dev_err(&pdev->dev, "Failed to request IO memory region\n");
|
|
|
- goto e_free;
|
|
|
+ state->regs = devm_request_and_ioremap(&pdev->dev, mem_res);
|
|
|
+ if (state->regs == NULL) {
|
|
|
+ dev_err(&pdev->dev, "Failed to request and remap io memory\n");
|
|
|
+ return -ENXIO;
|
|
|
}
|
|
|
- state->regs_res = regs_res;
|
|
|
-
|
|
|
- state->regs = ioremap(mem_res->start, resource_size(mem_res));
|
|
|
- if (!state->regs) {
|
|
|
- dev_err(&pdev->dev, "Failed to remap IO region\n");
|
|
|
- goto e_reqmem;
|
|
|
- }
|
|
|
-
|
|
|
- ret = s5pcsis_clk_get(state);
|
|
|
- if (ret)
|
|
|
- goto e_unmap;
|
|
|
-
|
|
|
- clk_enable(state->clock[CSIS_CLK_MUX]);
|
|
|
- if (pdata->clk_rate)
|
|
|
- clk_set_rate(state->clock[CSIS_CLK_MUX], pdata->clk_rate);
|
|
|
- else
|
|
|
- dev_WARN(&pdev->dev, "No clock frequency specified!\n");
|
|
|
|
|
|
state->irq = platform_get_irq(pdev, 0);
|
|
|
if (state->irq < 0) {
|
|
|
- ret = state->irq;
|
|
|
dev_err(&pdev->dev, "Failed to get irq\n");
|
|
|
- goto e_clkput;
|
|
|
+ return state->irq;
|
|
|
}
|
|
|
|
|
|
for (i = 0; i < CSIS_NUM_SUPPLIES; i++)
|
|
@@ -558,13 +530,23 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev)
|
|
|
|
|
|
ret = regulator_bulk_get(&pdev->dev, CSIS_NUM_SUPPLIES,
|
|
|
state->supplies);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ ret = s5pcsis_clk_get(state);
|
|
|
if (ret)
|
|
|
goto e_clkput;
|
|
|
|
|
|
- ret = request_irq(state->irq, s5pcsis_irq_handler, 0,
|
|
|
- dev_name(&pdev->dev), state);
|
|
|
+ clk_enable(state->clock[CSIS_CLK_MUX]);
|
|
|
+ if (pdata->clk_rate)
|
|
|
+ clk_set_rate(state->clock[CSIS_CLK_MUX], pdata->clk_rate);
|
|
|
+ else
|
|
|
+ dev_WARN(&pdev->dev, "No clock frequency specified!\n");
|
|
|
+
|
|
|
+ ret = devm_request_irq(&pdev->dev, state->irq, s5pcsis_irq_handler,
|
|
|
+ 0, dev_name(&pdev->dev), state);
|
|
|
if (ret) {
|
|
|
- dev_err(&pdev->dev, "request_irq failed\n");
|
|
|
+ dev_err(&pdev->dev, "Interrupt request failed\n");
|
|
|
goto e_regput;
|
|
|
}
|
|
|
|
|
@@ -583,7 +565,7 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev)
|
|
|
ret = media_entity_init(&state->sd.entity,
|
|
|
CSIS_PADS_NUM, state->pads, 0);
|
|
|
if (ret < 0)
|
|
|
- goto e_irqfree;
|
|
|
+ goto e_clkput;
|
|
|
|
|
|
/* This allows to retrieve the platform device id by the host driver */
|
|
|
v4l2_set_subdevdata(&state->sd, pdev);
|
|
@@ -592,22 +574,13 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev)
|
|
|
platform_set_drvdata(pdev, &state->sd);
|
|
|
|
|
|
pm_runtime_enable(&pdev->dev);
|
|
|
-
|
|
|
return 0;
|
|
|
|
|
|
-e_irqfree:
|
|
|
- free_irq(state->irq, state);
|
|
|
e_regput:
|
|
|
regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies);
|
|
|
e_clkput:
|
|
|
clk_disable(state->clock[CSIS_CLK_MUX]);
|
|
|
s5pcsis_clk_put(state);
|
|
|
-e_unmap:
|
|
|
- iounmap(state->regs);
|
|
|
-e_reqmem:
|
|
|
- release_mem_region(regs_res->start, resource_size(regs_res));
|
|
|
-e_free:
|
|
|
- kfree(state);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -709,21 +682,15 @@ static int __devexit s5pcsis_remove(struct platform_device *pdev)
|
|
|
{
|
|
|
struct v4l2_subdev *sd = platform_get_drvdata(pdev);
|
|
|
struct csis_state *state = sd_to_csis_state(sd);
|
|
|
- struct resource *res = state->regs_res;
|
|
|
|
|
|
pm_runtime_disable(&pdev->dev);
|
|
|
s5pcsis_suspend(&pdev->dev);
|
|
|
clk_disable(state->clock[CSIS_CLK_MUX]);
|
|
|
pm_runtime_set_suspended(&pdev->dev);
|
|
|
-
|
|
|
s5pcsis_clk_put(state);
|
|
|
regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies);
|
|
|
|
|
|
media_entity_cleanup(&state->sd.entity);
|
|
|
- free_irq(state->irq, state);
|
|
|
- iounmap(state->regs);
|
|
|
- release_mem_region(res->start, resource_size(res));
|
|
|
- kfree(state);
|
|
|
|
|
|
return 0;
|
|
|
}
|