[PATCH 2/2] powerpc/QE: implement QE Pin Multiplexing API
With this API we're able to set a QE pin to the GPIO mode or a dedicated peripheral function. The API relies on the fact that QE gpio controllers are registered. If they aren't, the API won't work (gracefully though). There is one caveat though: if anybody occupied the node-data before us, or overwrote it, then bad things will happen. Luckily this is all in the platform code that we fully control, so this should never happen. I could implement more checks (for example we could create a list of successfully registered QE controllers, and compare the node-data in the qe_pin_request()), but this is unneeded if nobody is going to do silly things behind our back. Signed-off-by: Anton Vorontsov [EMAIL PROTECTED] --- arch/powerpc/include/asm/qe.h |9 ++ arch/powerpc/sysdev/qe_lib/gpio.c | 195 + 2 files changed, 204 insertions(+), 0 deletions(-) diff --git a/arch/powerpc/include/asm/qe.h b/arch/powerpc/include/asm/qe.h index edee15d..31ddbc9 100644 --- a/arch/powerpc/include/asm/qe.h +++ b/arch/powerpc/include/asm/qe.h @@ -112,6 +112,15 @@ extern int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain, int assignment, int has_irq); extern int par_io_data_set(u8 port, u8 pin, u8 val); +/* + * Pin multiplexing functions. + */ +struct qe_pin; +extern struct qe_pin *qe_pin_request(struct device_node *np, int index); +extern void qe_pin_free(struct qe_pin *qe_pin); +extern void qe_pin_set_gpio(struct qe_pin *qe_pin); +extern void qe_pin_set_dedicated(struct qe_pin *pin); + /* QE internal API */ int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input); enum qe_clock qe_clock_source(const char *source); diff --git a/arch/powerpc/sysdev/qe_lib/gpio.c b/arch/powerpc/sysdev/qe_lib/gpio.c index 8e5a0bc..7f10b18 100644 --- a/arch/powerpc/sysdev/qe_lib/gpio.c +++ b/arch/powerpc/sysdev/qe_lib/gpio.c @@ -14,6 +14,7 @@ #include linux/kernel.h #include linux/init.h #include linux/spinlock.h +#include linux/err.h #include linux/io.h #include linux/of.h #include linux/of_gpio.h @@ -24,8 +25,14 @@ struct qe_gpio_chip { struct of_mm_gpio_chip mm_gc; spinlock_t lock; + unsigned long pin_flags[QE_PIO_PINS]; +#define QE_PIN_REQUESTED 0 + /* shadowed data register to clear/set bits safely */ u32 cpdata; + + /* saved_regs used to restore dedicated functions */ + struct qe_pio_regs saved_regs; }; static inline struct qe_gpio_chip * @@ -40,6 +47,12 @@ static void qe_gpio_save_regs(struct of_mm_gpio_chip *mm_gc) struct qe_pio_regs __iomem *regs = mm_gc-regs; qe_gc-cpdata = in_be32(regs-cpdata); + qe_gc-saved_regs.cpdata = qe_gc-cpdata; + qe_gc-saved_regs.cpdir1 = in_be32(regs-cpdir1); + qe_gc-saved_regs.cpdir2 = in_be32(regs-cpdir2); + qe_gc-saved_regs.cppar1 = in_be32(regs-cppar1); + qe_gc-saved_regs.cppar2 = in_be32(regs-cppar2); + qe_gc-saved_regs.cpodr = in_be32(regs-cpodr); } static int qe_gpio_get(struct gpio_chip *gc, unsigned int gpio) @@ -103,6 +116,188 @@ static int qe_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) return 0; } +struct qe_pin { + /* +* The qe_gpio_chip name is unfortunate, we should change that to +* something like qe_pio_controller. Someday. +*/ + struct qe_gpio_chip *controller; + int num; +}; + +/** + * qe_pin_request - Request a QE pin + * @np:device node to get a pin from + * @index: index of a pin in the device tree + * Context:non-atomic + * + * This function return qe_pin so that you could use it with the rest of + * the QE Pin Multiplexing API. + */ +struct qe_pin *qe_pin_request(struct device_node *np, int index) +{ + struct qe_pin *qe_pin; + struct device_node *gc; + struct of_gpio_chip *of_gc = NULL; + struct of_mm_gpio_chip *mm_gc; + struct qe_gpio_chip *qe_gc; + int err; + int size; + const void *gpio_spec; + const u32 *gpio_cells; + unsigned long flags; + + qe_pin = kzalloc(sizeof(*qe_pin), GFP_KERNEL); + if (!qe_pin) { + pr_debug(%s: can't allocate memory\n, __func__); + return ERR_PTR(-ENOMEM); + } + + err = of_parse_phandles_with_args(np, gpios, #gpio-cells, index, + gc, gpio_spec); + if (err) { + pr_debug(%s: can't parse gpios property\n, __func__); + goto err0; + } + + if (!of_device_is_compatible(gc, fsl,mpc8323-qe-pario-bank)) { + pr_debug(%s: tried to get a non-qe pin\n, __func__); + err = -EINVAL; + goto err1; + } + + of_gc = gc-data; + if (!of_gc) { + pr_debug(%s: gpio controller %s isn't registered\n, +np-full_name, gc-full_name); + err = -ENODEV; + goto
[PATCH 2/2] powerpc/QE: implement QE Pin Multiplexing API
Today the API is still based on a fact that QE gpio controllers are registered. If they aren't, the API won't work (gracefully though). There is one caveat though: if anybody occupied the node-data before us, or overwrote it, then bad things will happen. Luckily this is all in the platform code that we fully control, so this should never happen. I could implement more checks (for example we could create a list of successfully registered QE controllers, and compare the node-data in the qe_pin_get()), but this is unneeded if nobody is going to do silly things behind our back. Signed-off-by: Anton Vorontsov [EMAIL PROTECTED] --- p.s. I should probably change qe_pin_get() to allocate and return struct qe_pin instead of accepting already allocated one. arch/powerpc/include/asm/qe.h | 20 + arch/powerpc/sysdev/qe_lib/gpio.c | 167 + 2 files changed, 187 insertions(+), 0 deletions(-) diff --git a/arch/powerpc/include/asm/qe.h b/arch/powerpc/include/asm/qe.h index edee15d..3f15b2f 100644 --- a/arch/powerpc/include/asm/qe.h +++ b/arch/powerpc/include/asm/qe.h @@ -112,6 +112,26 @@ extern int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain, int assignment, int has_irq); extern int par_io_data_set(u8 port, u8 pin, u8 val); +/* + * Pin multiplexing functions. + */ +struct qe_gpio_chip; + +struct qe_pin { + /* +* The qe_gpio_chip name is unfortunate, we should change that to +* something like qe_pio_controller. Someday. +*/ + struct qe_gpio_chip *controller; + int num; +}; + +extern int qe_pin_get(struct device_node *np, int index, + struct qe_pin *qe_pin); +extern void qe_pin_put(struct qe_pin *qe_pin); +extern void qe_pin_set_gpio(struct qe_pin *qe_pin); +extern void qe_pin_set_dedicated(struct qe_pin *pin); + /* QE internal API */ int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input); enum qe_clock qe_clock_source(const char *source); diff --git a/arch/powerpc/sysdev/qe_lib/gpio.c b/arch/powerpc/sysdev/qe_lib/gpio.c index 8e5a0bc..f0d504b 100644 --- a/arch/powerpc/sysdev/qe_lib/gpio.c +++ b/arch/powerpc/sysdev/qe_lib/gpio.c @@ -24,8 +24,14 @@ struct qe_gpio_chip { struct of_mm_gpio_chip mm_gc; spinlock_t lock; +#define QE_PIN_REQUESTED 0 + unsigned long pin_flags[QE_PIO_PINS]; + /* shadowed data register to clear/set bits safely */ u32 cpdata; + + /* saved_regs used to restore dedicated functions */ + struct qe_pio_regs saved_regs; }; static inline struct qe_gpio_chip * @@ -40,6 +46,12 @@ static void qe_gpio_save_regs(struct of_mm_gpio_chip *mm_gc) struct qe_pio_regs __iomem *regs = mm_gc-regs; qe_gc-cpdata = in_be32(regs-cpdata); + qe_gc-saved_regs.cpdata = qe_gc-cpdata; + qe_gc-saved_regs.cpdir1 = in_be32(regs-cpdir1); + qe_gc-saved_regs.cpdir2 = in_be32(regs-cpdir2); + qe_gc-saved_regs.cppar1 = in_be32(regs-cppar1); + qe_gc-saved_regs.cppar2 = in_be32(regs-cppar2); + qe_gc-saved_regs.cpodr = in_be32(regs-cpodr); } static int qe_gpio_get(struct gpio_chip *gc, unsigned int gpio) @@ -103,6 +115,161 @@ static int qe_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) return 0; } +/** + * qe_pin_get - Get a QE pin from the device tree + * @np:device node to get a pin from + * @index: index of a pin in the device tree + * @qe_pin:pointer to the allocated qe_pin structure + * + * This function finds a pin from the device in the device tree and fills + * the qe_pin structure so that you could use it with the rest of QE Pin + * Multiplexing API. + */ +int qe_pin_get(struct device_node *np, int index, struct qe_pin *qe_pin) +{ + struct device_node *gc; + struct of_gpio_chip *of_gc = NULL; + struct of_mm_gpio_chip *mm_gc; + struct qe_gpio_chip *qe_gc; + int ret; + int size; + const void *gpio_spec; + const u32 *gpio_cells; + unsigned long flags; + + ret = of_parse_phandles_with_args(np, gpios, #gpio-cells, index, + gc, gpio_spec); + if (ret) { + pr_debug(%s: can't parse gpios property\n, __func__); + return ret; + } + + if (!of_device_is_compatible(gc, fsl,mpc8323-qe-pario-bank)) { + pr_debug(%s: tried to get a non-qe pin\n, __func__); + ret = -EINVAL; + goto err1; + } + + of_gc = gc-data; + if (!of_gc) { + pr_debug(%s: gpio controller %s isn't registered\n, +np-full_name, gc-full_name); + goto err1; + } + + gpio_cells = of_get_property(gc, #gpio-cells, size); + if (!gpio_cells || size != sizeof(*gpio_cells) || + *gpio_cells != of_gc-gpio_cells) { + pr_debug(%s: wrong #gpio-cells for