diff mbox

[RFC,1/2] soc: qcom: do not disable the iface clock in probe

Message ID 1402410717-12977-1-git-send-email-srinivas.kandagatla@linaro.org
State Superseded
Headers show

Commit Message

Srinivas Kandagatla June 10, 2014, 2:31 p.m. UTC
The use case here is when we have a bootconsole which is printing the
characters on serial console and gsbi driver comes up after some time.
As gsbi driver disables the clock in probe the bootconsole locks up.

This patch fixes the problem by disabling the clock in platform remove
rather than in probe.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/soc/qcom/qcom_gsbi.c | 46 +++++++++++++++++++++++++++++++-------------
 1 file changed, 33 insertions(+), 13 deletions(-)

Comments

Kumar Gala June 10, 2014, 3:20 p.m. UTC | #1
On Jun 10, 2014, at 9:31 AM, Srinivas Kandagatla <srinivas.kandagatla@linaro.org> wrote:

> The use case here is when we have a bootconsole which is printing the
> characters on serial console and gsbi driver comes up after some time.
> As gsbi driver disables the clock in probe the bootconsole locks up.
> 
> This patch fixes the problem by disabling the clock in platform remove
> rather than in probe.
> 
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> ---
> drivers/soc/qcom/qcom_gsbi.c | 46 +++++++++++++++++++++++++++++++-------------
> 1 file changed, 33 insertions(+), 13 deletions(-)

It seems like we shouldn’t need this change.  Adding Stephen to see if there is a reason we don’t have the clk’s enable_count adjusted for how the bootloader setup clks.

- k

