Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Janz MODULbus VMOD-TTL GPIO Driver
0004  *
0005  * Copyright (c) 2010 Ira W. Snyder <iws@ovro.caltech.edu>
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/init.h>
0011 #include <linux/interrupt.h>
0012 #include <linux/delay.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/io.h>
0015 #include <linux/gpio/driver.h>
0016 #include <linux/slab.h>
0017 #include <linux/bitops.h>
0018 
0019 #include <linux/mfd/janz.h>
0020 
0021 #define DRV_NAME "janz-ttl"
0022 
0023 #define PORTA_DIRECTION     0x23
0024 #define PORTB_DIRECTION     0x2B
0025 #define PORTC_DIRECTION     0x06
0026 #define PORTA_IOCTL     0x24
0027 #define PORTB_IOCTL     0x2C
0028 #define PORTC_IOCTL     0x07
0029 
0030 #define MASTER_INT_CTL      0x00
0031 #define MASTER_CONF_CTL     0x01
0032 
0033 #define CONF_PAE        BIT(2)
0034 #define CONF_PBE        BIT(7)
0035 #define CONF_PCE        BIT(4)
0036 
0037 struct ttl_control_regs {
0038     __be16 portc;
0039     __be16 portb;
0040     __be16 porta;
0041     __be16 control;
0042 };
0043 
0044 struct ttl_module {
0045     struct gpio_chip gpio;
0046 
0047     /* base address of registers */
0048     struct ttl_control_regs __iomem *regs;
0049 
0050     u8 portc_shadow;
0051     u8 portb_shadow;
0052     u8 porta_shadow;
0053 
0054     spinlock_t lock;
0055 };
0056 
0057 static int ttl_get_value(struct gpio_chip *gpio, unsigned offset)
0058 {
0059     struct ttl_module *mod = dev_get_drvdata(gpio->parent);
0060     u8 *shadow;
0061     int ret;
0062 
0063     if (offset < 8) {
0064         shadow = &mod->porta_shadow;
0065     } else if (offset < 16) {
0066         shadow = &mod->portb_shadow;
0067         offset -= 8;
0068     } else {
0069         shadow = &mod->portc_shadow;
0070         offset -= 16;
0071     }
0072 
0073     spin_lock(&mod->lock);
0074     ret = *shadow & BIT(offset);
0075     spin_unlock(&mod->lock);
0076     return !!ret;
0077 }
0078 
0079 static void ttl_set_value(struct gpio_chip *gpio, unsigned offset, int value)
0080 {
0081     struct ttl_module *mod = dev_get_drvdata(gpio->parent);
0082     void __iomem *port;
0083     u8 *shadow;
0084 
0085     if (offset < 8) {
0086         port = &mod->regs->porta;
0087         shadow = &mod->porta_shadow;
0088     } else if (offset < 16) {
0089         port = &mod->regs->portb;
0090         shadow = &mod->portb_shadow;
0091         offset -= 8;
0092     } else {
0093         port = &mod->regs->portc;
0094         shadow = &mod->portc_shadow;
0095         offset -= 16;
0096     }
0097 
0098     spin_lock(&mod->lock);
0099     if (value)
0100         *shadow |= BIT(offset);
0101     else
0102         *shadow &= ~BIT(offset);
0103 
0104     iowrite16be(*shadow, port);
0105     spin_unlock(&mod->lock);
0106 }
0107 
0108 static void ttl_write_reg(struct ttl_module *mod, u8 reg, u16 val)
0109 {
0110     iowrite16be(reg, &mod->regs->control);
0111     iowrite16be(val, &mod->regs->control);
0112 }
0113 
0114 static void ttl_setup_device(struct ttl_module *mod)
0115 {
0116     /* reset the device to a known state */
0117     iowrite16be(0x0000, &mod->regs->control);
0118     iowrite16be(0x0001, &mod->regs->control);
0119     iowrite16be(0x0000, &mod->regs->control);
0120 
0121     /* put all ports in open-drain mode */
0122     ttl_write_reg(mod, PORTA_IOCTL, 0x00ff);
0123     ttl_write_reg(mod, PORTB_IOCTL, 0x00ff);
0124     ttl_write_reg(mod, PORTC_IOCTL, 0x000f);
0125 
0126     /* set all ports as outputs */
0127     ttl_write_reg(mod, PORTA_DIRECTION, 0x0000);
0128     ttl_write_reg(mod, PORTB_DIRECTION, 0x0000);
0129     ttl_write_reg(mod, PORTC_DIRECTION, 0x0000);
0130 
0131     /* set all ports to drive zeroes */
0132     iowrite16be(0x0000, &mod->regs->porta);
0133     iowrite16be(0x0000, &mod->regs->portb);
0134     iowrite16be(0x0000, &mod->regs->portc);
0135 
0136     /* enable all ports */
0137     ttl_write_reg(mod, MASTER_CONF_CTL, CONF_PAE | CONF_PBE | CONF_PCE);
0138 }
0139 
0140 static int ttl_probe(struct platform_device *pdev)
0141 {
0142     struct janz_platform_data *pdata;
0143     struct ttl_module *mod;
0144     struct gpio_chip *gpio;
0145     int ret;
0146 
0147     pdata = dev_get_platdata(&pdev->dev);
0148     if (!pdata) {
0149         dev_err(&pdev->dev, "no platform data\n");
0150         return -ENXIO;
0151     }
0152 
0153     mod = devm_kzalloc(&pdev->dev, sizeof(*mod), GFP_KERNEL);
0154     if (!mod)
0155         return -ENOMEM;
0156 
0157     platform_set_drvdata(pdev, mod);
0158     spin_lock_init(&mod->lock);
0159 
0160     /* get access to the MODULbus registers for this module */
0161     mod->regs = devm_platform_ioremap_resource(pdev, 0);
0162     if (IS_ERR(mod->regs))
0163         return PTR_ERR(mod->regs);
0164 
0165     ttl_setup_device(mod);
0166 
0167     /* Initialize the GPIO data structures */
0168     gpio = &mod->gpio;
0169     gpio->parent = &pdev->dev;
0170     gpio->label = pdev->name;
0171     gpio->get = ttl_get_value;
0172     gpio->set = ttl_set_value;
0173     gpio->owner = THIS_MODULE;
0174 
0175     /* request dynamic allocation */
0176     gpio->base = -1;
0177     gpio->ngpio = 20;
0178 
0179     ret = devm_gpiochip_add_data(&pdev->dev, gpio, NULL);
0180     if (ret) {
0181         dev_err(&pdev->dev, "unable to add GPIO chip\n");
0182         return ret;
0183     }
0184 
0185     return 0;
0186 }
0187 
0188 static struct platform_driver ttl_driver = {
0189     .driver     = {
0190         .name   = DRV_NAME,
0191     },
0192     .probe      = ttl_probe,
0193 };
0194 
0195 module_platform_driver(ttl_driver);
0196 
0197 MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>");
0198 MODULE_DESCRIPTION("Janz MODULbus VMOD-TTL Driver");
0199 MODULE_LICENSE("GPL");
0200 MODULE_ALIAS("platform:janz-ttl");