diff mbox series

[U-Boot,1/2] mmc: sunxi: Support cd-inverted DT property

Message ID 20171218200942.23586-1-tuomas@tuxera.com
State Changes Requested
Delegated to: Jagannadha Sutradharudu Teki
Headers show
Series [U-Boot,1/2] mmc: sunxi: Support cd-inverted DT property | expand

Commit Message

Tuomas Tynkkynen Dec. 18, 2017, 8:09 p.m. UTC
Commit 8620f384098b ("dm: sunxi: Linksprite_pcDuino3: Correct polarity
of MMC card detect") claims that the Pcduino3 device tree has an
incorrect polarity for the card detect pin, but the actual problem is
that unlike the Linux MMC driver, the U-Boot driver isn't respecting the
cd-invert property (see Documentation/devicetree/bindings/mmc/mmc.txt)
which tells that the card detect signal level should be inverted.

Fix this properly by adding support for the cd-inverted property while
reverting the original commit at the same time. While at it, I noticed
the driver always enables pullups for the card detect line, which is not
right if the card detect GPIO is active-high, so fix that as well.

Signed-off-by: Tuomas Tynkkynen <tuomas@tuxera.com>
---
 arch/arm/dts/sun7i-a20-pcduino3.dts |  2 +-
 drivers/mmc/sunxi_mmc.c             | 12 ++++++++++--
 2 files changed, 11 insertions(+), 3 deletions(-)

Comments

Maxime Ripard Dec. 20, 2017, 12:26 p.m. UTC | #1
On Mon, Dec 18, 2017 at 10:09:41PM +0200, Tuomas Tynkkynen wrote:
> Commit 8620f384098b ("dm: sunxi: Linksprite_pcDuino3: Correct polarity
> of MMC card detect") claims that the Pcduino3 device tree has an
> incorrect polarity for the card detect pin, but the actual problem is
> that unlike the Linux MMC driver, the U-Boot driver isn't respecting the
> cd-invert property (see Documentation/devicetree/bindings/mmc/mmc.txt)
> which tells that the card detect signal level should be inverted.
> 
> Fix this properly by adding support for the cd-inverted property while
> reverting the original commit at the same time. While at it, I noticed
> the driver always enables pullups for the card detect line, which is not
> right if the card detect GPIO is active-high, so fix that as well.
> 
> Signed-off-by: Tuomas Tynkkynen <tuomas@tuxera.com>
> ---
>  arch/arm/dts/sun7i-a20-pcduino3.dts |  2 +-
>  drivers/mmc/sunxi_mmc.c             | 12 ++++++++++--
>  2 files changed, 11 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm/dts/sun7i-a20-pcduino3.dts b/arch/arm/dts/sun7i-a20-pcduino3.dts
> index 37b1e0ee9b..1a8b39be1d 100644
> --- a/arch/arm/dts/sun7i-a20-pcduino3.dts
> +++ b/arch/arm/dts/sun7i-a20-pcduino3.dts
> @@ -164,7 +164,7 @@
>  	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
>  	vmmc-supply = <&reg_vcc3v3>;
>  	bus-width = <4>;
> -	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
> +	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
>  	cd-inverted;
>  	status = "okay";
>  };
> diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c
> index 4edb4be46c..7cc7303570 100644
> --- a/drivers/mmc/sunxi_mmc.c
> +++ b/drivers/mmc/sunxi_mmc.c
> @@ -30,6 +30,7 @@ struct sunxi_mmc_priv {
>  	uint32_t *mclkreg;
>  	unsigned fatal_err;
>  	struct gpio_desc cd_gpio;	/* Change Detect GPIO */
> +	int cd_inverted;
>  	struct sunxi_mmc *reg;
>  	struct mmc_config cfg;
>  };
> @@ -545,7 +546,7 @@ static int sunxi_mmc_getcd(struct udevice *dev)
>  	struct sunxi_mmc_priv *priv = dev_get_priv(dev);
>  
>  	if (dm_gpio_is_valid(&priv->cd_gpio))
> -		return dm_gpio_get_value(&priv->cd_gpio);
> +		return dm_gpio_get_value(&priv->cd_gpio) ^ priv->cd_inverted;
>  
>  	return 1;
>  }
> @@ -606,8 +607,15 @@ static int sunxi_mmc_probe(struct udevice *dev)
>  	if (!gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio,
>  				  GPIOD_IS_IN)) {
>  		int cd_pin = gpio_get_number(&priv->cd_gpio);
> +		int cd_state = priv->cd_gpio.flags & GPIOD_ACTIVE_LOW ? 0 : 1;

Isn't that change itself enough to get what you wanted?

You really shouldn't be doing anything else.

Maxime
Tuomas Tynkkynen Dec. 20, 2017, 1:34 p.m. UTC | #2
On Wed, 2017-12-20 at 13:26 +0100, Maxime Ripard wrote:
> On Mon, Dec 18, 2017 at 10:09:41PM +0200, Tuomas Tynkkynen wrote:
> > Commit 8620f384098b ("dm: sunxi: Linksprite_pcDuino3: Correct
> > polarity
> > of MMC card detect") claims that the Pcduino3 device tree has an
> > incorrect polarity for the card detect pin, but the actual problem
> > is
> > that unlike the Linux MMC driver, the U-Boot driver isn't
> > respecting the
> > cd-invert property (see
> > Documentation/devicetree/bindings/mmc/mmc.txt)
> > which tells that the card detect signal level should be inverted.
> > 
> > Fix this properly by adding support for the cd-inverted property
> > while
> > reverting the original commit at the same time. While at it, I
> > noticed
> > the driver always enables pullups for the card detect line, which
> > is not
> > right if the card detect GPIO is active-high, so fix that as well.
> > 
> > Signed-off-by: Tuomas Tynkkynen <tuomas@tuxera.com>
> > ---
> >  arch/arm/dts/sun7i-a20-pcduino3.dts |  2 +-
> >  drivers/mmc/sunxi_mmc.c             | 12 ++++++++++--
> >  2 files changed, 11 insertions(+), 3 deletions(-)
> > 
> > diff --git a/arch/arm/dts/sun7i-a20-pcduino3.dts
> > b/arch/arm/dts/sun7i-a20-pcduino3.dts
> > index 37b1e0ee9b..1a8b39be1d 100644
> > --- a/arch/arm/dts/sun7i-a20-pcduino3.dts
> > +++ b/arch/arm/dts/sun7i-a20-pcduino3.dts
> > @@ -164,7 +164,7 @@
> >  	pinctrl-0 = <&mmc0_pins_a>,
> > <&mmc0_cd_pin_reference_design>;
> >  	vmmc-supply = <&reg_vcc3v3>;
> >  	bus-width = <4>;
> > -	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
> > +	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
> >  	cd-inverted;
> >  	status = "okay";
> >  };
> > diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c
> > index 4edb4be46c..7cc7303570 100644
> > --- a/drivers/mmc/sunxi_mmc.c
> > +++ b/drivers/mmc/sunxi_mmc.c
> > @@ -30,6 +30,7 @@ struct sunxi_mmc_priv {
> >  	uint32_t *mclkreg;
> >  	unsigned fatal_err;
> >  	struct gpio_desc cd_gpio;	/* Change Detect GPIO */
> > +	int cd_inverted;
> >  	struct sunxi_mmc *reg;
> >  	struct mmc_config cfg;
> >  };
> > @@ -545,7 +546,7 @@ static int sunxi_mmc_getcd(struct udevice *dev)
> >  	struct sunxi_mmc_priv *priv = dev_get_priv(dev);
> >  
> >  	if (dm_gpio_is_valid(&priv->cd_gpio))
> > -		return dm_gpio_get_value(&priv->cd_gpio);
> > +		return dm_gpio_get_value(&priv->cd_gpio) ^ priv-
> > >cd_inverted;
> >  
> >  	return 1;
> >  }
> > @@ -606,8 +607,15 @@ static int sunxi_mmc_probe(struct udevice
> > *dev)
> >  	if (!gpio_request_by_name(dev, "cd-gpios", 0, &priv-
> > >cd_gpio,
> >  				  GPIOD_IS_IN)) {
> >  		int cd_pin = gpio_get_number(&priv->cd_gpio);
> > +		int cd_state = priv->cd_gpio.flags &
> > GPIOD_ACTIVE_LOW ? 0 : 1;
> 
> Isn't that change itself enough to get what you wanted?
> 
> You really shouldn't be doing anything else.

Was that the correct part you meant to quote? The cd_state
was only for the somewhat pull-up change... Sorry about that,
here's the minimal (probably whitespace-damaged) change:

diff --git a/arch/arm/dts/sun7i-a20-pcduino3.dts b/arch/arm/dts/sun7i-a20-pcduino3.dts
index 37b1e0ee9b..1a8b39be1d 100644
--- a/arch/arm/dts/sun7i-a20-pcduino3.dts
+++ b/arch/arm/dts/sun7i-a20-pcduino3.dts
@@ -164,7 +164,7 @@
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
 	cd-inverted;
 	status = "okay";
 };
diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c
index 4edb4be46c..a974543148 100644
--- a/drivers/mmc/sunxi_mmc.c
+++ b/drivers/mmc/sunxi_mmc.c
@@ -30,6 +30,7 @@ struct sunxi_mmc_priv {
 	uint32_t *mclkreg;
 	unsigned fatal_err;
 	struct gpio_desc cd_gpio;	/* Change Detect GPIO */
+	int cd_inverted;
 	struct sunxi_mmc *reg;
 	struct mmc_config cfg;
 };
@@ -545,7 +546,7 @@ static int sunxi_mmc_getcd(struct udevice *dev)
 	struct sunxi_mmc_priv *priv = dev_get_priv(dev);
 
 	if (dm_gpio_is_valid(&priv->cd_gpio))
-		return dm_gpio_get_value(&priv->cd_gpio);
+		return dm_gpio_get_value(&priv->cd_gpio) ^ priv->cd_inverted;
 
 	return 1;
 }
@@ -607,6 +608,8 @@ static int sunxi_mmc_probe(struct udevice *dev)
 				  GPIOD_IS_IN)) {
 		int cd_pin = gpio_get_number(&priv->cd_gpio);
 
+		priv->cd_inverted = dev_read_bool(dev, "cd-inverted");
+
 		sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP);
 	}
 