> 
> diff --git a/drivers/soc/qcom/qcom_gsbi.c b/drivers/soc/qcom/qcom_gsbi.c
> index ab7b441..64fb298 100644
> --- a/drivers/soc/qcom/qcom_gsbi.c
> +++ b/drivers/soc/qcom/qcom_gsbi.c
> @@ -22,44 +22,63 @@
> #define GSBI_CTRL_REG		0x0000
> #define GSBI_PROTOCOL_SHIFT	4
> 
> +struct gsbi_info {
> +	struct clk *hclk;
> +	u32 mode;
> +	u32 crci;
> +};
> +
> static int gsbi_probe(struct platform_device *pdev)
> {
> 	struct device_node *node = pdev->dev.of_node;
> 	struct resource *res;
> 	void __iomem *base;
> -	struct clk *hclk;
> -	u32 mode, crci = 0;
> +	struct gsbi_info *gsbi;
> +
> +	gsbi = devm_kzalloc(&pdev->dev, sizeof(*gsbi), GFP_KERNEL);
> +
> +	if (!gsbi)
> +		return -ENOMEM;
> 
> 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> 	base = devm_ioremap_resource(&pdev->dev, res);
> 	if (IS_ERR(base))
> 		return PTR_ERR(base);
> 
> -	if (of_property_read_u32(node, "qcom,mode", &mode)) {
> +	if (of_property_read_u32(node, "qcom,mode", &gsbi->mode)) {
> 		dev_err(&pdev->dev, "missing mode configuration\n");
> 		return -EINVAL;
> 	}
> 
> 	/* not required, so default to 0 if not present */
> -	of_property_read_u32(node, "qcom,crci", &crci);
> +	of_property_read_u32(node, "qcom,crci", &gsbi->crci);
> 
> -	dev_info(&pdev->dev, "GSBI port protocol: %d crci: %d\n", mode, crci);
> +	dev_info(&pdev->dev, "GSBI port protocol: %d crci: %d\n",
> +		 gsbi->mode, gsbi->crci);
> +	gsbi->hclk = devm_clk_get(&pdev->dev, "iface");
> +	if (IS_ERR(gsbi->hclk))
> +		return PTR_ERR(gsbi->hclk);
> 
> -	hclk = devm_clk_get(&pdev->dev, "iface");
> -	if (IS_ERR(hclk))
> -		return PTR_ERR(hclk);
> +	clk_prepare_enable(gsbi->hclk);
> 
> -	clk_prepare_enable(hclk);
> -
> -	writel_relaxed((mode << GSBI_PROTOCOL_SHIFT) | crci,
> +	writel_relaxed((gsbi->mode << GSBI_PROTOCOL_SHIFT) | gsbi->crci,
> 				base + GSBI_CTRL_REG);
> 
> 	/* make sure the gsbi control write is not reordered */
> 	wmb();
> 
> -	clk_disable_unprepare(hclk);
> +	platform_set_drvdata(pdev, gsbi);
> +
> +	return of_platform_populate(node, NULL, NULL, &pdev->dev);
> +}
> +
> +static int gsbi_remove(struct platform_device *pdev)
> +{
> +	struct gsbi_info *gsbi = platform_get_drvdata(pdev);
> +
> +	clk_disable_unprepare(gsbi->hclk);
> 
> -	return of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
> +	return 0;
> }
> 
> static const struct of_device_id gsbi_dt_match[] = {
> @@ -76,6 +95,7 @@ static struct platform_driver gsbi_driver = {
> 		.of_match_table	= gsbi_dt_match,
> 	},
> 	.probe = gsbi_probe,
> +	.remove	= gsbi_remove,
> };
> 
> module_platform_driver(gsbi_driver);
> -- 
> 1.9.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
Stephen Boyd June 10, 2014, 5:39 p.m. UTC | #2
On 06/10/14 08:20, Kumar Gala wrote:
> On Jun 10, 2014, at 9:31 AM, Srinivas Kandagatla <srinivas.kandagatla@linaro.org> wrote:
>
>> The use case here is when we have a bootconsole which is printing the
>> characters on serial console and gsbi driver comes up after some time.
>> As gsbi driver disables the clock in probe the bootconsole locks up.
>>
>> This patch fixes the problem by disabling the clock in platform remove
>> rather than in probe.
>>
>> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>> ---
>> drivers/soc/qcom/qcom_gsbi.c | 46 +++++++++++++++++++++++++++++++-------------
>> 1 file changed, 33 insertions(+), 13 deletions(-)
> It seems like we shouldn’t need this change.  Adding Stephen to see if there is a reason we don’t have the clk’s enable_count adjusted for how the bootloader setup clks.

This is a long standing problem with the clock framework. In our vendor
tree we've added something called "handoff" which basically detects the
state of all clocks upon registration and keeps clocks enabled until
late_init() if the clocks were enabled at the time of registration.

For this case though "handoff" doesn't seem necessary. It's easier to
just disable the clock when the driver is removed. With finer grained
power management this driver can participate in runtime_pm and disable
the ahb clock when the device is runtime suspended; which would only
happen when the child devices (uart/spi/i2c) are also runtime suspended.

> - k
>
>> diff --git a/drivers/soc/qcom/qcom_gsbi.c b/drivers/soc/qcom/qcom_gsbi.c
>> index ab7b441..64fb298 100644
>> --- a/drivers/soc/qcom/qcom_gsbi.c
>> +++ b/drivers/soc/qcom/qcom_gsbi.c
>> @@ -22,44 +22,63 @@
>> #define GSBI_CTRL_REG		0x0000
>> #define GSBI_PROTOCOL_SHIFT	4
>>
>> +struct gsbi_info {
>> +	struct clk *hclk;
>> +	u32 mode;
>> +	u32 crci;
>> +};

What does mode and crci have to do with this patch? Can't we just put
the clock into the platform data?
Andy Gross June 10, 2014, 5:46 p.m. UTC | #3
On Tue, Jun 10, 2014 at 10:39:02AM -0700, Stephen Boyd wrote:

<snip>

> >> diff --git a/drivers/soc/qcom/qcom_gsbi.c b/drivers/soc/qcom/qcom_gsbi.c
> >> index ab7b441..64fb298 100644
> >> --- a/drivers/soc/qcom/qcom_gsbi.c
> >> +++ b/drivers/soc/qcom/qcom_gsbi.c
> >> @@ -22,44 +22,63 @@
> >> #define GSBI_CTRL_REG		0x0000
> >> #define GSBI_PROTOCOL_SHIFT	4
> >>
> >> +struct gsbi_info {
> >> +	struct clk *hclk;
> >> +	u32 mode;
> >> +	u32 crci;
> >> +};
> 
> What does mode and crci have to do with this patch? Can't we just put
> the clock into the platform data?

I second this notion.
Srinivas Kandagatla June 10, 2014, 5:47 p.m. UTC | #4
On 10/06/14 18:39, Stephen Boyd wrote:
> On 06/10/14 08:20, Kumar Gala wrote:
>> On Jun 10, 2014, at 9:31 AM, Srinivas Kandagatla <srinivas.kandagatla@linaro.org> wrote:
>>
>>> The use case here is when we have a bootconsole which is printing the
>>> characters on serial console and gsbi driver comes up after some time.
>>> As gsbi driver disables the clock in probe the bootconsole locks up.
>>>
>>> This patch fixes the problem by disabling the clock in platform remove
>>> rather than in probe.
>>>
>>> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>>> ---
>>> drivers/soc/qcom/qcom_gsbi.c | 46 +++++++++++++++++++++++++++++++-------------
>>> 1 file changed, 33 insertions(+), 13 deletions(-)
>> It seems like we shouldn’t need this change.  Adding Stephen to see if there is a reason we don’t have the clk’s enable_count adjusted for how the bootloader setup clks.
>
> This is a long standing problem with the clock framework. In our vendor
> tree we've added something called "handoff" which basically detects the
> state of all clocks upon registration and keeps clocks enabled until
> late_init() if the clocks were enabled at the time of registration.
>
> For this case though "handoff" doesn't seem necessary. It's easier to
> just disable the clock when the driver is removed. With finer grained
> power management this driver can participate in runtime_pm and disable
> the ahb clock when the device is runtime suspended; which would only
> happen when the child devices (uart/spi/i2c) are also runtime suspended.

I had same thought about gsbi participating in PM.
>
>> - k
>>
>>> diff --git a/drivers/soc/qcom/qcom_gsbi.c b/drivers/soc/qcom/qcom_gsbi.c
>>> index ab7b441..64fb298 100644
>>> --- a/drivers/soc/qcom/qcom_gsbi.c
>>> +++ b/drivers/soc/qcom/qcom_gsbi.c
>>> @@ -22,44 +22,63 @@
>>> #define GSBI_CTRL_REG		0x0000
>>> #define GSBI_PROTOCOL_SHIFT	4
>>>
>>> +struct gsbi_info {
>>> +	struct clk *hclk;
>>> +	u32 mode;
>>> +	u32 crci;
>>> +};
>
> What does mode and crci have to do with this patch? Can't we just put
> the clock into the platform data?
It has nothing to do with this but, for completeness and we might need 
this if we are doing PM in future. for example pm resume might want to 
reconfigure the gsbi.

Am Ok with either approaches.


--srini

>
--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Andy Gross June 10, 2014, 5:57 p.m. UTC | #5
On Tue, Jun 10, 2014 at 06:47:29PM +0100, Srinivas Kandagatla wrote:

<snip>

> >What does mode and crci have to do with this patch? Can't we just put
> >the clock into the platform data?
> It has nothing to do with this but, for completeness and we might
> need this if we are doing PM in future. for example pm resume might
> want to reconfigure the gsbi.

Yes, setting idle mode would save some power.
Srinivas Kandagatla July 17, 2014, 8:18 p.m. UTC | #6
Hi Andy,
Do you know who is going to queue this patch for 3.17?

thanks,
srini


On 10/06/14 15:31, Srinivas Kandagatla wrote:
> The use case here is when we have a bootconsole which is printing the
> characters on serial console and gsbi driver comes up after some time.
> As gsbi driver disables the clock in probe the bootconsole locks up.
>
> This patch fixes the problem by disabling the clock in platform remove
> rather than in probe.
>
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> ---
>   drivers/soc/qcom/qcom_gsbi.c | 46 +++++++++++++++++++++++++++++++-------------
>   1 file changed, 33 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/soc/qcom/qcom_gsbi.c b/drivers/soc/qcom/qcom_gsbi.c
> index ab7b441..64fb298 100644
> --- a/drivers/soc/qcom/qcom_gsbi.c
> +++ b/drivers/soc/qcom/qcom_gsbi.c
> @@ -22,44 +22,63 @@
>   #define GSBI_CTRL_REG		0x0000
>   #define GSBI_PROTOCOL_SHIFT	4
>
> +struct gsbi_info {
> +	struct clk *hclk;
> +	u32 mode;
> +	u32 crci;
> +};
> +
>   static int gsbi_probe(struct platform_device *pdev)
>   {
>   	struct device_node *node = pdev->dev.of_node;
>   	struct resource *res;
>   	void __iomem *base;
> -	struct clk *hclk;
> -	u32 mode, crci = 0;
> +	struct gsbi_info *gsbi;
> +
> +	gsbi = devm_kzalloc(&pdev->dev, sizeof(*gsbi), GFP_KERNEL);
> +
> +	if (!gsbi)
> +		return -ENOMEM;
>
>   	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>   	base = devm_ioremap_resource(&pdev->dev, res);
>   	if (IS_ERR(base))
>   		return PTR_ERR(base);
>
> -	if (of_property_read_u32(node, "qcom,mode", &mode)) {
> +	if (of_property_read_u32(node, "qcom,mode", &gsbi->mode)) {
>   		dev_err(&pdev->dev, "missing mode configuration\n");
>   		return -EINVAL;
>   	}
>
>   	/* not required, so default to 0 if not present */
> -	of_property_read_u32(node, "qcom,crci", &crci);
> +	of_property_read_u32(node, "qcom,crci", &gsbi->crci);
>
> -	dev_info(&pdev->dev, "GSBI port protocol: %d crci: %d\n", mode, crci);
> +	dev_info(&pdev->dev, "GSBI port protocol: %d crci: %d\n",
> +		 gsbi->mode, gsbi->crci);
> +	gsbi->hclk = devm_clk_get(&pdev->dev, "iface");
> +	if (IS_ERR(gsbi->hclk))
> +		return PTR_ERR(gsbi->hclk);
>
> -	hclk = devm_clk_get(&pdev->dev, "iface");
> -	if (IS_ERR(hclk))
> -		return PTR_ERR(hclk);
> +	clk_prepare_enable(gsbi->hclk);
>
> -	clk_prepare_enable(hclk);
> -
> -	writel_relaxed((mode << GSBI_PROTOCOL_SHIFT) | crci,
> +	writel_relaxed((gsbi->mode << GSBI_PROTOCOL_SHIFT) | gsbi->crci,
>   				base + GSBI_CTRL_REG);
>
>   	/* make sure the gsbi control write is not reordered */
>   	wmb();
>
> -	clk_disable_unprepare(hclk);
> +	platform_set_drvdata(pdev, gsbi);
> +
> +	return of_platform_populate(node, NULL, NULL, &pdev->dev);
> +}
> +
> +static int gsbi_remove(struct platform_device *pdev)
> +{
> +	struct gsbi_info *gsbi = platform_get_drvdata(pdev);
> +
> +	clk_disable_unprepare(gsbi->hclk);
>
> -	return of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
> +	return 0;
>   }
>
>   static const struct of_device_id gsbi_dt_match[] = {
> @@ -76,6 +95,7 @@ static struct platform_driver gsbi_driver = {
>   		.of_match_table	= gsbi_dt_match,
>   	},
>   	.probe = gsbi_probe,
> +	.remove	= gsbi_remove,
>   };
>
>   module_platform_driver(gsbi_driver);
>
--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Srinivas Kandagatla Aug. 12, 2014, 4:25 a.m. UTC | #7
Hi Andy/Kumar,

If its not too late,
Can we queue this fix for 3.17-rc1 or rc2?


thanks,
srini
On 10/06/14 15:31, Srinivas Kandagatla wrote:
> The use case here is when we have a bootconsole which is printing the
> characters on serial console and gsbi driver comes up after some time.
> As gsbi driver disables the clock in probe the bootconsole locks up.
>
> This patch fixes the problem by disabling the clock in platform remove
> rather than in probe.
>
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> ---
>   drivers/soc/qcom/qcom_gsbi.c | 46 +++++++++++++++++++++++++++++++-------------
>   1 file changed, 33 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/soc/qcom/qcom_gsbi.c b/drivers/soc/qcom/qcom_gsbi.c
> index ab7b441..64fb298 100644
> --- a/drivers/soc/qcom/qcom_gsbi.c
> +++ b/drivers/soc/qcom/qcom_gsbi.c
> @@ -22,44 +22,63 @@
>   #define GSBI_CTRL_REG		0x0000
>   #define GSBI_PROTOCOL_SHIFT	4
>
> +struct gsbi_info {
> +	struct clk *hclk;
> +	u32 mode;
> +	u32 crci;
> +};
> +
>   static int gsbi_probe(struct platform_device *pdev)
>   {
>   	struct device_node *node = pdev->dev.of_node;
>   	struct resource *res;
>   	void __iomem *base;
> -	struct clk *hclk;
> -	u32 mode, crci = 0;
> +	struct gsbi_info *gsbi;
> +
> +	gsbi = devm_kzalloc(&pdev->dev, sizeof(*gsbi), GFP_KERNEL);
> +
> +	if (!gsbi)
> +		return -ENOMEM;
>
>   	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>   	base = devm_ioremap_resource(&pdev->dev, res);
>   	if (IS_ERR(base))
>   		return PTR_ERR(base);
>
> -	if (of_property_read_u32(node, "qcom,mode", &mode)) {
> +	if (of_property_read_u32(node, "qcom,mode", &gsbi->mode)) {
>   		dev_err(&pdev->dev, "missing mode configuration\n");
>   		return -EINVAL;
>   	}
>
>   	/* not required, so default to 0 if not present */
> -	of_property_read_u32(node, "qcom,crci", &crci);
> +	of_property_read_u32(node, "qcom,crci", &gsbi->crci);
>
> -	dev_info(&pdev->dev, "GSBI port protocol: %d crci: %d\n", mode, crci);
> +	dev_info(&pdev->dev, "GSBI port protocol: %d crci: %d\n",
> +		 gsbi->mode, gsbi->crci);
> +	gsbi->hclk = devm_clk_get(&pdev->dev, "iface");
> +	if (IS_ERR(gsbi->hclk))
> +		return PTR_ERR(gsbi->hclk);
>
> -	hclk = devm_clk_get(&pdev->dev, "iface");
> -	if (IS_ERR(hclk))
> -		return PTR_ERR(hclk);
> +	clk_prepare_enable(gsbi->hclk);
>
> -	clk_prepare_enable(hclk);
> -
> -	writel_relaxed((mode << GSBI_PROTOCOL_SHIFT) | crci,
> +	writel_relaxed((gsbi->mode << GSBI_PROTOCOL_SHIFT) | gsbi->crci,
>   				base + GSBI_CTRL_REG);
>
>   	/* make sure the gsbi control write is not reordered */
>   	wmb();
>
> -	clk_disable_unprepare(hclk);
> +	platform_set_drvdata(pdev, gsbi);
> +
> +	return of_platform_populate(node, NULL, NULL, &pdev->dev);
> +}
> +
> +static int gsbi_remove(struct platform_device *pdev)
> +{
> +	struct gsbi_info *gsbi = platform_get_drvdata(pdev);
> +
> +	clk_disable_unprepare(gsbi->hclk);
>
> -	return of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
> +	return 0;
>   }
>
>   static const struct of_device_id gsbi_dt_match[] = {
> @@ -76,6 +95,7 @@ static struct platform_driver gsbi_driver = {
>   		.of_match_table	= gsbi_dt_match,
>   	},
>   	.probe = gsbi_probe,
> +	.remove	= gsbi_remove,
>   };
>
>   module_platform_driver(gsbi_driver);
>
--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/soc/qcom/qcom_gsbi.c b/drivers/soc/qcom/qcom_gsbi.c
index ab7b441..64fb298 100644
--- a/drivers/soc/qcom/qcom_gsbi.c
+++ b/drivers/soc/qcom/qcom_gsbi.c
@@ -22,44 +22,63 @@ 
 #define GSBI_CTRL_REG		0x0000
 #define GSBI_PROTOCOL_SHIFT	4
 
+struct gsbi_info {
+	struct clk *hclk;
+	u32 mode;
+	u32 crci;
+};
+
 static int gsbi_probe(struct platform_device *pdev)
 {
 	struct device_node *node = pdev->dev.of_node;
 	struct resource *res;
 	void __iomem *base;
-	struct clk *hclk;
-	u32 mode, crci = 0;
+	struct gsbi_info *gsbi;
+
+	gsbi = devm_kzalloc(&pdev->dev, sizeof(*gsbi), GFP_KERNEL);
+
+	if (!gsbi)
+		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(base))
 		return PTR_ERR(base);
 
-	if (of_property_read_u32(node, "qcom,mode", &mode)) {
+	if (of_property_read_u32(node, "qcom,mode", &gsbi->mode)) {
 		dev_err(&pdev->dev, "missing mode configuration\n");
 		return -EINVAL;
 	}
 
 	/* not required, so default to 0 if not present */
-	of_property_read_u32(node, "qcom,crci", &crci);
+	of_property_read_u32(node, "qcom,crci", &gsbi->crci);
 
-	dev_info(&pdev->dev, "GSBI port protocol: %d crci: %d\n", mode, crci);
+	dev_info(&pdev->dev, "GSBI port protocol: %d crci: %d\n",
+		 gsbi->mode, gsbi->crci);
+	gsbi->hclk = devm_clk_get(&pdev->dev, "iface");
+	if (IS_ERR(gsbi->hclk))
+		return PTR_ERR(gsbi->hclk);
 
-	hclk = devm_clk_get(&pdev->dev, "iface");
-	if (IS_ERR(hclk))
-		return PTR_ERR(hclk);
+	clk_prepare_enable(gsbi->hclk);
 
-	clk_prepare_enable(hclk);
-
-	writel_relaxed((mode << GSBI_PROTOCOL_SHIFT) | crci,
+	writel_relaxed((gsbi->mode << GSBI_PROTOCOL_SHIFT) | gsbi->crci,
 				base + GSBI_CTRL_REG);
 
 	/* make sure the gsbi control write is not reordered */
 	wmb();
 
-	clk_disable_unprepare(hclk);
+	platform_set_drvdata(pdev, gsbi);
+
+	return of_platform_populate(node, NULL, NULL, &pdev->dev);
+}
+
+static int gsbi_remove(struct platform_device *pdev)
+{
+	struct gsbi_info *gsbi = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(gsbi->hclk);
 
-	return of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+	return 0;
 }
 
 static const struct of_device_id gsbi_dt_match[] = {
@@ -76,6 +95,7 @@  static struct platform_driver gsbi_driver = {
 		.of_match_table	= gsbi_dt_match,
 	},
 	.probe = gsbi_probe,
+	.remove	= gsbi_remove,
 };
 
 module_platform_driver(gsbi_driver);