From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from de01egw02.freescale.net (de01egw02.freescale.net [192.88.165.103]) by ozlabs.org (Postfix) with ESMTP id 8B5EC67B93 for ; Sun, 1 Oct 2006 09:34:10 +1000 (EST) Date: Sat, 30 Sep 2006 18:33:54 -0500 From: Kim Phillips To: linuxppc-dev@ozlabs.org Subject: [PATCH 5/15] qe_lib: Add QE I/O ports API Message-Id: <20060930183354.736ce4e2.kim.phillips@freescale.com> Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , qe_lib: Add QE I/O ports API Signed-off-by: Li Yang Signed-off-by: Shlomi Gridish Signed-off-by: Kim Phillips --- arch/powerpc/sysdev/qe_lib/qe_io.c | 230 ++++++++++++++++++++++++++++++++++++ 1 files changed, 230 insertions(+), 0 deletions(-) diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/arch/powerpc/sysdev/qe_lib/qe_io.c new file mode 100644 index 0000000..265b464 --- /dev/null +++ b/arch/powerpc/sysdev/qe_lib/qe_io.c @@ -0,0 +1,230 @@ +/* + * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. + * + * Author: Li Yang + * + * Description: + * QE Parallel I/O ports configuration routines. Based on code from + * Shlomi Gridish + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#undef DEBUG + +#define NUM_OF_PINS 32 + +struct port_regs { + u32 cpodr; /* Open drain register */ + u32 cpdata; /* Data register */ + u32 cpdir1; /* Direction register */ + u32 cpdir2; /* Direction register */ + u32 cppar1; /* Pin assignment register */ + u32 cppar2; /* Pin assignment register */ +}; + +static struct port_regs *par_io = NULL; +static int num_par_io_ports = 0; + +int par_io_init(struct device_node *np) +{ + struct resource res; + int ret; + u32 *num_ports; + + /* Map Parallel I/O ports registers */ + ret = of_address_to_resource(np, 0, &res); + if (ret) + return ret; + par_io = (struct port_regs *)ioremap(res.start, res.end - res.start + 1); + + num_ports = get_property(np, "num-ports", NULL); + if (num_ports) + num_par_io_ports = *num_ports; + + return 0; +} + +int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain, + int assignment, int has_irq) +{ + u32 pinMask1bit, pinMask2bits, newMask2bits, tmp_val; + + if (!par_io) + return -1; + + /* calculate pin location for single and 2 bits information */ + pinMask1bit = (u32) (1 << (NUM_OF_PINS - (pin + 1))); + + /* Set open drain, if required */ + tmp_val = in_be32(&par_io[port].cpodr); + if (open_drain) + out_be32(&par_io[port].cpodr, pinMask1bit | tmp_val); + else + out_be32(&par_io[port].cpodr, ~pinMask1bit & tmp_val); + + /* define direction */ + tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ? + in_be32(&par_io[port].cpdir2) : + in_be32(&par_io[port].cpdir1); + + /* get all bits mask for 2 bit per port */ + pinMask2bits = (u32) (0x3 << + (NUM_OF_PINS - + (pin % (NUM_OF_PINS / 2) + 1) * 2)); + + /* Get the final mask we need for the right definition */ + newMask2bits = (u32) (dir << + (NUM_OF_PINS - + (pin % (NUM_OF_PINS / 2) + 1) * 2)); + + /* clear and set 2 bits mask */ + if (pin > (NUM_OF_PINS / 2) - 1) { + out_be32(&par_io[port].cpdir2, + ~pinMask2bits & tmp_val); + tmp_val &= ~pinMask2bits; + out_be32(&par_io[port].cpdir2, newMask2bits | tmp_val); + } else { + out_be32(&par_io[port].cpdir1, + ~pinMask2bits & tmp_val); + tmp_val &= ~pinMask2bits; + out_be32(&par_io[port].cpdir1, newMask2bits | tmp_val); + } + /* define pin assignment */ + tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ? + in_be32(&par_io[port].cppar2) : + in_be32(&par_io[port].cppar1); + + newMask2bits = (u32) (assignment << (NUM_OF_PINS - + (pin % (NUM_OF_PINS / 2) + 1) * 2)); + /* clear and set 2 bits mask */ + if (pin > (NUM_OF_PINS / 2) - 1) { + out_be32(&par_io[port].cppar2, + ~pinMask2bits & tmp_val); + tmp_val &= ~pinMask2bits; + out_be32(&par_io[port].cppar2, newMask2bits | tmp_val); + } else { + out_be32(&par_io[port].cppar1, + ~pinMask2bits & tmp_val); + tmp_val &= ~pinMask2bits; + out_be32(&par_io[port].cppar1, newMask2bits | tmp_val); + } + + return 0; +} + +EXPORT_SYMBOL(par_io_config_pin); + +int par_io_data_set(u8 port, u8 pin, u8 val) +{ + u32 pin_mask, tmp_val; + + if (port >= num_par_io_ports) + return -EINVAL; + if (pin >= NUM_OF_PINS) + return -EINVAL; + /* calculate pin location */ + pin_mask = (u32) (1 << (NUM_OF_PINS - 1 - pin)); + + tmp_val = in_be32(&par_io[port].cpdata); + + if (val == 0) /* clear */ + out_be32(&par_io[port].cpdata, ~pin_mask & tmp_val); + else /* set */ + out_be32(&par_io[port].cpdata, pin_mask | tmp_val); + + return 0; +} + +EXPORT_SYMBOL(par_io_data_set); + +int par_io_of_config(struct device_node *np) +{ + struct device_node *pio; + phandle *ph; + int pio_map_len; + unsigned int *pio_map; + + if (par_io == NULL) { + printk(KERN_ERR "par_io not initialized \n"); + return -1; + } + + ph = (phandle *) get_property(np, "pio-handle", NULL); + if (ph == 0) { + printk(KERN_ERR "pio-handle not available \n"); + return -1; + } + + pio = of_find_node_by_phandle(*ph); + + pio_map = (unsigned int *) + get_property(pio, "pio-map", &pio_map_len); + if (pio_map == NULL) { + printk(KERN_ERR "pio-map is not set! \n"); + return -1; + } + pio_map_len /= sizeof(unsigned int); + if ((pio_map_len % 6) != 0) { + printk(KERN_ERR "pio-map format wrong! \n"); + return -1; + } + + while (pio_map_len > 0) { + par_io_config_pin((u8) pio_map[0], (u8) pio_map[1], + (int) pio_map[2], (int) pio_map[3], + (int) pio_map[4], (int) pio_map[5]); + pio_map += 6; + pio_map_len -= 6; + } + of_node_put(pio); + return 0; +} +EXPORT_SYMBOL(par_io_of_config); + +#ifdef DEBUG +static void dump_par_io(void) +{ + int i; + + printk(KERN_INFO "PAR IO registars:\n"); + printk(KERN_INFO "Base address: 0x%08x\n", (u32) par_io); + for (i = 0; i < num_par_io_ports; i++) { + printk(KERN_INFO "cpodr[%d] : addr - 0x%08x, val - 0x%08x\n", + i, (u32) & par_io[i].cpodr, + in_be32(&par_io[i].cpodr)); + printk(KERN_INFO "cpdata[%d]: addr - 0x%08x, val - 0x%08x\n", + i, (u32) & par_io[i].cpdata, + in_be32(&par_io[i].cpdata)); + printk(KERN_INFO "cpdir1[%d]: addr - 0x%08x, val - 0x%08x\n", + i, (u32) & par_io[i].cpdir1, + in_be32(&par_io[i].cpdir1)); + printk(KERN_INFO "cpdir2[%d]: addr - 0x%08x, val - 0x%08x\n", + i, (u32) & par_io[i].cpdir2, + in_be32(&par_io[i].cpdir2)); + printk(KERN_INFO "cppar1[%d]: addr - 0x%08x, val - 0x%08x\n", + i, (u32) & par_io[i].cppar1, + in_be32(&par_io[i].cppar1)); + printk(KERN_INFO "cppar2[%d]: addr - 0x%08x, val - 0x%08x\n", + i, (u32) & par_io[i].cppar2, + in_be32(&par_io[i].cppar2)); + } + +} + +EXPORT_SYMBOL(dump_par_io); +#endif -- 1.4.2.1