When compiled as a module, the i2c-s3c2410 driver does not
free either the IRQ or the i2c adapter it attached to the system.
As part of this fix, move to the usual kernel style
of freeing items as part of the probe error path
making the remove process easier.
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
-static void s3c24xx_i2c_free(struct s3c24xx_i2c *i2c)
-{
- if (i2c->clk != NULL && !IS_ERR(i2c->clk)) {
- clk_disable(i2c->clk);
- clk_put(i2c->clk);
- i2c->clk = NULL;
- }
-
- if (i2c->regs != NULL) {
- iounmap(i2c->regs);
- i2c->regs = NULL;
- }
-
- if (i2c->ioarea != NULL) {
- release_resource(i2c->ioarea);
- kfree(i2c->ioarea);
- i2c->ioarea = NULL;
- }
-}
-
/* s3c24xx_i2c_probe
*
* called by the bus driver when a suitable device is found
/* s3c24xx_i2c_probe
*
* called by the bus driver when a suitable device is found
if (IS_ERR(i2c->clk)) {
dev_err(&pdev->dev, "cannot get clock\n");
ret = -ENOENT;
if (IS_ERR(i2c->clk)) {
dev_err(&pdev->dev, "cannot get clock\n");
ret = -ENOENT;
}
dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);
}
dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);
if (res == NULL) {
dev_err(&pdev->dev, "cannot find IO resource\n");
ret = -ENOENT;
if (res == NULL) {
dev_err(&pdev->dev, "cannot find IO resource\n");
ret = -ENOENT;
}
i2c->ioarea = request_mem_region(res->start, (res->end-res->start)+1,
}
i2c->ioarea = request_mem_region(res->start, (res->end-res->start)+1,
if (i2c->ioarea == NULL) {
dev_err(&pdev->dev, "cannot request IO\n");
ret = -ENXIO;
if (i2c->ioarea == NULL) {
dev_err(&pdev->dev, "cannot request IO\n");
ret = -ENXIO;
}
i2c->regs = ioremap(res->start, (res->end-res->start)+1);
}
i2c->regs = ioremap(res->start, (res->end-res->start)+1);
if (i2c->regs == NULL) {
dev_err(&pdev->dev, "cannot map IO\n");
ret = -ENXIO;
if (i2c->regs == NULL) {
dev_err(&pdev->dev, "cannot map IO\n");
ret = -ENXIO;
}
dev_dbg(&pdev->dev, "registers %p (%p, %p)\n", i2c->regs, i2c->ioarea, res);
}
dev_dbg(&pdev->dev, "registers %p (%p, %p)\n", i2c->regs, i2c->ioarea, res);
ret = s3c24xx_i2c_init(i2c);
if (ret != 0)
ret = s3c24xx_i2c_init(i2c);
if (ret != 0)
/* find the IRQ for this unit (note, this relies on the init call to
* ensure no current IRQs pending
/* find the IRQ for this unit (note, this relies on the init call to
* ensure no current IRQs pending
if (res == NULL) {
dev_err(&pdev->dev, "cannot find IRQ\n");
ret = -ENOENT;
if (res == NULL) {
dev_err(&pdev->dev, "cannot find IRQ\n");
ret = -ENOENT;
}
ret = request_irq(res->start, s3c24xx_i2c_irq, IRQF_DISABLED,
}
ret = request_irq(res->start, s3c24xx_i2c_irq, IRQF_DISABLED,
if (ret != 0) {
dev_err(&pdev->dev, "cannot claim IRQ\n");
if (ret != 0) {
dev_err(&pdev->dev, "cannot claim IRQ\n");
ret = i2c_add_adapter(&i2c->adap);
if (ret < 0) {
dev_err(&pdev->dev, "failed to add bus to i2c core\n");
ret = i2c_add_adapter(&i2c->adap);
if (ret < 0) {
dev_err(&pdev->dev, "failed to add bus to i2c core\n");
}
platform_set_drvdata(pdev, i2c);
dev_info(&pdev->dev, "%s: S3C I2C adapter\n", i2c->adap.dev.bus_id);
}
platform_set_drvdata(pdev, i2c);
dev_info(&pdev->dev, "%s: S3C I2C adapter\n", i2c->adap.dev.bus_id);
- out:
- if (ret < 0)
- s3c24xx_i2c_free(i2c);
+ err_irq:
+ free_irq(i2c->irq->start, i2c);
+
+ err_iomap:
+ iounmap(i2c->regs);
+
+ err_ioarea:
+ release_resource(i2c->ioarea);
+ kfree(i2c->ioarea);
+
+ err_clk:
+ clk_disable(i2c->clk);
+ clk_put(i2c->clk);
static int s3c24xx_i2c_remove(struct platform_device *pdev)
{
struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
static int s3c24xx_i2c_remove(struct platform_device *pdev)
{
struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
-
- if (i2c != NULL) {
- s3c24xx_i2c_free(i2c);
- platform_set_drvdata(pdev, NULL);
- }
+
+ i2c_del_adapter(&i2c->adap);
+ free_irq(i2c->irq->start, i2c);
+
+ clk_disable(i2c->clk);
+ clk_put(i2c->clk);
+
+ iounmap(i2c->regs);
+
+ release_resource(i2c->ioarea);
+ kfree(i2c->ioarea);