/* * gsc3280_gpioparal.c - driver for Gpio Test * 8bits out, 4bits in * * Copyright (C) 2012 Loongson Corporation * * 2013-03-15 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gsc3280_gpioparal.h" /*----------------------------------------------------------------------------*/ enum { OUT_DAT0 = 0, OUT_DAT1, OUT_DAT2, OUT_DAT3, OUT_DAT4, OUT_DAT5, OUT_DAT6, OUT_DAT7, OUT_PIN_NR, }; enum { IN_DAT0 = 0, IN_DAT1, IN_DAT2, IN_DAT3, IN_PIN_NR }; enum { SWITCH_PIN = 0, CTRL_PIN_NR }; struct gpio out_gpios[OUT_PIN_NR] = { {GSC3280_GPB(30), GPIOF_OUT_INIT_HIGH, "OUT_DAT0"}, {GSC3280_GPA(12), GPIOF_OUT_INIT_HIGH, "OUT_DAT1"}, {GSC3280_GPA(10), GPIOF_OUT_INIT_HIGH, "OUT_DAT2"}, {GSC3280_GPA(11), GPIOF_OUT_INIT_HIGH, "OUT_DAT3"}, {GSC3280_GPA(19), GPIOF_OUT_INIT_HIGH, "OUT_DAT4"}, {GSC3280_GPA(20), GPIOF_OUT_INIT_HIGH, "OUT_DAT5"}, {GSC3280_GPA(22), GPIOF_OUT_INIT_HIGH, "OUT_DAT6"}, {GSC3280_GPA(9), GPIOF_OUT_INIT_HIGH, "OUT_DAT7"} }; struct gpio in_gpios[IN_PIN_NR] = { {GSC3280_GPA(19), GPIOF_IN, "IN_DAT0"}, {GSC3280_GPA(20), GPIOF_IN, "IN_DAT1"}, {GSC3280_GPC(2), GPIOF_IN, "IN_DAT2"}, {GSC3280_GPC(0), GPIOF_IN, "IN_DAT3"} }; struct gpio ctl_gpios[CTRL_PIN_NR] = { {GSC3280_GPC(1), GPIOF_OUT_INIT_HIGH, "CTL_DAT0"} }; /*----------------------------------------------------------------------------*/ struct gsc3280_gpioparal { struct cdev cdev; struct class *gpioparal_class; bool out_gpios_init; bool in_gpios_init; dev_t dev; }; struct gsc3280_gpioparal gpioparal_priv; /*----------------------------------------------------------------------------*/ /* */ static ssize_t gpioparal_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { return 0; } /*----------------------------------------------------------------------------*/ /* */ static ssize_t gpioparal_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { return 0; } void gpio_paral_out_8bits(unsigned char val) { int i; for (i = 0; i < OUT_PIN_NR; i++) { gpio_set_value(out_gpios[i].gpio, (val >> i) & 0x01); } return; } unsigned char gpio_paral_in_8bits(void) { int i; unsigned char val = 0; gpio_set_value(ctl_gpios[SWITCH_PIN].gpio, 1); udelay(1000); for (i = 0; i < IN_PIN_NR; i++) { val |= ((gpio_get_value(in_gpios[IN_PIN_NR - i - 1].gpio) & 0x01) << i); } gpio_set_value(ctl_gpios[SWITCH_PIN].gpio, 0); udelay(1000); for (i = 0; i < IN_PIN_NR; i++) { val |= ((gpio_get_value(in_gpios[IN_PIN_NR - i - 1].gpio) & 0x01) << (i + IN_PIN_NR)); } return val; } /*----------------------------------------------------------------------------*/ /* */ static long gpioparal_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int ret = 0; unsigned char val = 0; if (_IOC_TYPE(cmd) != GPIOPARAL_IOC_MAGIC) return -ENOTTY; if (_IOC_NR(cmd) > GPIOPARAL_IOC_MAXNR) return -ENOTTY; switch(cmd) { case GPIO_INIT_WRITE: if (gpioparal_priv.out_gpios_init || gpioparal_priv.in_gpios_init) break; ret = gpio_request_array(out_gpios, OUT_PIN_NR); if (ret < 0) return ret; gpioparal_priv.out_gpios_init = true; break; case GPIO_INIT_READ: if (gpioparal_priv.out_gpios_init || gpioparal_priv.in_gpios_init) break; ret = gpio_request_array(in_gpios, IN_PIN_NR); ret |= gpio_request_array(ctl_gpios, CTRL_PIN_NR); if (ret < 0) return ret; gpioparal_priv.in_gpios_init = true; break; case GPIO_RELEASE_WRITE: if (gpioparal_priv.out_gpios_init) gpio_free_array(out_gpios, OUT_PIN_NR); gpioparal_priv.out_gpios_init = false; break; case GPIO_RELEASE_READ: if (gpioparal_priv.in_gpios_init) { gpio_free_array(in_gpios, IN_PIN_NR); gpio_free_array(ctl_gpios, CTRL_PIN_NR); } gpioparal_priv.in_gpios_init = false; break; case GPIO_PARAL_OUT: if (arg) { if (!gpioparal_priv.out_gpios_init) return EPERM; __get_user(val, (unsigned char*)arg); gpio_paral_out_8bits(val); } break; case GPIO_PARAL_IN: if (arg) { if (!gpioparal_priv.in_gpios_init) return EPERM; val = gpio_paral_in_8bits(); __put_user(val, (unsigned char*)arg); } break; default: return -ENOTTY; } return 0; } /*----------------------------------------------------------------------------*/ static int gpioparal_open(struct inode *inode, struct file *filp) { return 0; } /*----------------------------------------------------------------------------*/ static int gpioparal_release(struct inode *inode, struct file *filp) { if (gpioparal_priv.out_gpios_init) gpio_free_array(out_gpios, OUT_PIN_NR); if (gpioparal_priv.in_gpios_init) { gpio_free_array(in_gpios, IN_PIN_NR); gpio_free_array(ctl_gpios, CTRL_PIN_NR); } gpioparal_priv.out_gpios_init = false; gpioparal_priv.in_gpios_init = false; return 0; } /*----------------------------------------------------------------------------*/ struct file_operations gpioparal_fops = { .owner = THIS_MODULE, .read = gpioparal_read, .write = gpioparal_write, .unlocked_ioctl = gpioparal_ioctl, .open = gpioparal_open, .release = gpioparal_release, }; /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ static int __init gsc3280_gpioparal_init(void) { int err; int result; int major; result = alloc_chrdev_region(&gpioparal_priv.dev, 0, 0, "gpioparal"); major = MAJOR(gpioparal_priv.dev); if (result < 0) { printk(KERN_WARNING "gpioparal: can't get major %d\n", major); return result; } cdev_init(&gpioparal_priv.cdev, &gpioparal_fops); gpioparal_priv.cdev.owner = THIS_MODULE; gpioparal_priv.cdev.ops = &gpioparal_fops; err = cdev_add(&gpioparal_priv.cdev, gpioparal_priv.dev, 1); if (err) { printk(KERN_NOTICE "Error[%d] cdev_add gpioparal\n", err); return -1; } gpioparal_priv.gpioparal_class = class_create(THIS_MODULE, "gsc3280_gpioparal"); if (IS_ERR(gpioparal_priv.gpioparal_class)) { printk(KERN_ERR "Failed in create gpioparal class\n"); return -1; } device_create(gpioparal_priv.gpioparal_class, NULL, gpioparal_priv.dev, NULL, "gpioparal"); gpioparal_priv.out_gpios_init = false; gpioparal_priv.in_gpios_init = false; sysctl_iomux_disable(SYSCTL_IOMUX_SPI1); return 0; } /*----------------------------------------------------------------------------*/ static void __exit gsc3280_gpioparal_exit(void) { cdev_del(&gpioparal_priv.cdev); unregister_chrdev_region(gpioparal_priv.dev, 1); device_destroy(gpioparal_priv.gpioparal_class, gpioparal_priv.dev); class_destroy(gpioparal_priv.gpioparal_class); } /*----------------------------------------------------------------------------*/ module_init(gsc3280_gpioparal_init); module_exit(gsc3280_gpioparal_exit); /*----------------------------------------------------------------------------*/ MODULE_AUTHOR("ansonn.wang@gmail.com"); MODULE_DESCRIPTION("gsc3280 gpio parallel test<8bits <-> 4bits> driver"); MODULE_LICENSE("GPL"); /*----------------------------------------------------------------------------*/