/*
  * 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
  * @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
        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];
 {
        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;
 
        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++)
 
        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;
        }
 
        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);
        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;
 }
 
 {
        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;
 }