// SPDX-License-Identifier: GPL-2.0-or-later /* * arch/powerpc/sysdev/qe_lib/qe_io.c * * QE Parallel I/O ports configuration routines * * Copyright 2006 Freescale Semiconductor, Inc. All rights reserved. * * Author: Li Yang * Based on code from Shlomi Gridish */ #include #include #include #include #include #include #include #undef DEBUG static struct qe_pio_regs __iomem *par_io; 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 = ioremap(res.start, resource_size(&res)); if (!par_io) return -ENOMEM; if (!of_property_read_u32(np, "num-ports", &num_ports)) num_par_io_ports = num_ports; return 0; } void __par_io_config_pin(struct qe_pio_regs __iomem *par_io, u8 pin, int dir, int open_drain, int assignment, int has_irq) { u32 pin_mask1bit; u32 pin_mask2bits; u32 new_mask2bits; u32 tmp_val; /* calculate pin location for single and 2 bits information */ pin_mask1bit = (u32) (1 << (QE_PIO_PINS - (pin + 1))); /* Set open drain, if required */ tmp_val = ioread32be(&par_io->cpodr); if (open_drain) iowrite32be(pin_mask1bit | tmp_val, &par_io->cpodr); else iowrite32be(~pin_mask1bit & tmp_val, &par_io->cpodr); /* define direction */ tmp_val = (pin > (QE_PIO_PINS / 2) - 1) ? ioread32be(&par_io->cpdir2) : ioread32be(&par_io->cpdir1); /* get all bits mask for 2 bit per port */ pin_mask2bits = (u32) (0x3 << (QE_PIO_PINS - (pin % (QE_PIO_PINS / 2) + 1) * 2)); /* Get the final mask we need for the right definition */ new_mask2bits = (u32) (dir << (QE_PIO_PINS - (pin % (QE_PIO_PINS / 2) + 1) * 2)); /* clear and set 2 bits mask */ if (pin > (QE_PIO_PINS / 2) - 1) { iowrite32be(~pin_mask2bits & tmp_val, &par_io->cpdir2); tmp_val &= ~pin_mask2bits; iowrite32be(new_mask2bits | tmp_val, &par_io->cpdir2); } else { iowrite32be(~pin_mask2bits & tmp_val, &par_io->cpdir1); tmp_val &= ~pin_mask2bits; iowrite32be(new_mask2bits | tmp_val, &par_io->cpdir1); } /* define pin assignment */ tmp_val = (pin > (QE_PIO_PINS / 2) - 1) ? ioread32be(&par_io->cppar2) : ioread32be(&par_io->cppar1); new_mask2bits = (u32) (assignment << (QE_PIO_PINS - (pin % (QE_PIO_PINS / 2) + 1) * 2)); /* clear and set 2 bits mask */ if (pin > (QE_PIO_PINS / 2) - 1) { iowrite32be(~pin_mask2bits & tmp_val, &par_io->cppar2); tmp_val &= ~pin_mask2bits; iowrite32be(new_mask2bits | tmp_val, &par_io->cppar2); } else { iowrite32be(~pin_mask2bits & tmp_val, &par_io->cppar1); tmp_val &= ~pin_mask2bits; iowrite32be(new_mask2bits | tmp_val, &par_io->cppar1); } } EXPORT_SYMBOL(__par_io_config_pin); int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain, int assignment, int has_irq) { if (!par_io || port >= num_par_io_ports) return -EINVAL; __par_io_config_pin(&par_io[port], pin, dir, open_drain, assignment, has_irq); 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 >= QE_PIO_PINS) return -EINVAL; /* calculate pin location */ pin_mask = (u32) (1 << (QE_PIO_PINS - 1 - pin)); tmp_val = ioread32be(&par_io[port].cpdata); if (val == 0) /* clear */ iowrite32be(~pin_mask & tmp_val, &par_io[port].cpdata); else /* set */ iowrite32be(pin_mask | tmp_val, &par_io[port].cpdata); return 0; } EXPORT_SYMBOL(par_io_data_set); int par_io_of_config(struct device_node *np) { struct device_node *pio; int pio_map_len; const __be32 *pio_map; if (par_io == NULL) { printk(KERN_ERR "par_io not initialized\n"); return -1; } pio = of_parse_phandle(np, "pio-handle", 0); if (pio == NULL) { printk(KERN_ERR "pio-handle not available\n"); return -1; } pio_map = of_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) { u8 port = be32_to_cpu(pio_map[0]); u8 pin = be32_to_cpu(pio_map[1]); int dir = be32_to_cpu(pio_map[2]); int open_drain = be32_to_cpu(pio_map[3]); int assignment = be32_to_cpu(pio_map[4]); int has_irq = be32_to_cpu(pio_map[5]); par_io_config_pin(port, pin, dir, open_drain, assignment, has_irq); pio_map += 6; pio_map_len -= 6; } of_node_put(pio); return 0; } EXPORT_SYMBOL(par_io_of_config);