12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 27aa1aa6eSZhao Qiang /* 37aa1aa6eSZhao Qiang * arch/powerpc/sysdev/qe_lib/qe_io.c 47aa1aa6eSZhao Qiang * 57aa1aa6eSZhao Qiang * QE Parallel I/O ports configuration routines 67aa1aa6eSZhao Qiang * 77aa1aa6eSZhao Qiang * Copyright 2006 Freescale Semiconductor, Inc. All rights reserved. 87aa1aa6eSZhao Qiang * 97aa1aa6eSZhao Qiang * Author: Li Yang <LeoLi@freescale.com> 107aa1aa6eSZhao Qiang * Based on code from Shlomi Gridish <gridish@freescale.com> 117aa1aa6eSZhao Qiang */ 127aa1aa6eSZhao Qiang 137aa1aa6eSZhao Qiang #include <linux/stddef.h> 147aa1aa6eSZhao Qiang #include <linux/kernel.h> 157aa1aa6eSZhao Qiang #include <linux/errno.h> 167aa1aa6eSZhao Qiang #include <linux/module.h> 177aa1aa6eSZhao Qiang #include <linux/ioport.h> 187aa1aa6eSZhao Qiang 197aa1aa6eSZhao Qiang #include <asm/io.h> 207aa1aa6eSZhao Qiang #include <soc/fsl/qe/qe.h> 217aa1aa6eSZhao Qiang #include <asm/prom.h> 227aa1aa6eSZhao Qiang #include <sysdev/fsl_soc.h> 237aa1aa6eSZhao Qiang 247aa1aa6eSZhao Qiang #undef DEBUG 257aa1aa6eSZhao Qiang 267aa1aa6eSZhao Qiang static struct qe_pio_regs __iomem *par_io; 277aa1aa6eSZhao Qiang static int num_par_io_ports = 0; 287aa1aa6eSZhao Qiang 297aa1aa6eSZhao Qiang int par_io_init(struct device_node *np) 307aa1aa6eSZhao Qiang { 317aa1aa6eSZhao Qiang struct resource res; 327aa1aa6eSZhao Qiang int ret; 337aa1aa6eSZhao Qiang const u32 *num_ports; 347aa1aa6eSZhao Qiang 357aa1aa6eSZhao Qiang /* Map Parallel I/O ports registers */ 367aa1aa6eSZhao Qiang ret = of_address_to_resource(np, 0, &res); 377aa1aa6eSZhao Qiang if (ret) 387aa1aa6eSZhao Qiang return ret; 397aa1aa6eSZhao Qiang par_io = ioremap(res.start, resource_size(&res)); 407aa1aa6eSZhao Qiang 417aa1aa6eSZhao Qiang num_ports = of_get_property(np, "num-ports", NULL); 427aa1aa6eSZhao Qiang if (num_ports) 437aa1aa6eSZhao Qiang num_par_io_ports = *num_ports; 447aa1aa6eSZhao Qiang 457aa1aa6eSZhao Qiang return 0; 467aa1aa6eSZhao Qiang } 477aa1aa6eSZhao Qiang 487aa1aa6eSZhao Qiang void __par_io_config_pin(struct qe_pio_regs __iomem *par_io, u8 pin, int dir, 497aa1aa6eSZhao Qiang int open_drain, int assignment, int has_irq) 507aa1aa6eSZhao Qiang { 517aa1aa6eSZhao Qiang u32 pin_mask1bit; 527aa1aa6eSZhao Qiang u32 pin_mask2bits; 537aa1aa6eSZhao Qiang u32 new_mask2bits; 547aa1aa6eSZhao Qiang u32 tmp_val; 557aa1aa6eSZhao Qiang 567aa1aa6eSZhao Qiang /* calculate pin location for single and 2 bits information */ 577aa1aa6eSZhao Qiang pin_mask1bit = (u32) (1 << (QE_PIO_PINS - (pin + 1))); 587aa1aa6eSZhao Qiang 597aa1aa6eSZhao Qiang /* Set open drain, if required */ 6077d7676aSRasmus Villemoes tmp_val = qe_ioread32be(&par_io->cpodr); 617aa1aa6eSZhao Qiang if (open_drain) 6277d7676aSRasmus Villemoes qe_iowrite32be(pin_mask1bit | tmp_val, &par_io->cpodr); 637aa1aa6eSZhao Qiang else 6477d7676aSRasmus Villemoes qe_iowrite32be(~pin_mask1bit & tmp_val, &par_io->cpodr); 657aa1aa6eSZhao Qiang 667aa1aa6eSZhao Qiang /* define direction */ 677aa1aa6eSZhao Qiang tmp_val = (pin > (QE_PIO_PINS / 2) - 1) ? 6877d7676aSRasmus Villemoes qe_ioread32be(&par_io->cpdir2) : 6977d7676aSRasmus Villemoes qe_ioread32be(&par_io->cpdir1); 707aa1aa6eSZhao Qiang 717aa1aa6eSZhao Qiang /* get all bits mask for 2 bit per port */ 727aa1aa6eSZhao Qiang pin_mask2bits = (u32) (0x3 << (QE_PIO_PINS - 737aa1aa6eSZhao Qiang (pin % (QE_PIO_PINS / 2) + 1) * 2)); 747aa1aa6eSZhao Qiang 757aa1aa6eSZhao Qiang /* Get the final mask we need for the right definition */ 767aa1aa6eSZhao Qiang new_mask2bits = (u32) (dir << (QE_PIO_PINS - 777aa1aa6eSZhao Qiang (pin % (QE_PIO_PINS / 2) + 1) * 2)); 787aa1aa6eSZhao Qiang 797aa1aa6eSZhao Qiang /* clear and set 2 bits mask */ 807aa1aa6eSZhao Qiang if (pin > (QE_PIO_PINS / 2) - 1) { 8177d7676aSRasmus Villemoes qe_iowrite32be(~pin_mask2bits & tmp_val, &par_io->cpdir2); 827aa1aa6eSZhao Qiang tmp_val &= ~pin_mask2bits; 8377d7676aSRasmus Villemoes qe_iowrite32be(new_mask2bits | tmp_val, &par_io->cpdir2); 847aa1aa6eSZhao Qiang } else { 8577d7676aSRasmus Villemoes qe_iowrite32be(~pin_mask2bits & tmp_val, &par_io->cpdir1); 867aa1aa6eSZhao Qiang tmp_val &= ~pin_mask2bits; 8777d7676aSRasmus Villemoes qe_iowrite32be(new_mask2bits | tmp_val, &par_io->cpdir1); 887aa1aa6eSZhao Qiang } 897aa1aa6eSZhao Qiang /* define pin assignment */ 907aa1aa6eSZhao Qiang tmp_val = (pin > (QE_PIO_PINS / 2) - 1) ? 9177d7676aSRasmus Villemoes qe_ioread32be(&par_io->cppar2) : 9277d7676aSRasmus Villemoes qe_ioread32be(&par_io->cppar1); 937aa1aa6eSZhao Qiang 947aa1aa6eSZhao Qiang new_mask2bits = (u32) (assignment << (QE_PIO_PINS - 957aa1aa6eSZhao Qiang (pin % (QE_PIO_PINS / 2) + 1) * 2)); 967aa1aa6eSZhao Qiang /* clear and set 2 bits mask */ 977aa1aa6eSZhao Qiang if (pin > (QE_PIO_PINS / 2) - 1) { 9877d7676aSRasmus Villemoes qe_iowrite32be(~pin_mask2bits & tmp_val, &par_io->cppar2); 997aa1aa6eSZhao Qiang tmp_val &= ~pin_mask2bits; 10077d7676aSRasmus Villemoes qe_iowrite32be(new_mask2bits | tmp_val, &par_io->cppar2); 1017aa1aa6eSZhao Qiang } else { 10277d7676aSRasmus Villemoes qe_iowrite32be(~pin_mask2bits & tmp_val, &par_io->cppar1); 1037aa1aa6eSZhao Qiang tmp_val &= ~pin_mask2bits; 10477d7676aSRasmus Villemoes qe_iowrite32be(new_mask2bits | tmp_val, &par_io->cppar1); 1057aa1aa6eSZhao Qiang } 1067aa1aa6eSZhao Qiang } 1077aa1aa6eSZhao Qiang EXPORT_SYMBOL(__par_io_config_pin); 1087aa1aa6eSZhao Qiang 1097aa1aa6eSZhao Qiang int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain, 1107aa1aa6eSZhao Qiang int assignment, int has_irq) 1117aa1aa6eSZhao Qiang { 1127aa1aa6eSZhao Qiang if (!par_io || port >= num_par_io_ports) 1137aa1aa6eSZhao Qiang return -EINVAL; 1147aa1aa6eSZhao Qiang 1157aa1aa6eSZhao Qiang __par_io_config_pin(&par_io[port], pin, dir, open_drain, assignment, 1167aa1aa6eSZhao Qiang has_irq); 1177aa1aa6eSZhao Qiang return 0; 1187aa1aa6eSZhao Qiang } 1197aa1aa6eSZhao Qiang EXPORT_SYMBOL(par_io_config_pin); 1207aa1aa6eSZhao Qiang 1217aa1aa6eSZhao Qiang int par_io_data_set(u8 port, u8 pin, u8 val) 1227aa1aa6eSZhao Qiang { 1237aa1aa6eSZhao Qiang u32 pin_mask, tmp_val; 1247aa1aa6eSZhao Qiang 1257aa1aa6eSZhao Qiang if (port >= num_par_io_ports) 1267aa1aa6eSZhao Qiang return -EINVAL; 1277aa1aa6eSZhao Qiang if (pin >= QE_PIO_PINS) 1287aa1aa6eSZhao Qiang return -EINVAL; 1297aa1aa6eSZhao Qiang /* calculate pin location */ 1307aa1aa6eSZhao Qiang pin_mask = (u32) (1 << (QE_PIO_PINS - 1 - pin)); 1317aa1aa6eSZhao Qiang 13277d7676aSRasmus Villemoes tmp_val = qe_ioread32be(&par_io[port].cpdata); 1337aa1aa6eSZhao Qiang 1347aa1aa6eSZhao Qiang if (val == 0) /* clear */ 13577d7676aSRasmus Villemoes qe_iowrite32be(~pin_mask & tmp_val, &par_io[port].cpdata); 1367aa1aa6eSZhao Qiang else /* set */ 13777d7676aSRasmus Villemoes qe_iowrite32be(pin_mask | tmp_val, &par_io[port].cpdata); 1387aa1aa6eSZhao Qiang 1397aa1aa6eSZhao Qiang return 0; 1407aa1aa6eSZhao Qiang } 1417aa1aa6eSZhao Qiang EXPORT_SYMBOL(par_io_data_set); 1427aa1aa6eSZhao Qiang 1437aa1aa6eSZhao Qiang int par_io_of_config(struct device_node *np) 1447aa1aa6eSZhao Qiang { 1457aa1aa6eSZhao Qiang struct device_node *pio; 1467aa1aa6eSZhao Qiang const phandle *ph; 1477aa1aa6eSZhao Qiang int pio_map_len; 1487aa1aa6eSZhao Qiang const unsigned int *pio_map; 1497aa1aa6eSZhao Qiang 1507aa1aa6eSZhao Qiang if (par_io == NULL) { 1517aa1aa6eSZhao Qiang printk(KERN_ERR "par_io not initialized\n"); 1527aa1aa6eSZhao Qiang return -1; 1537aa1aa6eSZhao Qiang } 1547aa1aa6eSZhao Qiang 1557aa1aa6eSZhao Qiang ph = of_get_property(np, "pio-handle", NULL); 1567aa1aa6eSZhao Qiang if (ph == NULL) { 1577aa1aa6eSZhao Qiang printk(KERN_ERR "pio-handle not available\n"); 1587aa1aa6eSZhao Qiang return -1; 1597aa1aa6eSZhao Qiang } 1607aa1aa6eSZhao Qiang 1617aa1aa6eSZhao Qiang pio = of_find_node_by_phandle(*ph); 1627aa1aa6eSZhao Qiang 1637aa1aa6eSZhao Qiang pio_map = of_get_property(pio, "pio-map", &pio_map_len); 1647aa1aa6eSZhao Qiang if (pio_map == NULL) { 1657aa1aa6eSZhao Qiang printk(KERN_ERR "pio-map is not set!\n"); 1667aa1aa6eSZhao Qiang return -1; 1677aa1aa6eSZhao Qiang } 1687aa1aa6eSZhao Qiang pio_map_len /= sizeof(unsigned int); 1697aa1aa6eSZhao Qiang if ((pio_map_len % 6) != 0) { 1707aa1aa6eSZhao Qiang printk(KERN_ERR "pio-map format wrong!\n"); 1717aa1aa6eSZhao Qiang return -1; 1727aa1aa6eSZhao Qiang } 1737aa1aa6eSZhao Qiang 1747aa1aa6eSZhao Qiang while (pio_map_len > 0) { 1757aa1aa6eSZhao Qiang par_io_config_pin((u8) pio_map[0], (u8) pio_map[1], 1767aa1aa6eSZhao Qiang (int) pio_map[2], (int) pio_map[3], 1777aa1aa6eSZhao Qiang (int) pio_map[4], (int) pio_map[5]); 1787aa1aa6eSZhao Qiang pio_map += 6; 1797aa1aa6eSZhao Qiang pio_map_len -= 6; 1807aa1aa6eSZhao Qiang } 1817aa1aa6eSZhao Qiang of_node_put(pio); 1827aa1aa6eSZhao Qiang return 0; 1837aa1aa6eSZhao Qiang } 1847aa1aa6eSZhao Qiang EXPORT_SYMBOL(par_io_of_config); 185