So: if the DT specifies GPIO_ACTIVE_LOW, dm_gpio_get_value()
does its own inversion of the GPIO level. Then, on top of that
we do another inversion if the "cd-inverted" property was specified.
This matches what the Linux MMC driver does.

Does that make sense?

Thanks.
Maxime Ripard Dec. 21, 2017, 1:09 p.m. UTC | #3
Hi Tuomas,

On Wed, Dec 20, 2017 at 03:34:47PM +0200, Tuomas Tynkkynen wrote:
> > > @@ -606,8 +607,15 @@ static int sunxi_mmc_probe(struct udevice
> > > *dev)
> > >  	if (!gpio_request_by_name(dev, "cd-gpios", 0, &priv-
> > > >cd_gpio,
> > >  				  GPIOD_IS_IN)) {
> > >  		int cd_pin = gpio_get_number(&priv->cd_gpio);
> > > +		int cd_state = priv->cd_gpio.flags &
> > > GPIOD_ACTIVE_LOW ? 0 : 1;
> > 
> > Isn't that change itself enough to get what you wanted?
> > 
> > You really shouldn't be doing anything else.
> 
> Was that the correct part you meant to quote? The cd_state
> was only for the somewhat pull-up change... Sorry about that,
> here's the minimal (probably whitespace-damaged) change:

Sorry if it wasn't really clear, I actually wanted to say that
cd-inverted is deprecated, and you should just teach about the gpio
flags like you did.

The rest seems superfluous, especially since I'd expect the
combination of our GPIO flags and cd-inverted in our DTs to be buggy
in most cases.

> diff --git a/arch/arm/dts/sun7i-a20-pcduino3.dts b/arch/arm/dts/sun7i-a20-pcduino3.dts
> index 37b1e0ee9b..1a8b39be1d 100644
> --- a/arch/arm/dts/sun7i-a20-pcduino3.dts
> +++ b/arch/arm/dts/sun7i-a20-pcduino3.dts
> @@ -164,7 +164,7 @@
>  	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
>  	vmmc-supply = <&reg_vcc3v3>;
>  	bus-width = <4>;
> -	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
> +	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
>  	cd-inverted;
>  	status = "okay";
>  };
> diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c
> index 4edb4be46c..a974543148 100644
> --- a/drivers/mmc/sunxi_mmc.c
> +++ b/drivers/mmc/sunxi_mmc.c
> @@ -30,6 +30,7 @@ struct sunxi_mmc_priv {
>  	uint32_t *mclkreg;
>  	unsigned fatal_err;
>  	struct gpio_desc cd_gpio;	/* Change Detect GPIO */
> +	int cd_inverted;
>  	struct sunxi_mmc *reg;
>  	struct mmc_config cfg;
>  };
> @@ -545,7 +546,7 @@ static int sunxi_mmc_getcd(struct udevice *dev)
>  	struct sunxi_mmc_priv *priv = dev_get_priv(dev);
>  
>  	if (dm_gpio_is_valid(&priv->cd_gpio))
> -		return dm_gpio_get_value(&priv->cd_gpio);
> +		return dm_gpio_get_value(&priv->cd_gpio) ^ priv->cd_inverted;
>  
>  	return 1;
>  }
> @@ -607,6 +608,8 @@ static int sunxi_mmc_probe(struct udevice *dev)
>  				  GPIOD_IS_IN)) {
>  		int cd_pin = gpio_get_number(&priv->cd_gpio);
>  
> +		priv->cd_inverted = dev_read_bool(dev, "cd-inverted");
> +
>  		sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP);
>  	}
>  
> So: if the DT specifies GPIO_ACTIVE_LOW, dm_gpio_get_value()
> does its own inversion of the GPIO level. Then, on top of that
> we do another inversion if the "cd-inverted" property was specified.
> This matches what the Linux MMC driver does.

Hmmm, right.

I guess in your particular case then, you'd be better off droping the
cd-inverted property. Like I said, it's really legacy these days. That
of course doesn't prevent the rest of the patch to go in.

