/* * Copyright (C) 2009 SPiDCOM Technologies * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #define SPC300_GPIO_PID_MAX_NB 8 static int spc300_gpio_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); static unsigned int spc300_gpio_poll (struct file *filp, poll_table *wait); static int spc300_gpio_flush (struct inode *inode, struct file *filp); /** Private data structure */ struct spc300_gpio { int irq; struct platform_device *pdev; uint32_t allowed; /* 1 for each allowed gpio */ uint32_t already_in_use; /* 1 for each allowed gpio already in used * by kernel but that can be used */ uint32_t is_init; /* 1 when gpio direction is set */ /** Private data for interrupt handler and poll function */ struct { wait_queue_head_t queue; spinlock_t lock; /* Contains registered PID-s waiting for a GPIO interrupt, * and their associated GPIO raw interrupt status * when interrupt is handled */ pid_t pid[SPC300_GPIO_PID_MAX_NB][2]; } interrupt; }; /** Misc device structures */ static const struct file_operations spc300_gpio_fops = { .owner = THIS_MODULE, .ioctl = spc300_gpio_ioctl, .poll = spc300_gpio_poll, .flush = spc300_gpio_flush, }; static struct miscdevice spc300_gpio_miscdev = { .minor = GPIO_MINOR, .name = "gpio user mode", .fops = &spc300_gpio_fops, }; /** * Set gpio direction from ioctl. * * This function will set a gpio direction through libgpio. * But this direction will be set only if gpio number is : * Allowed, if not set direction is stop * Not Already_in_use, in this case direction can't be changed * Choosen direction can't be accepted. * Once direction is set Is_init flag is also set for get/set procedure * * WARNING: currently nb gpios cannot exceed 32. * * \param gpio spc300_gpio structure. * \param gd gpio_direction structure. * \return error code. */ static int ioctl_set_direction (struct spc300_gpio *gpio, struct gpio_direction *gd) { struct device *dev = &(gpio->pdev)->dev; /* Check if gpio already in used by kernel */ if ((gpio->already_in_use >> gd->num) & 1) { dev_err (dev, "GPIO %d direction already set by Kernel, you cannot change it\n", gd->num); return 0; } /* Check if gpio is allowed */ if ((gpio->allowed >> gd->num) & 1) { /* Set direction */ if (SPC300_GPIO_DIRECTION_OUTPUT == gd->dir) { /* Wanted direction = OUTPUT */ if (gpio_direction_output (gd->num, gd->val)) { /* GPIO cannot be in OUTPUT */ dev_err (dev, "GPIO %d cannot accept OUTPUT direction\n", gd->num); } } else if (SPC300_GPIO_DIRECTION_INPUT == gd->dir) { /* Wanted direction = INPUT */ if (gpio_direction_input (gd->num)) { /* GPIO cannot be in INPUT */ dev_err (dev, "GPIO %d cannot accept INPUT direction\n", gd->num); } } else if (SPC300_GPIO_DIRECTION_BIDIR == gd->dir) { /* GPIO cannot be in BIDIR */ dev_err (dev, "GPIO %d cannot accept BIDIR direction\n", gd->num); } else /* NONE */ { return 0; } /* Set gpio number as initialize */ gpio->is_init |= (1 << gd->num); return 0; } else { /* GPIO not allowed */ dev_err (dev, "You cannot access to GPIO %d\n", gd->num); return -EFAULT; } } /** * Set gpio value from ioctl. * * \param gpio spc300_gpio structure. * \param gv gpio_value structure. * \return error code. */ static int ioctl_set_value (struct spc300_gpio *gpio, struct gpio_value *gv) { struct device *dev = &(gpio->pdev)->dev; /* Check if gpio number is initialized */ if ((gpio->is_init >> gv->num) & 1) { /* Set gpio number value */ gpio_set_value (gv->num, gv->val); return 0; } else { /* Gpio direction is not set */ dev_dbg (dev, "Set GPIO %d direction before\n", gv->num); return -EFAULT; } } /** * Get gpio value from ioctl. * * \param gpio spc300_gpio structure. * \param gv gpio_value structure. * \return error code. */ static int ioctl_get_value (struct spc300_gpio *gpio, struct gpio_value *gv) { struct device *dev = &(gpio->pdev)->dev; /* Check if gpio number is initialized */ if ((gpio->is_init >> gv->num) & 1) { /* Find gpio number value */ gv->val = gpio_get_value (gv->num); return 0; } else { /* Gpio direction is not set */ dev_err (dev, "Set GPIO %d direction before\n", gv->num); return -EFAULT; } } /** * Request allowed GPIO and fill spc300_gpio fields. * * This function will request a gpios through libgpio and set the differents * spc300_gpio fields depending on request result and SPC300_GPIO_USABLE value. * Allowed : will be set if request and GPIO_USABLE are ok. * Already_in_use : will be set if request returns busy that means that a * kernel part has already this gpio number in use. * Is_init : will be set when direction is configured or when Already_in_use * flag is set. * * WARNING: currently nb gpios cannot exceed 32. * * \param gpio spc300_gpio structure. */ static void request_allowed_gpios (struct spc300_gpio *gpio) { int i, status; struct device *dev = &(gpio->pdev)->dev; gpio->allowed = 0; gpio->already_in_use = 0; gpio->is_init = 0; for (i=0 ; i> i) & 1) { status = gpio_request (i, "IN USE"); if (status == 0) gpio->allowed |= (1<already_in_use |= (1<is_init |= (1<allowed >> i) & 1) gpio_free (i); } } /** * Get number of PID-s registered in the GPIO interrupt PID table. * * \param gpio device structure * \return count if not empty, 0 if empty, -1 if error */ int spc300_gpio_pid_count (struct spc300_gpio *gpio) { int count = 0, i = 0; unsigned long flags; if (NULL == gpio) return -1; spin_lock_irqsave (&gpio->interrupt.lock, flags); for (i = 0; i < SPC300_GPIO_PID_MAX_NB; i++) { if (-1 != gpio->interrupt.pid[i][0]) count++; } spin_unlock_irqrestore (&gpio->interrupt.lock, flags); return count; } /** * Indicate if the current PID is registered in the GPIO interrupt PID table. * * \param gpio device structure * \return 1 if registered, 0 if not registered, -1 if error */ int spc300_gpio_pid_registered (struct spc300_gpio *gpio) { int registered = 0, i = 0; unsigned long flags; if (NULL == gpio) return -1; spin_lock_irqsave (&gpio->interrupt.lock, flags); for (i = 0; i < SPC300_GPIO_PID_MAX_NB; i++) { if (current->pid == gpio->interrupt.pid[i][0]) { registered = 1; break; } } spin_unlock_irqrestore (&gpio->interrupt.lock, flags); return registered; } /** * Register a PID to the GPIO interrupt PID table. * * \param gpio device structure * \return index if ok, -1 if error */ int spc300_gpio_pid_add (struct spc300_gpio *gpio) { int index = 0; unsigned long flags; if (NULL == gpio) return -1; spin_lock_irqsave (&gpio->interrupt.lock, flags); for (index = 0; index < SPC300_GPIO_PID_MAX_NB; index++) { if (-1 == gpio->interrupt.pid[index][0]) { /* Register PID */ gpio->interrupt.pid[index][0] = current->pid; break; } } spin_unlock_irqrestore (&gpio->interrupt.lock, flags); if (SPC300_GPIO_PID_MAX_NB <= index) /* Not enough space */ index = -1; return index; } /** * Unregister the current PID from the GPIO interrupt PID table. * * \param gpio device structure * \return 0 if ok, -1 if error */ int spc300_gpio_pid_remove (struct spc300_gpio *gpio) { int i = 0; unsigned long flags; if (NULL == gpio) return -1; spin_lock_irqsave (&gpio->interrupt.lock, flags); for (i = 0; i < SPC300_GPIO_PID_MAX_NB; i++) { if (current->pid == gpio->interrupt.pid[i][0]) { /* Unregister PID */ gpio->interrupt.pid[i][0] = -1; gpio->interrupt.pid[i][1] = 0; } } spin_unlock_irqrestore (&gpio->interrupt.lock, flags); return 0; } int spc300_gpio_pid_set_raw_status (struct spc300_gpio *gpio, int raw_status) { int i = 0; unsigned long flags; if (NULL == gpio) return -1; spin_lock_irqsave (&gpio->interrupt.lock, flags); for (i = 0; i < SPC300_GPIO_PID_MAX_NB; i++) { if (-1 != gpio->interrupt.pid[i][0]) { gpio->interrupt.pid[i][1] |= raw_status; } } spin_unlock_irqrestore (&gpio->interrupt.lock, flags); return 0; } int spc300_gpio_pid_get_raw_status (struct spc300_gpio *gpio) { int i = 0, raw_status = 0; unsigned long flags; if (NULL == gpio) return -1; spin_lock_irqsave (&gpio->interrupt.lock, flags); for (i = 0; i < SPC300_GPIO_PID_MAX_NB; i++) { if (current->pid == gpio->interrupt.pid[i][0]) { raw_status = gpio->interrupt.pid[i][1]; break; } } spin_unlock_irqrestore (&gpio->interrupt.lock, flags); return raw_status; } int spc300_gpio_pid_reset_raw_status (struct spc300_gpio *gpio) { int i = 0; unsigned long flags; if (NULL == gpio) return -1; spin_lock_irqsave (&gpio->interrupt.lock, flags); for (i = 0; i < SPC300_GPIO_PID_MAX_NB; i++) { if (current->pid == gpio->interrupt.pid[i][0]) { gpio->interrupt.pid[i][1] = 0; } } spin_unlock_irqrestore (&gpio->interrupt.lock, flags); return 0; } /** * IOCTL commands for GPIO User Mode device. * * \param inode inode structure. * \param file user exchange structure. * \param cmd command to execute. * \param arg arguments. * \return error code. */ static int spc300_gpio_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *)arg; struct spc300_gpio *gpio; union gpio_info info; /* Find gpio private structure pointer */ if (spc300_gpio_miscdev.parent) { gpio = dev_get_drvdata (spc300_gpio_miscdev.parent); if (gpio == NULL) return -EINVAL; } else { return -EFAULT; } switch (cmd) { case GPIOIOC_GETVALUE: /* Get gpio number given by user */ if (copy_from_user (&info, argp, sizeof (info))) return -EFAULT; /* Get gpio number value */ if (ioctl_get_value (gpio, &info.gpioval)) return -EFAULT; /* Give the response to user */ return copy_to_user (argp, &info, sizeof (info)) ? -EFAULT : 0; case GPIOIOC_SETVALUE: /* Get gpio number and it value given by user */ if (copy_from_user(&info, argp, sizeof (info))) return -EFAULT; /* Set gpio number value */ if (ioctl_set_value (gpio, &info.gpioval)) return -EFAULT; return 0; case GPIOIOC_SETDIRECTION: /* Get gpio number and it direction given by user */ if (copy_from_user (&info, argp, sizeof (info))) return -EFAULT; /* Set gpio number direction */ if (ioctl_set_direction (gpio, &info.gpiodir)) return -EFAULT; return 0; case GPIOIOC_SETIT: if (NULL == file) return -EFAULT; /* Get gpio mask given by user */ if (copy_from_user (&info, argp, sizeof (info))) return -EFAULT; if (info.gpioit.enable) { if (!spc300_gpio_pid_registered (gpio)) /* Register current PID to PID-s table */ if (0 > spc300_gpio_pid_add (gpio)) return -EFAULT; /* Set gpio user mask */ file->private_data = (void *) info.gpioit.mask; } else { if (spc300_gpio_pid_registered (gpio)) /* Unregister current PID from PID-s table */ if (0 > spc300_gpio_pid_remove (gpio)) return -EFAULT; /* Reset gpio user mask */ file->private_data = 0; } return 0; default: return -EFAULT; } } /** * Interrupt Handler GPIO procedure. * * \param irq interrupt number * \param dev_id device structure * \return error code */ irqreturn_t spc300_gpio_interrupt_handler (int irq, void *dev_id) { struct spc300_gpio *dev = (struct spc300_gpio *) dev_id; unsigned int raw_status = 0; if (NULL == dev) return IRQ_NONE; if (dev->irq != irq) return IRQ_NONE; printk (KERN_DEBUG "Handle SPC300 GPIO interrupt\n"); /* Get GPIO raw interrupt status */ raw_status = spc300_gpio_get_interrupt_raw_status (); /* Reset raised interrupt(s) */ spc300_gpio_clear_interrupts (raw_status); /* Check if any PID is waiting for a GPIO interrupt */ if (0 != spc300_gpio_pid_count (dev)) { /* Save GPIO raw interrupt status */ if (0 > spc300_gpio_pid_set_raw_status (dev, raw_status)) return IRQ_NONE; /* Wake up waiting queue */ wake_up (&dev->interrupt.queue); } return IRQ_HANDLED; } /** * Poll GPIO interrupts. * * \param filp file structure * \param wait poll table structure * \return error code * * This function is called * when a user process calls poll() or select() functions on "/dev/gpio". * To be able to warn all waiting processes, a (un)registration system is needed. * That's why GPIOIOC_SETIT has to be called by user process before polling. * To determinate calling PID, "struct task_struct current pid_t pid" field is used. */ static unsigned int spc300_gpio_poll (struct file *filp, poll_table *wait) { struct spc300_gpio *gpio = NULL; unsigned int it_mask = 0, raw_status = 0; if (NULL == filp) return POLLERR; /* Find gpio private structure pointer */ if (spc300_gpio_miscdev.parent) { gpio = dev_get_drvdata (spc300_gpio_miscdev.parent); if (NULL == gpio) return POLLERR; } poll_wait (filp, &gpio->interrupt.queue, wait); /* Get GPIO raw interrupt status and GPIO user interrupt mask */ raw_status = spc300_gpio_pid_get_raw_status (gpio); it_mask = (unsigned int) filp->private_data; if (spc300_gpio_pid_registered (gpio)) /* current PID registration status */ { if (raw_status) { /* Reset GPIO raw interrupt status of the caller */ if (0 > spc300_gpio_pid_reset_raw_status (gpio)) return POLLERR; /* If already registered, and an interrupt occured, * check GPIO raw interrupt status and GPIO user interrupt mask */ if (raw_status & it_mask) { /* Inform caller */ return POLLPRI; } } } else { /* Not registered */ printk (KERN_WARNING "You have to configure interruption via GPIOIOC_SETIT before polling\n"); } /* - PID not registered, or * - no interrupt => continue waiting for interrupt or timeout, or * - interrupt masked by user => continue waiting for interrupt or timeout, or * - timeout */ return 0; } /** * Flush function is called * each time a user process calls close() function on "/dev/gpio". * * \param inode inode structure * \param file user exchange structure * \return error code */ static int spc300_gpio_flush (struct inode *inode, struct file *file) { struct spc300_gpio *gpio; printk (KERN_DEBUG "Flush SPC300 GPIO driver\n"); /* Find gpio private structure pointer */ if (spc300_gpio_miscdev.parent) { gpio = dev_get_drvdata (spc300_gpio_miscdev.parent); if (NULL == gpio) return -EINVAL; } else return -EFAULT; if (spc300_gpio_pid_registered (gpio)) /* Unregister current PID from PID-s table */ if (0 > spc300_gpio_pid_remove (gpio)) return -EFAULT; /* Reset gpio user mask */ file->private_data = 0; return 0; } /** * Initialise GPIO driver. * * \param pdev platform device structure. * \return error code. */ static int __init spc300_gpio_probe (struct platform_device *pdev) { struct spc300_gpio *gpio; int res, num = 0; /* Check arguments */ if (!pdev) return -EFAULT; /* Allocate private data */ gpio = kzalloc (sizeof *gpio, GFP_KERNEL); if (!gpio) return -ENOMEM; /* Link pdev with private data */ gpio->pdev = pdev; dev_set_drvdata (&pdev->dev, gpio); /* Get IRQ number */ gpio->irq = platform_get_irq (pdev, 0); if (gpio->irq < 0) { res = gpio->irq; goto fail; } /* Check if someone has already register a spc300_gpio device */ if (spc300_gpio_miscdev.parent) { res = -EBUSY; goto fail; } spc300_gpio_miscdev.parent = &pdev->dev; /* Register a Misc device for ioctl... management */ if ((res = misc_register (&spc300_gpio_miscdev)) != 0) goto fail; /* Request allowed gpios */ request_allowed_gpios (gpio); /* Initialize structure for poll/select management */ init_waitqueue_head (&gpio->interrupt.queue); spin_lock_init (&gpio->interrupt.lock); for (num = 0; num < SPC300_GPIO_PID_MAX_NB; num++) { gpio->interrupt.pid[num][0] = -1; gpio->interrupt.pid[num][1] = 0; } /* Request GPIO IRQ */ if (0 != request_irq (gpio->irq, &spc300_gpio_interrupt_handler, 0, spc300_gpio_miscdev.name, gpio)) { printk (KERN_ERR "%s - interrupt %d request fail\n", spc300_gpio_miscdev.name, gpio->irq); res = -ENODEV; goto fail; } /* Setup GPIO interrupts */ for (num = 0; num < spc300_gpio_max_nb (spidcom_nvram.pkg_cfg); num++) { if (SPC300_GPIO_DIRECTION_INPUT == \ spc300_gpio_direction (spidcom_nvram.gpio_allow_dir, num)) spc300_gpio_set_interrupt (num, 1, 1); } dev_info (&pdev->dev, "SPC300 GPIO Driver enabled\n"); return 0; fail: dev_dbg (&pdev->dev, "probe error %d for SPC300 GPIO Driver\n",res); kfree (gpio); return res; } /** * Uninitialise GPIO driver. * * \param pdev platform device structure. * \return error code. */ static int __exit spc300_gpio_remove (struct platform_device *pdev) { struct spc300_gpio *gpio = dev_get_drvdata (&pdev->dev); int res; /* Check argument */ if (gpio == NULL) return -EINVAL; /* Freeing IRQ */ //free_irq (gpio->irq, pdev); /* Free requested gpios */ free_allowed_gpios (gpio); /* Freeing private data */ kfree (gpio); /* Unregister Misc device */ res = misc_deregister (&spc300_gpio_miscdev); if (!res) spc300_gpio_miscdev.parent = NULL; return res; } /** Module structure */ static struct platform_driver spc300_gpio_driver = { .driver = { .name = "spc300gpio", .owner = THIS_MODULE, }, .suspend = NULL, .resume = NULL, .remove = __exit_p (spc300_gpio_remove), }; /** * Module initialization. * * \return error code. */ static int __init spc300_gpio_init (void) { return platform_driver_probe (&spc300_gpio_driver, spc300_gpio_probe); } /** * Module uninitialization. * * \return error code. */ static void __exit spc300_gpio_exit (void) { platform_driver_unregister (&spc300_gpio_driver); } module_init (spc300_gpio_init); module_exit (spc300_gpio_exit); MODULE_DESCRIPTION ("SPiDCOM SPC300 GPIO driver"); MODULE_AUTHOR ("SPiDCOM Technologies"); MODULE_LICENSE ("GPL"); MODULE_ALIAS_MISCDEV (GPIO_MINOR);