On Sat, Jun 8, 2013 at 4:50 AM, Tony Lindgren <tony@xxxxxxxxxxx> wrote: > At least on omaps, each board typically has at least one device > configured as wake-up capable from deeper idle modes. In the > deeper idle modes the normal interrupt wake-up path won't work > as the logic is powered off and separate wake-up hardware is > available either via IO ring or GPIO hardware. The wake-up > event can be device specific, or may need to be dynamically > remuxed to GPIO input for wake-up events. When the wake-up > event happens, it's IRQ need to be called so the device won't > lose interrupts. > > Allow supporting IRQ and GPIO wake-up events if a hardware > spefific module is registered for the enable and disable > calls. > > Done in collaboration with Roger Quadros <rogerq@xxxxxx>. > > Cc: Haojian Zhuang <haojian.zhuang@xxxxxxxxx> > Cc: Peter Ujfalusi <peter.ujfalusi@xxxxxx> > Cc: devicetree-discuss@xxxxxxxxxxxxxxxx > Signed-off-by: Roger Quadros <rogerq@xxxxxx> > Signed-off-by: Tony Lindgren <tony@xxxxxxxxxxx> > --- > .../devicetree/bindings/pinctrl/pinctrl-single.txt | 5 + > drivers/pinctrl/pinctrl-single.c | 104 +++++++++++++++++--- > drivers/pinctrl/pinctrl-single.h | 28 +++++ > 3 files changed, 123 insertions(+), 14 deletions(-) > > diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt > index 08f0c3d..5dfd74b 100644 > --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt > +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt > @@ -68,6 +68,10 @@ Optional properties: > The number of parameters is depend on #pinctrl-single,gpio-range-cells > property. > > +- interrrupts : the interrupt that a function may have for a wake-up event > + > +- gpios: the gpio that a function may have for a wake-up event > + > /* pin base, nr pins & gpio function */ > pinctrl-single,gpio-range = <&range 0 3 0 &range 3 9 1>; > > @@ -204,6 +208,7 @@ pmx_gpio: pinmux@d401e000 { > 0xdc 0x118 > 0xde 0 > >; > + interrupts = <74>; > }; > }; > > diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c > index 0f178d1..7cb7940 100644 > --- a/drivers/pinctrl/pinctrl-single.c > +++ b/drivers/pinctrl/pinctrl-single.c > @@ -19,6 +19,8 @@ > #include <linux/of.h> > #include <linux/of_device.h> > #include <linux/of_address.h> > +#include <linux/of_gpio.h> > +#include <linux/of_irq.h> > > #include <linux/pinctrl/pinctrl.h> > #include <linux/pinctrl/pinmux.h> > @@ -95,6 +97,8 @@ struct pcs_conf_type { > * @nvals: number of entries in vals array > * @pgnames: array of pingroup names the function uses > * @npgnames: number of pingroup names the function uses > + * @irq: optional irq associated with the function > + * @gpio: optional gpio associated with the function > * @node: list node > */ > struct pcs_function { > @@ -105,6 +109,8 @@ struct pcs_function { > int npgnames; > struct pcs_conf_vals *conf; > int nconfs; > + int irq; > + int gpio; > struct list_head node; > }; > > @@ -410,6 +416,18 @@ static int pcs_get_function(struct pinctrl_dev *pctldev, unsigned pin, > return 0; > } > > +static void pcs_reg_init(struct pcs_reg *p, struct pcs_device *pcs, > + struct pcs_function *func, > + void __iomem *reg, unsigned val) > +{ > + p->read = pcs->read; > + p->write = pcs->write; > + p->irq = func->irq; > + p->gpio = func->gpio; > + p->reg = reg; > + p->val = val; > +} > + > static int pcs_enable(struct pinctrl_dev *pctldev, unsigned fselector, > unsigned group) > { > @@ -442,6 +460,12 @@ static int pcs_enable(struct pinctrl_dev *pctldev, unsigned fselector, > val &= ~mask; > val |= (vals->val & mask); > pcs->write(val, vals->reg); > + if ((func->irq || func->gpio) && pcs->soc && pcs->soc->enable) { > + struct pcs_reg pcsr; > + > + pcs_reg_init(&pcsr, pcs, func, vals->reg, val); > + pcs->soc->enable(pcs->soc, &pcsr); > + } > } > > return 0; > @@ -466,18 +490,6 @@ static void pcs_disable(struct pinctrl_dev *pctldev, unsigned fselector, > return; > } > > - /* > - * Ignore disable if function-off is not specified. Some hardware > - * does not have clearly defined disable function. For pin specific > - * off modes, you can use alternate named states as described in > - * pinctrl-bindings.txt. > - */ > - if (pcs->foff == PCS_OFF_DISABLED) { > - dev_dbg(pcs->dev, "ignoring disable for %s function%i\n", > - func->name, fselector); > - return; > - } > - > dev_dbg(pcs->dev, "disabling function%i %s\n", > fselector, func->name); > > @@ -488,8 +500,28 @@ static void pcs_disable(struct pinctrl_dev *pctldev, unsigned fselector, > vals = &func->vals[i]; > val = pcs->read(vals->reg); > val &= ~pcs->fmask; > - val |= pcs->foff << pcs->fshift; > - pcs->write(val, vals->reg); > + > + /* > + * Ignore disable if function-off is not specified. Some > + * hardware does not have clearly defined disable function. > + * For pin specific off modes, you can use alternate named > + * states as described in pinctrl-bindings.txt. > + */ > + if (pcs->foff == PCS_OFF_DISABLED) { > + dev_dbg(pcs->dev, "ignoring disable for %s function%i\n", > + func->name, fselector); > + } else { > + val |= pcs->foff << pcs->fshift; > + pcs->write(val, vals->reg); > + } > + > + if ((func->irq || func->gpio) && > + pcs->soc && pcs->soc->disable) { > + struct pcs_reg pcsr; > + > + pcs_reg_init(&pcsr, pcs, func, vals->reg, val); > + pcs->soc->disable(pcs->soc, &pcsr); > + } > } > } > > @@ -1007,6 +1039,32 @@ static void pcs_add_conf4(struct pcs_device *pcs, struct device_node *np, > add_setting(settings, param, ret); > } > > +static int pcs_parse_wakeup(struct pcs_device *pcs, struct device_node *np, > + struct pcs_function *function) > +{ > + struct pcs_reg pcsr; > + int i, ret = 0; > + > + for (i = 0; i < function->nvals; i++) { > + struct pcs_func_vals *vals; > + unsigned mask; > + > + vals = &function->vals[i]; > + if (!vals->mask) > + mask = pcs->fmask; > + else > + mask = pcs->fmask & vals->mask; I assume that this patch is used in both v1 & v2 version. Since Manjunathappa changed the logic of distinguishing bits and pins in blew. if (pcs->bits_per_mux) mask = vals->mask; else mask = pcs->fmask Would you like to sync with his style? > + > + pcs_reg_init(&pcsr, pcs, function, vals->reg, > + vals->val & mask); > + ret = pcs->soc->reg_init(pcs->soc, &pcsr); > + if (ret) > + break; > + } > + > + return ret; > +} > + > static int pcs_parse_pinconf(struct pcs_device *pcs, struct device_node *np, > struct pcs_function *func, > struct pinctrl_map **map) > @@ -1176,6 +1234,24 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs, > } else { > *num_maps = 1; > } > + > + if (pcs->flags & PCS_HAS_FUNCTION_IRQ) > + function->irq = irq_of_parse_and_map(np, 0); > + > + if (pcs->flags & PCS_HAS_FUNCTION_GPIO) { > + function->gpio = of_get_gpio(np, 0); > + if (function->gpio > 0 && !function->irq) { > + if (gpio_is_valid(function->gpio)) > + function->irq = gpio_to_irq(function->gpio); > + } > + } > + > + if (function->irq > 0 && pcs->soc && pcs->soc->reg_init) { > + res = pcs_parse_wakeup(pcs, np, function); > + if (res) > + goto free_pingroups; > + } > + > return 0; > > free_pingroups: > diff --git a/drivers/pinctrl/pinctrl-single.h b/drivers/pinctrl/pinctrl-single.h > index 18f3205..c2dcc7a 100644 > --- a/drivers/pinctrl/pinctrl-single.h > +++ b/drivers/pinctrl/pinctrl-single.h > @@ -1,13 +1,41 @@ > +/** > + * struct pcs_reg - pinctrl register > + * @read: pinctrl-single provided register read function > + * @write: pinctrl-single provided register write function > + * @reg: virtual address of a register > + * @val: pinctrl configured value of the register > + * @irq: optional irq specified for wake-up for example > + * @gpio: optional gpio specified for wake-up for example > + * @node: optional list > + */ > +struct pcs_reg { > + unsigned (*read)(void __iomem *reg); > + void (*write)(unsigned val, void __iomem *reg); > + void __iomem *reg; > + unsigned val; > + int irq; > + int gpio; > + struct list_head node; > +}; > + > +#define PCS_HAS_FUNCTION_GPIO (1 << 2) > +#define PCS_HAS_FUNCTION_IRQ (1 << 1) > #define PCS_HAS_PINCONF (1 << 0) > > /** > * struct pcs_soc - SoC specific interface to pinctrl-single > * @data: SoC specific data pointer > * @flags: mask of PCS_HAS_xxx values > + * @reg_init: SoC specific register init function > + * @enable: SoC specific enable function > + * @disable: SoC specific disable function > */ > struct pcs_soc { > void *data; > unsigned flags; > + int (*reg_init)(const struct pcs_soc *soc, struct pcs_reg *r); > + int (*enable)(const struct pcs_soc *soc, struct pcs_reg *r); > + void (*disable)(const struct pcs_soc *soc, struct pcs_reg *r); > }; > > extern int pinctrl_single_probe(struct platform_device *pdev, > For others: Acked-by: Haojian Zhuang <haojian.zhuang@xxxxxxxxx> -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html