Maxime
Tuomas Tynkkynen Dec. 21, 2017, 2:09 p.m. UTC | #4
On Thu, 2017-12-21 at 14:09 +0100, Maxime Ripard wrote:

> >  		sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP);
> >  	}
> >  
> > So: if the DT specifies GPIO_ACTIVE_LOW, dm_gpio_get_value()
> > does its own inversion of the GPIO level. Then, on top of that
> > we do another inversion if the "cd-inverted" property was
> > specified.
> > This matches what the Linux MMC driver does.
> 
> Hmmm, right.
> 
> I guess in your particular case then, you'd be better off droping the
> cd-inverted property. Like I said, it's really legacy these days.
> That
> of course doesn't prevent the rest of the patch to go in.

Yes, getting rid of the cd-inverted properties from the DTs should make
card detection work without any code changes. So the plan of action
will be:

- Drop cd-inverted from U-Boot's sun7i-a20-pcduino3.dts
- Flip the GPIO_ACTIVE_* around + drop cd-inverted from Linux DTs
- Re-sync DTs from Linux to U-Boot
- Finally switch all sunxi boards to DM_MMC in U-Boot
Maxime Ripard Dec. 21, 2017, 3:49 p.m. UTC | #5
On Thu, Dec 21, 2017 at 04:09:46PM +0200, Tuomas Tynkkynen wrote:
> On Thu, 2017-12-21 at 14:09 +0100, Maxime Ripard wrote:
> 
> > >  		sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP);
> > >  	}
> > >  
> > > So: if the DT specifies GPIO_ACTIVE_LOW, dm_gpio_get_value()
> > > does its own inversion of the GPIO level. Then, on top of that
> > > we do another inversion if the "cd-inverted" property was
> > > specified.
> > > This matches what the Linux MMC driver does.
> > 
> > Hmmm, right.
> > 
> > I guess in your particular case then, you'd be better off droping the
> > cd-inverted property. Like I said, it's really legacy these days.
> > That
> > of course doesn't prevent the rest of the patch to go in.
> 
> Yes, getting rid of the cd-inverted properties from the DTs should make
> card detection work without any code changes. So the plan of action
> will be:
> 
> - Drop cd-inverted from U-Boot's sun7i-a20-pcduino3.dts
> - Flip the GPIO_ACTIVE_* around + drop cd-inverted from Linux DTs
> - Re-sync DTs from Linux to U-Boot
> - Finally switch all sunxi boards to DM_MMC in U-Boot

Looks good to me :)

Maxime
diff mbox series

Patch

diff --git a/arch/arm/dts/sun7i-a20-pcduino3.dts b/arch/arm/dts/sun7i-a20-pcduino3.dts
index 37b1e0ee9b..1a8b39be1d 100644
--- a/arch/arm/dts/sun7i-a20-pcduino3.dts
+++ b/arch/arm/dts/sun7i-a20-pcduino3.dts
@@ -164,7 +164,7 @@ 
 	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
 	vmmc-supply = <&reg_vcc3v3>;
 	bus-width = <4>;
-	cd-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; /* PH1 */
+	cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
 	cd-inverted;
 	status = "okay";
 };
diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c
index 4edb4be46c..7cc7303570 100644
--- a/drivers/mmc/sunxi_mmc.c
+++ b/drivers/mmc/sunxi_mmc.c
@@ -30,6 +30,7 @@  struct sunxi_mmc_priv {
 	uint32_t *mclkreg;
 	unsigned fatal_err;
 	struct gpio_desc cd_gpio;	/* Change Detect GPIO */
+	int cd_inverted;
 	struct sunxi_mmc *reg;
 	struct mmc_config cfg;
 };
@@ -545,7 +546,7 @@  static int sunxi_mmc_getcd(struct udevice *dev)
 	struct sunxi_mmc_priv *priv = dev_get_priv(dev);
 
 	if (dm_gpio_is_valid(&priv->cd_gpio))
-		return dm_gpio_get_value(&priv->cd_gpio);
+		return dm_gpio_get_value(&priv->cd_gpio) ^ priv->cd_inverted;
 
 	return 1;
 }
@@ -606,8 +607,15 @@  static int sunxi_mmc_probe(struct udevice *dev)
 	if (!gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio,
 				  GPIOD_IS_IN)) {
 		int cd_pin = gpio_get_number(&priv->cd_gpio);
+		int cd_state = priv->cd_gpio.flags & GPIOD_ACTIVE_LOW ? 0 : 1;
 
-		sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP);
+		priv->cd_inverted = dev_read_bool(dev, "cd-inverted");
+		cd_state ^= priv->cd_inverted;
+
+		if (cd_state)
+			sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_DOWN);
+		else
+			sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP);
 	}
 
 	upriv->mmc = &plat->mmc;