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 227aa1aa6eSZhao Qiang #undef DEBUG 237aa1aa6eSZhao Qiang 247aa1aa6eSZhao Qiang static struct qe_pio_regs __iomem *par_io; 257aa1aa6eSZhao Qiang static int num_par_io_ports = 0; 267aa1aa6eSZhao Qiang 277aa1aa6eSZhao Qiang int par_io_init(struct device_node *np) 287aa1aa6eSZhao Qiang { 297aa1aa6eSZhao Qiang struct resource res; 307aa1aa6eSZhao Qiang int ret; 317aa1aa6eSZhao Qiang const u32 *num_ports; 327aa1aa6eSZhao Qiang 337aa1aa6eSZhao Qiang /* Map Parallel I/O ports registers */ 347aa1aa6eSZhao Qiang ret = of_address_to_resource(np, 0, &res); 357aa1aa6eSZhao Qiang if (ret) 367aa1aa6eSZhao Qiang return ret; 377aa1aa6eSZhao Qiang par_io = ioremap(res.start, resource_size(&res)); 387aa1aa6eSZhao Qiang 397aa1aa6eSZhao Qiang num_ports = of_get_property(np, "num-ports", NULL); 407aa1aa6eSZhao Qiang if (num_ports) 417aa1aa6eSZhao Qiang num_par_io_ports = *num_ports; 427aa1aa6eSZhao Qiang 437aa1aa6eSZhao Qiang return 0; 447aa1aa6eSZhao Qiang } 457aa1aa6eSZhao Qiang 467aa1aa6eSZhao Qiang void __par_io_config_pin(struct qe_pio_regs __iomem *par_io, u8 pin, int dir, 477aa1aa6eSZhao Qiang int open_drain, int assignment, int has_irq) 487aa1aa6eSZhao Qiang { 497aa1aa6eSZhao Qiang u32 pin_mask1bit; 507aa1aa6eSZhao Qiang u32 pin_mask2bits; 517aa1aa6eSZhao Qiang u32 new_mask2bits; 527aa1aa6eSZhao Qiang u32 tmp_val; 537aa1aa6eSZhao Qiang 547aa1aa6eSZhao Qiang /* calculate pin location for single and 2 bits information */ 557aa1aa6eSZhao Qiang pin_mask1bit = (u32) (1 << (QE_PIO_PINS - (pin + 1))); 567aa1aa6eSZhao Qiang 577aa1aa6eSZhao Qiang /* Set open drain, if required */ 5877d7676aSRasmus Villemoes tmp_val = qe_ioread32be(&par_io->cpodr); 597aa1aa6eSZhao Qiang if (open_drain) 6077d7676aSRasmus Villemoes qe_iowrite32be(pin_mask1bit | tmp_val, &par_io->cpodr); 617aa1aa6eSZhao Qiang else 6277d7676aSRasmus Villemoes qe_iowrite32be(~pin_mask1bit & tmp_val, &par_io->cpodr); 637aa1aa6eSZhao Qiang 647aa1aa6eSZhao Qiang /* define direction */ 657aa1aa6eSZhao Qiang tmp_val = (pin > (QE_PIO_PINS / 2) - 1) ? 6677d7676aSRasmus Villemoes qe_ioread32be(&par_io->cpdir2) : 6777d7676aSRasmus Villemoes qe_ioread32be(&par_io->cpdir1); 687aa1aa6eSZhao Qiang 697aa1aa6eSZhao Qiang /* get all bits mask for 2 bit per port */ 707aa1aa6eSZhao Qiang pin_mask2bits = (u32) (0x3 << (QE_PIO_PINS - 717aa1aa6eSZhao Qiang (pin % (QE_PIO_PINS / 2) + 1) * 2)); 727aa1aa6eSZhao Qiang 737aa1aa6eSZhao Qiang /* Get the final mask we need for the right definition */ 747aa1aa6eSZhao Qiang new_mask2bits = (u32) (dir << (QE_PIO_PINS - 757aa1aa6eSZhao Qiang (pin % (QE_PIO_PINS / 2) + 1) * 2)); 767aa1aa6eSZhao Qiang 777aa1aa6eSZhao Qiang /* clear and set 2 bits mask */ 787aa1aa6eSZhao Qiang if (pin > (QE_PIO_PINS / 2) - 1) { 7977d7676aSRasmus Villemoes qe_iowrite32be(~pin_mask2bits & tmp_val, &par_io->cpdir2); 807aa1aa6eSZhao Qiang tmp_val &= ~pin_mask2bits; 8177d7676aSRasmus Villemoes qe_iowrite32be(new_mask2bits | tmp_val, &par_io->cpdir2); 827aa1aa6eSZhao Qiang } else { 8377d7676aSRasmus Villemoes qe_iowrite32be(~pin_mask2bits & tmp_val, &par_io->cpdir1); 847aa1aa6eSZhao Qiang tmp_val &= ~pin_mask2bits; 8577d7676aSRasmus Villemoes qe_iowrite32be(new_mask2bits | tmp_val, &par_io->cpdir1); 867aa1aa6eSZhao Qiang } 877aa1aa6eSZhao Qiang /* define pin assignment */ 887aa1aa6eSZhao Qiang tmp_val = (pin > (QE_PIO_PINS / 2) - 1) ? 8977d7676aSRasmus Villemoes qe_ioread32be(&par_io->cppar2) : 9077d7676aSRasmus Villemoes qe_ioread32be(&par_io->cppar1); 917aa1aa6eSZhao Qiang 927aa1aa6eSZhao Qiang new_mask2bits = (u32) (assignment << (QE_PIO_PINS - 937aa1aa6eSZhao Qiang (pin % (QE_PIO_PINS / 2) + 1) * 2)); 947aa1aa6eSZhao Qiang /* clear and set 2 bits mask */ 957aa1aa6eSZhao Qiang if (pin > (QE_PIO_PINS / 2) - 1) { 9677d7676aSRasmus Villemoes qe_iowrite32be(~pin_mask2bits & tmp_val, &par_io->cppar2); 977aa1aa6eSZhao Qiang tmp_val &= ~pin_mask2bits; 9877d7676aSRasmus Villemoes qe_iowrite32be(new_mask2bits | tmp_val, &par_io->cppar2); 997aa1aa6eSZhao Qiang } else { 10077d7676aSRasmus Villemoes qe_iowrite32be(~pin_mask2bits & tmp_val, &par_io->cppar1); 1017aa1aa6eSZhao Qiang tmp_val &= ~pin_mask2bits; 10277d7676aSRasmus Villemoes qe_iowrite32be(new_mask2bits | tmp_val, &par_io->cppar1); 1037aa1aa6eSZhao Qiang } 1047aa1aa6eSZhao Qiang } 1057aa1aa6eSZhao Qiang EXPORT_SYMBOL(__par_io_config_pin); 1067aa1aa6eSZhao Qiang 1077aa1aa6eSZhao Qiang int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain, 1087aa1aa6eSZhao Qiang int assignment, int has_irq) 1097aa1aa6eSZhao Qiang { 1107aa1aa6eSZhao Qiang if (!par_io || port >= num_par_io_ports) 1117aa1aa6eSZhao Qiang return -EINVAL; 1127aa1aa6eSZhao Qiang 1137aa1aa6eSZhao Qiang __par_io_config_pin(&par_io[port], pin, dir, open_drain, assignment, 1147aa1aa6eSZhao Qiang has_irq); 1157aa1aa6eSZhao Qiang return 0; 1167aa1aa6eSZhao Qiang } 1177aa1aa6eSZhao Qiang EXPORT_SYMBOL(par_io_config_pin); 1187aa1aa6eSZhao Qiang 1197aa1aa6eSZhao Qiang int par_io_data_set(u8 port, u8 pin, u8 val) 1207aa1aa6eSZhao Qiang { 1217aa1aa6eSZhao Qiang u32 pin_mask, tmp_val; 1227aa1aa6eSZhao Qiang 1237aa1aa6eSZhao Qiang if (port >= num_par_io_ports) 1247aa1aa6eSZhao Qiang return -EINVAL; 1257aa1aa6eSZhao Qiang if (pin >= QE_PIO_PINS) 1267aa1aa6eSZhao Qiang return -EINVAL; 1277aa1aa6eSZhao Qiang /* calculate pin location */ 1287aa1aa6eSZhao Qiang pin_mask = (u32) (1 << (QE_PIO_PINS - 1 - pin)); 1297aa1aa6eSZhao Qiang 13077d7676aSRasmus Villemoes tmp_val = qe_ioread32be(&par_io[port].cpdata); 1317aa1aa6eSZhao Qiang 1327aa1aa6eSZhao Qiang if (val == 0) /* clear */ 13377d7676aSRasmus Villemoes qe_iowrite32be(~pin_mask & tmp_val, &par_io[port].cpdata); 1347aa1aa6eSZhao Qiang else /* set */ 13577d7676aSRasmus Villemoes qe_iowrite32be(pin_mask | tmp_val, &par_io[port].cpdata); 1367aa1aa6eSZhao Qiang 1377aa1aa6eSZhao Qiang return 0; 1387aa1aa6eSZhao Qiang } 1397aa1aa6eSZhao Qiang EXPORT_SYMBOL(par_io_data_set); 1407aa1aa6eSZhao Qiang 1417aa1aa6eSZhao Qiang int par_io_of_config(struct device_node *np) 1427aa1aa6eSZhao Qiang { 1437aa1aa6eSZhao Qiang struct device_node *pio; 1447aa1aa6eSZhao Qiang int pio_map_len; 1457aa1aa6eSZhao Qiang const unsigned int *pio_map; 1467aa1aa6eSZhao Qiang 1477aa1aa6eSZhao Qiang if (par_io == NULL) { 1487aa1aa6eSZhao Qiang printk(KERN_ERR "par_io not initialized\n"); 1497aa1aa6eSZhao Qiang return -1; 1507aa1aa6eSZhao Qiang } 1517aa1aa6eSZhao Qiang 152abc6311bSRasmus Villemoes pio = of_parse_phandle(np, "pio-handle", 0); 153abc6311bSRasmus Villemoes if (pio == NULL) { 1547aa1aa6eSZhao Qiang printk(KERN_ERR "pio-handle not available\n"); 1557aa1aa6eSZhao Qiang return -1; 1567aa1aa6eSZhao Qiang } 1577aa1aa6eSZhao Qiang 1587aa1aa6eSZhao Qiang pio_map = of_get_property(pio, "pio-map", &pio_map_len); 1597aa1aa6eSZhao Qiang if (pio_map == NULL) { 1607aa1aa6eSZhao Qiang printk(KERN_ERR "pio-map is not set!\n"); 1617aa1aa6eSZhao Qiang return -1; 1627aa1aa6eSZhao Qiang } 1637aa1aa6eSZhao Qiang pio_map_len /= sizeof(unsigned int); 1647aa1aa6eSZhao Qiang if ((pio_map_len % 6) != 0) { 1657aa1aa6eSZhao Qiang printk(KERN_ERR "pio-map format wrong!\n"); 1667aa1aa6eSZhao Qiang return -1; 1677aa1aa6eSZhao Qiang } 1687aa1aa6eSZhao Qiang 1697aa1aa6eSZhao Qiang while (pio_map_len > 0) { 1707aa1aa6eSZhao Qiang par_io_config_pin((u8) pio_map[0], (u8) pio_map[1], 1717aa1aa6eSZhao Qiang (int) pio_map[2], (int) pio_map[3], 1727aa1aa6eSZhao Qiang (int) pio_map[4], (int) pio_map[5]); 1737aa1aa6eSZhao Qiang pio_map += 6; 1747aa1aa6eSZhao Qiang pio_map_len -= 6; 1757aa1aa6eSZhao Qiang } 1767aa1aa6eSZhao Qiang of_node_put(pio); 1777aa1aa6eSZhao Qiang return 0; 1787aa1aa6eSZhao Qiang } 1797aa1aa6eSZhao Qiang EXPORT_SYMBOL(par_io_of_config); 180