devices/ccat/gpio.c
branchstable-1.5
changeset 2639 3bedfc5ecd74
parent 2638 5995331a55fe
equal deleted inserted replaced
2632:08aa7305b9ba 2639:3bedfc5ecd74
       
     1 /**
       
     2     Network Driver for Beckhoff CCAT communication controller
       
     3     Copyright (C) 2014  Beckhoff Automation GmbH
       
     4     Author: Patrick Bruenn <p.bruenn@beckhoff.com>
       
     5 
       
     6     This program is free software; you can redistribute it and/or modify
       
     7     it under the terms of the GNU General Public License as published by
       
     8     the Free Software Foundation; either version 2 of the License, or
       
     9     (at your option) any later version.
       
    10 
       
    11     This program is distributed in the hope that it will be useful,
       
    12     but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    14     GNU General Public License for more details.
       
    15 
       
    16     You should have received a copy of the GNU General Public License along
       
    17     with this program; if not, write to the Free Software Foundation, Inc.,
       
    18     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
       
    19 */
       
    20 
       
    21 #include <linux/kernel.h>
       
    22 #include <linux/module.h>
       
    23 #include <linux/gpio.h>
       
    24 #include <linux/version.h>
       
    25 #include "module.h"
       
    26 
       
    27 /**
       
    28  * struct ccat_gpio - CCAT GPIO function
       
    29  * @ioaddr: PCI base address of the CCAT Update function
       
    30  * @info: holds a copy of the CCAT Update function information block (read from PCI config space)
       
    31  */
       
    32 struct ccat_gpio {
       
    33 	struct gpio_chip chip;
       
    34 	void __iomem *ioaddr;
       
    35 	struct mutex lock;
       
    36 };
       
    37 
       
    38 /** TODO implement in LED driver
       
    39 	#define TC_RED 0x01
       
    40 	#define TC_GREEN 0x02
       
    41 	#define TC_BLUE 0x04
       
    42 	#define FB1_RED 0x08
       
    43 	#define FB1_GREEN 0x10
       
    44 	#define FB1_BLUE 0x20
       
    45 	#define FB2_RED 0x40
       
    46 	#define FB2_GREEN 0x80
       
    47 	#define FB2_BLUE 0x100
       
    48  */
       
    49 
       
    50 static int set_bit_in_register(struct mutex *lock, void __iomem * ioaddr,
       
    51 			       unsigned nr, int val)
       
    52 {
       
    53 	volatile unsigned long old;
       
    54 
       
    55 	mutex_lock(lock);
       
    56 	old = ioread32(ioaddr);
       
    57 	val ? set_bit(nr, &old) : clear_bit(nr, &old);
       
    58 	if (val)
       
    59 		set_bit(nr, &old);
       
    60 	else
       
    61 		clear_bit(nr, &old);
       
    62 	iowrite32(old, ioaddr);
       
    63 	mutex_unlock(lock);
       
    64 	return 0;
       
    65 }
       
    66 
       
    67 static int ccat_gpio_get_direction(struct gpio_chip *chip, unsigned nr)
       
    68 {
       
    69 	struct ccat_gpio *gdev = container_of(chip, struct ccat_gpio, chip);
       
    70 	const size_t byte_offset = 4 * (nr / 32) + 0x8;
       
    71 	const u32 mask = 1 << (nr % 32);
       
    72 
       
    73 	return !(mask & ioread32(gdev->ioaddr + byte_offset));
       
    74 }
       
    75 
       
    76 static int ccat_gpio_direction_input(struct gpio_chip *chip, unsigned nr)
       
    77 {
       
    78 	struct ccat_gpio *gdev = container_of(chip, struct ccat_gpio, chip);
       
    79 
       
    80 	return set_bit_in_register(&gdev->lock, gdev->ioaddr + 0x8, nr, 0);
       
    81 }
       
    82 
       
    83 static int ccat_gpio_direction_output(struct gpio_chip *chip, unsigned nr,
       
    84 				      int val)
       
    85 {
       
    86 	struct ccat_gpio *gdev = container_of(chip, struct ccat_gpio, chip);
       
    87 
       
    88 	return set_bit_in_register(&gdev->lock, gdev->ioaddr + 0x8, nr, 1);
       
    89 }
       
    90 
       
    91 static int ccat_gpio_get(struct gpio_chip *chip, unsigned nr)
       
    92 {
       
    93 	struct ccat_gpio *gdev = container_of(chip, struct ccat_gpio, chip);
       
    94 	const size_t byte_off = 4 * (nr / 32);
       
    95 	const int mask = 1 << (nr % 32);
       
    96 	int dir_off;
       
    97 	int value;
       
    98 
       
    99 	/** omit direction changes before value was read */
       
   100 	mutex_lock(&gdev->lock);
       
   101 	dir_off = 0x10 * ccat_gpio_get_direction(chip, nr);
       
   102 	value = !(mask & ioread32(gdev->ioaddr + byte_off + dir_off));
       
   103 	mutex_unlock(&gdev->lock);
       
   104 	return value;
       
   105 }
       
   106 
       
   107 static void ccat_gpio_set(struct gpio_chip *chip, unsigned nr, int val)
       
   108 {
       
   109 	struct ccat_gpio *gdev = container_of(chip, struct ccat_gpio, chip);
       
   110 
       
   111 	set_bit_in_register(&gdev->lock, gdev->ioaddr, nr, val);
       
   112 }
       
   113 
       
   114 static const struct gpio_chip ccat_gpio_chip = {
       
   115 	.label = KBUILD_MODNAME,
       
   116 	.owner = THIS_MODULE,
       
   117 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,12,0))
       
   118 	.get_direction = ccat_gpio_get_direction,
       
   119 #endif
       
   120 	.direction_input = ccat_gpio_direction_input,
       
   121 	.get = ccat_gpio_get,
       
   122 	.direction_output = ccat_gpio_direction_output,
       
   123 	.set = ccat_gpio_set,
       
   124 	.dbg_show = NULL,
       
   125 	.base = -1,
       
   126 	.can_sleep = false
       
   127 };
       
   128 
       
   129 static int ccat_gpio_probe(struct ccat_function *func)
       
   130 {
       
   131 	struct ccat_gpio *const gpio = kzalloc(sizeof(*gpio), GFP_KERNEL);
       
   132 	int ret;
       
   133 
       
   134 	if (!gpio)
       
   135 		return -ENOMEM;
       
   136 
       
   137 	gpio->ioaddr = func->ccat->bar_0 + func->info.addr;
       
   138 	memcpy(&gpio->chip, &ccat_gpio_chip, sizeof(gpio->chip));
       
   139 	gpio->chip.ngpio = func->info.num_gpios;
       
   140 	mutex_init(&gpio->lock);
       
   141 
       
   142 	ret = gpiochip_add(&gpio->chip);
       
   143 	if (ret) {
       
   144 		kfree(gpio);
       
   145 		return ret;
       
   146 	}
       
   147 	pr_info("registered %s as gpiochip%d with #%d GPIOs.\n",
       
   148 		gpio->chip.label, gpio->chip.base, gpio->chip.ngpio);
       
   149 	func->private_data = gpio;
       
   150 	return 0;
       
   151 }
       
   152 
       
   153 static void ccat_gpio_remove(struct ccat_function *func)
       
   154 {
       
   155 	struct ccat_gpio *const gpio = func->private_data;
       
   156 
       
   157 	gpiochip_remove(&gpio->chip);
       
   158 };
       
   159 
       
   160 const struct ccat_driver gpio_driver = {
       
   161 	.type = CCATINFO_GPIO,
       
   162 	.probe = ccat_gpio_probe,
       
   163 	.remove = ccat_gpio_remove,
       
   164 };