Skip to content

Commit 4542452

Browse files
Uwe Kleine-Königgregkh
authored andcommitted
pinctrl: mxs: atomically switch mux and drive strength config
commit da6c2addf66d7ff7d0b090d6267d4292f951e4e6 upstream. To set the mux mode of a pin two bits must be set. Up to now this is implemented using the following idiom: writel(mask, reg + CLR); writel(value, reg + SET); . This however results in the mux mode being 0 between the two writes. On my machine there is an IC's reset pin connected to LCD_D20. The bootloader configures this pin as GPIO output-high (i.e. not holding the IC in reset). When Linux reconfigures the pin to GPIO the short time LCD_D20 is muxed as LCD_D20 instead of GPIO_1_20 is enough to confuse the connected IC. The same problem is present for the pin's drive strength setting which is reset to low drive strength before using the right value. So instead of relying on the hardware to modify the register setting using two writes implement the bit toggling using read-modify-write. Fixes: 1772311 ("pinctrl: add pinctrl-mxs support") Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Acked-by: Shawn Guo <shawnguo@kernel.org> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 7956574 commit 4542452

1 file changed

Lines changed: 12 additions & 4 deletions

File tree

drivers/pinctrl/freescale/pinctrl-mxs.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,16 @@ static int mxs_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,
195195
return 0;
196196
}
197197

198+
static void mxs_pinctrl_rmwl(u32 value, u32 mask, u8 shift, void __iomem *reg)
199+
{
200+
u32 tmp;
201+
202+
tmp = readl(reg);
203+
tmp &= ~(mask << shift);
204+
tmp |= value << shift;
205+
writel(tmp, reg);
206+
}
207+
198208
static int mxs_pinctrl_set_mux(struct pinctrl_dev *pctldev, unsigned selector,
199209
unsigned group)
200210
{
@@ -212,8 +222,7 @@ static int mxs_pinctrl_set_mux(struct pinctrl_dev *pctldev, unsigned selector,
212222
reg += bank * 0x20 + pin / 16 * 0x10;
213223
shift = pin % 16 * 2;
214224

215-
writel(0x3 << shift, reg + CLR);
216-
writel(g->muxsel[i] << shift, reg + SET);
225+
mxs_pinctrl_rmwl(g->muxsel[i], 0x3, shift, reg);
217226
}
218227

219228
return 0;
@@ -280,8 +289,7 @@ static int mxs_pinconf_group_set(struct pinctrl_dev *pctldev,
280289
/* mA */
281290
if (config & MA_PRESENT) {
282291
shift = pin % 8 * 4;
283-
writel(0x3 << shift, reg + CLR);
284-
writel(ma << shift, reg + SET);
292+
mxs_pinctrl_rmwl(ma, 0x3, shift, reg);
285293
}
286294

287295
/* vol */

0 commit comments

Comments
 (0)