i2c: bcm2835: Store pointer to bus clock
The commitbebff81fb8
("i2c: bcm2835: Model Divider in CCF") introduced a NULL pointer dereference on driver unload. It seems that we can't fetch the bus clock via devm_clk_get in bcm2835_i2c_remove. As an alternative approach store a pointer to the bus clock in the private driver structure. Fixes:bebff81fb8
("i2c: bcm2835: Model Divider in CCF") Signed-off-by: Stefan Wahren <wahrenst@gmx.net> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
This commit is contained in:
Родитель
42052d96ae
Коммит
3b722da667
|
@ -58,6 +58,7 @@ struct bcm2835_i2c_dev {
|
||||||
struct i2c_adapter adapter;
|
struct i2c_adapter adapter;
|
||||||
struct completion completion;
|
struct completion completion;
|
||||||
struct i2c_msg *curr_msg;
|
struct i2c_msg *curr_msg;
|
||||||
|
struct clk *bus_clk;
|
||||||
int num_msgs;
|
int num_msgs;
|
||||||
u32 msg_err;
|
u32 msg_err;
|
||||||
u8 *msg_buf;
|
u8 *msg_buf;
|
||||||
|
@ -404,7 +405,6 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
|
||||||
struct resource *mem, *irq;
|
struct resource *mem, *irq;
|
||||||
int ret;
|
int ret;
|
||||||
struct i2c_adapter *adap;
|
struct i2c_adapter *adap;
|
||||||
struct clk *bus_clk;
|
|
||||||
struct clk *mclk;
|
struct clk *mclk;
|
||||||
u32 bus_clk_rate;
|
u32 bus_clk_rate;
|
||||||
|
|
||||||
|
@ -427,11 +427,11 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
|
||||||
return PTR_ERR(mclk);
|
return PTR_ERR(mclk);
|
||||||
}
|
}
|
||||||
|
|
||||||
bus_clk = bcm2835_i2c_register_div(&pdev->dev, mclk, i2c_dev);
|
i2c_dev->bus_clk = bcm2835_i2c_register_div(&pdev->dev, mclk, i2c_dev);
|
||||||
|
|
||||||
if (IS_ERR(bus_clk)) {
|
if (IS_ERR(i2c_dev->bus_clk)) {
|
||||||
dev_err(&pdev->dev, "Could not register clock\n");
|
dev_err(&pdev->dev, "Could not register clock\n");
|
||||||
return PTR_ERR(bus_clk);
|
return PTR_ERR(i2c_dev->bus_clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
|
ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
|
||||||
|
@ -442,13 +442,13 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
|
||||||
bus_clk_rate = 100000;
|
bus_clk_rate = 100000;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = clk_set_rate_exclusive(bus_clk, bus_clk_rate);
|
ret = clk_set_rate_exclusive(i2c_dev->bus_clk, bus_clk_rate);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&pdev->dev, "Could not set clock frequency\n");
|
dev_err(&pdev->dev, "Could not set clock frequency\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = clk_prepare_enable(bus_clk);
|
ret = clk_prepare_enable(i2c_dev->bus_clk);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "Couldn't prepare clock");
|
dev_err(&pdev->dev, "Couldn't prepare clock");
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -491,10 +491,9 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
|
||||||
static int bcm2835_i2c_remove(struct platform_device *pdev)
|
static int bcm2835_i2c_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct bcm2835_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
|
struct bcm2835_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
|
||||||
struct clk *bus_clk = devm_clk_get(i2c_dev->dev, "div");
|
|
||||||
|
|
||||||
clk_rate_exclusive_put(bus_clk);
|
clk_rate_exclusive_put(i2c_dev->bus_clk);
|
||||||
clk_disable_unprepare(bus_clk);
|
clk_disable_unprepare(i2c_dev->bus_clk);
|
||||||
|
|
||||||
free_irq(i2c_dev->irq, i2c_dev);
|
free_irq(i2c_dev->irq, i2c_dev);
|
||||||
i2c_del_adapter(&i2c_dev->adapter);
|
i2c_del_adapter(&i2c_dev->adapter);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче