cregit-Linux how code gets into the kernel

Release 4.14 drivers/gpio/gpio-xilinx.c

Directory: drivers/gpio
/*
 * Xilinx gpio driver for xps/axi_gpio IP.
 *
 * Copyright 2008 - 2013 Xilinx, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation.
 *
 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <linux/bitops.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/slab.h>

/* Register Offset Definitions */

#define XGPIO_DATA_OFFSET   (0x0)	
/* Data register  */

#define XGPIO_TRI_OFFSET    (0x4)	
/* I/O direction register  */


#define XGPIO_CHANNEL_OFFSET	0x8

/* Read/Write access to the GPIO registers */
#if defined(CONFIG_ARCH_ZYNQ) || defined(CONFIG_X86)

# define xgpio_readreg(offset)		readl(offset)

# define xgpio_writereg(offset, val)	writel(val, offset)
#else

# define xgpio_readreg(offset)		__raw_readl(offset)

# define xgpio_writereg(offset, val)	__raw_writel(val, offset)
#endif

/**
 * struct xgpio_instance - Stores information about GPIO device
 * @mmchip: OF GPIO chip for memory mapped banks
 * @gpio_width: GPIO width for every channel
 * @gpio_state: GPIO state shadow register
 * @gpio_dir: GPIO direction shadow register
 * @gpio_lock: Lock used for synchronization
 */

struct xgpio_instance {
	
struct of_mm_gpio_chip mmchip;
	
unsigned int gpio_width[2];
	
u32 gpio_state[2];
	
u32 gpio_dir[2];
	
spinlock_t gpio_lock[2];
};


static inline int xgpio_index(struct xgpio_instance *chip, int gpio) { if (gpio >= chip->gpio_width[0]) return 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Ricardo Ribalda Delgado32100.00%1100.00%
Total32100.00%1100.00%


static inline int xgpio_regoffset(struct xgpio_instance *chip, int gpio) { if (xgpio_index(chip, gpio)) return XGPIO_CHANNEL_OFFSET; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Ricardo Ribalda Delgado30100.00%2100.00%
Total30100.00%2100.00%


static inline int xgpio_offset(struct xgpio_instance *chip, int gpio) { if (xgpio_index(chip, gpio)) return gpio - chip->gpio_width[0]; return gpio; }

Contributors

PersonTokensPropCommitsCommitProp
Ricardo Ribalda Delgado3697.30%266.67%
John Linn12.70%133.33%
Total37100.00%3100.00%

/** * xgpio_get - Read the specified signal of the GPIO device. * @gc: Pointer to gpio_chip device structure. * @gpio: GPIO signal number. * * This function reads the specified signal of the GPIO device. * * Return: * 0 if direction of GPIO signals is set as input otherwise it * returns negative error value. */
static int xgpio_get(struct gpio_chip *gc, unsigned int gpio) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct xgpio_instance *chip = gpiochip_get_data(gc); u32 val; val = xgpio_readreg(mm_gc->regs + XGPIO_DATA_OFFSET + xgpio_regoffset(chip, gpio)); return !!(val & BIT(xgpio_offset(chip, gpio))); }

Contributors

PersonTokensPropCommitsCommitProp
Ricardo Ribalda Delgado3345.21%240.00%
John Linn3243.84%120.00%
Michal Simek68.22%120.00%
Linus Walleij22.74%120.00%
Total73100.00%5100.00%

/** * xgpio_set - Write the specified signal of the GPIO device. * @gc: Pointer to gpio_chip device structure. * @gpio: GPIO signal number. * @val: Value to be written to specified signal. * * This function writes the specified value in to the specified signal of the * GPIO device. */
static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) { unsigned long flags; struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct xgpio_instance *chip = gpiochip_get_data(gc); int index = xgpio_index(chip, gpio); int offset = xgpio_offset(chip, gpio); spin_lock_irqsave(&chip->gpio_lock[index], flags); /* Write to GPIO signal and set its direction to output */ if (val) chip->gpio_state[index] |= BIT(offset); else chip->gpio_state[index] &= ~BIT(offset); xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + xgpio_regoffset(chip, gpio), chip->gpio_state[index]); spin_unlock_irqrestore(&chip->gpio_lock[index], flags); }

Contributors

PersonTokensPropCommitsCommitProp
John Linn8559.86%116.67%
Ricardo Ribalda Delgado4632.39%233.33%
Michal Simek96.34%233.33%
Linus Walleij21.41%116.67%
Total142100.00%6100.00%

/** * xgpio_set_multiple - Write the specified signals of the GPIO device. * @gc: Pointer to gpio_chip device structure. * @mask: Mask of the GPIOS to modify. * @bits: Value to be wrote on each GPIO * * This function writes the specified values into the specified signals of the * GPIO devices. */
static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, unsigned long *bits) { unsigned long flags; struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct xgpio_instance *chip = gpiochip_get_data(gc); int index = xgpio_index(chip, 0); int offset, i; spin_lock_irqsave(&chip->gpio_lock[index], flags); /* Write to GPIO signals */ for (i = 0; i < gc->ngpio; i++) { if (*mask == 0) break; if (index != xgpio_index(chip, i)) { xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + xgpio_regoffset(chip, i), chip->gpio_state[index]); spin_unlock_irqrestore(&chip->gpio_lock[index], flags); index = xgpio_index(chip, i); spin_lock_irqsave(&chip->gpio_lock[index], flags); } if (__test_and_clear_bit(i, mask)) { offset = xgpio_offset(chip, i); if (test_bit(i, bits)) chip->gpio_state[index] |= BIT(offset); else chip->gpio_state[index] &= ~BIT(offset); } } xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + xgpio_regoffset(chip, i), chip->gpio_state[index]); spin_unlock_irqrestore(&chip->gpio_lock[index], flags); }

Contributors

PersonTokensPropCommitsCommitProp
Iban Rodriguez261100.00%1100.00%
Total261100.00%1100.00%

/** * xgpio_dir_in - Set the direction of the specified GPIO signal as input. * @gc: Pointer to gpio_chip device structure. * @gpio: GPIO signal number. * * Return: * 0 - if direction of GPIO signals is set as input * otherwise it returns negative error value. */
static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) { unsigned long flags; struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct xgpio_instance *chip = gpiochip_get_data(gc); int index = xgpio_index(chip, gpio); int offset = xgpio_offset(chip, gpio); spin_lock_irqsave(&chip->gpio_lock[index], flags); /* Set the GPIO bit in shadow register and set direction as input */ chip->gpio_dir[index] |= BIT(offset); xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET + xgpio_regoffset(chip, gpio), chip->gpio_dir[index]); spin_unlock_irqrestore(&chip->gpio_lock[index], flags); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
John Linn7459.68%116.67%
Ricardo Ribalda Delgado4233.87%233.33%
Michal Simek64.84%233.33%
Linus Walleij21.61%116.67%
Total124100.00%6100.00%

/** * xgpio_dir_out - Set the direction of the specified GPIO signal as output. * @gc: Pointer to gpio_chip device structure. * @gpio: GPIO signal number. * @val: Value to be written to specified signal. * * This function sets the direction of specified GPIO signal as output. * * Return: * If all GPIO signals of GPIO chip is configured as input then it returns * error otherwise it returns 0. */
static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) { unsigned long flags; struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); struct xgpio_instance *chip = gpiochip_get_data(gc); int index = xgpio_index(chip, gpio); int offset = xgpio_offset(chip, gpio); spin_lock_irqsave(&chip->gpio_lock[index], flags); /* Write state of GPIO signal */ if (val) chip->gpio_state[index] |= BIT(offset); else chip->gpio_state[index] &= ~BIT(offset); xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + xgpio_regoffset(chip, gpio), chip->gpio_state[index]); /* Clear the GPIO bit in shadow register and set direction as output */ chip->gpio_dir[index] &= ~BIT(offset); xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET + xgpio_regoffset(chip, gpio), chip->gpio_dir[index]); spin_unlock_irqrestore(&chip->gpio_lock[index], flags); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
John Linn10256.04%116.67%
Ricardo Ribalda Delgado6334.62%233.33%
Michal Simek158.24%233.33%
Linus Walleij21.10%116.67%
Total182100.00%6100.00%

/** * xgpio_save_regs - Set initial values of GPIO pins * @mm_gc: Pointer to memory mapped GPIO chip structure */
static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc) { struct xgpio_instance *chip = container_of(mm_gc, struct xgpio_instance, mmchip); xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state[0]); xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir[0]); if (!chip->gpio_width[1]) return; xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + XGPIO_CHANNEL_OFFSET, chip->gpio_state[1]); xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET + XGPIO_CHANNEL_OFFSET, chip->gpio_dir[1]); }

Contributors

PersonTokensPropCommitsCommitProp
Ricardo Ribalda Delgado5148.57%120.00%
John Linn4441.90%120.00%
Guenter Roeck65.71%120.00%
Raphaël Teysseyre21.90%120.00%
Michal Simek21.90%120.00%
Total105100.00%5100.00%

/** * xgpio_remove - Remove method for the GPIO device. * @pdev: pointer to the platform device * * This function remove gpiochips and frees all the allocated resources. * * Return: 0 always */
static int xgpio_remove(struct platform_device *pdev) { struct xgpio_instance *chip = platform_get_drvdata(pdev); of_mm_gpiochip_remove(&chip->mmchip); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Ricardo Ribalda Delgado2475.00%375.00%
John Linn825.00%125.00%
Total32100.00%4100.00%

/** * xgpio_of_probe - Probe method for the GPIO device. * @pdev: pointer to the platform device * * Return: * It returns 0, if the driver is bound to the GPIO device, or * a negative value if there is an error. */
static int xgpio_probe(struct platform_device *pdev) { struct xgpio_instance *chip; int status = 0; struct device_node *np = pdev->dev.of_node; u32 is_dual; chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; platform_set_drvdata(pdev, chip); /* Update GPIO state shadow register with default value */ of_property_read_u32(np, "xlnx,dout-default", &chip->gpio_state[0]); /* Update GPIO direction shadow register with default value */ if (of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir[0])) chip->gpio_dir[0] = 0xFFFFFFFF; /* * Check device node and parent device node for device width * and assume default width of 32 */ if (of_property_read_u32(np, "xlnx,gpio-width", &chip->gpio_width[0])) chip->gpio_width[0] = 32; spin_lock_init(&chip->gpio_lock[0]); if (of_property_read_u32(np, "xlnx,is-dual", &is_dual)) is_dual = 0; if (is_dual) { /* Update GPIO state shadow register with default value */ of_property_read_u32(np, "xlnx,dout-default-2", &chip->gpio_state[1]); /* Update GPIO direction shadow register with default value */ if (of_property_read_u32(np, "xlnx,tri-default-2", &chip->gpio_dir[1])) chip->gpio_dir[1] = 0xFFFFFFFF; /* * Check device node and parent device node for device width * and assume default width of 32 */ if (of_property_read_u32(np, "xlnx,gpio2-width", &chip->gpio_width[1])) chip->gpio_width[1] = 32; spin_lock_init(&chip->gpio_lock[1]); } chip->mmchip.gc.ngpio = chip->gpio_width[0] + chip->gpio_width[1]; chip->mmchip.gc.parent = &pdev->dev; chip->mmchip.gc.direction_input = xgpio_dir_in; chip->mmchip.gc.direction_output = xgpio_dir_out; chip->mmchip.gc.get = xgpio_get; chip->mmchip.gc.set = xgpio_set; chip->mmchip.gc.set_multiple = xgpio_set_multiple; chip->mmchip.save_regs = xgpio_save_regs; /* Call the OF gpio helper to setup and register the GPIO device */ status = of_mm_gpiochip_add_data(np, &chip->mmchip, chip); if (status) { pr_err("%pOF: error in probe function with status %d\n", np, status); return status; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Ricardo Ribalda Delgado14337.43%216.67%
Michal Simek13936.39%325.00%
John Linn6817.80%18.33%
Gernot Vormayr164.19%18.33%
Iban Rodriguez102.62%18.33%
Linus Walleij41.05%216.67%
Rob Herring10.26%18.33%
Anton Vorontsov10.26%18.33%
Total382100.00%12100.00%

static const struct of_device_id xgpio_of_match[] = { { .compatible = "xlnx,xps-gpio-1.00.a", }, { /* end of list */ }, }; MODULE_DEVICE_TABLE(of, xgpio_of_match); static struct platform_driver xgpio_plat_driver = { .probe = xgpio_probe, .remove = xgpio_remove, .driver = { .name = "gpio-xilinx", .of_match_table = xgpio_of_match, }, };
static int __init xgpio_init(void) { return platform_driver_register(&xgpio_plat_driver); }

Contributors

PersonTokensPropCommitsCommitProp
John Linn1275.00%150.00%
Ricardo Ribalda Delgado425.00%150.00%
Total16100.00%2100.00%

subsys_initcall(xgpio_init);
static void __exit xgpio_exit(void) { platform_driver_unregister(&xgpio_plat_driver); }

Contributors

PersonTokensPropCommitsCommitProp
Ricardo Ribalda Delgado15100.00%1100.00%
Total15100.00%1100.00%

module_exit(xgpio_exit); MODULE_AUTHOR("Xilinx, Inc."); MODULE_DESCRIPTION("Xilinx GPIO driver"); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
Ricardo Ribalda Delgado59736.14%625.00%
John Linn51331.05%14.17%
Iban Rodriguez27216.46%14.17%
Michal Simek22513.62%625.00%
Gernot Vormayr160.97%14.17%
Linus Walleij120.73%28.33%
Guenter Roeck60.36%14.17%
Paul Gortmaker30.18%14.17%
Tejun Heo30.18%14.17%
Raphaël Teysseyre20.12%14.17%
Jingoo Han10.06%14.17%
Anton Vorontsov10.06%14.17%
Rob Herring10.06%14.17%
Bill Pemberton0.00%00.00%
Total1652100.00%24100.00%
Directory: drivers/gpio
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.