cregit-Linux how code gets into the kernel

Release 4.7 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 ribaldaricardo ribalda32100.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 ribaldaricardo ribalda30100.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 ribaldaricardo ribalda3697.30%266.67%
john linnjohn 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 ribaldaricardo ribalda3345.21%240.00%
john linnjohn linn3041.10%120.00%
michal simekmichal simek810.96%120.00%
linus walleijlinus 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 linnjohn linn8559.86%116.67%
ricardo ribaldaricardo ribalda4632.39%233.33%
michal simekmichal simek96.34%233.33%
linus walleijlinus walleij21.41%116.67%
Total142100.00%6100.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 linnjohn linn7459.68%116.67%
ricardo ribaldaricardo ribalda4233.87%233.33%
michal simekmichal simek64.84%233.33%
linus walleijlinus 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 linnjohn linn10256.04%116.67%
ricardo ribaldaricardo ribalda6334.62%233.33%
michal simekmichal simek158.24%233.33%
linus walleijlinus 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 ribaldaricardo ribalda5148.57%120.00%
john linnjohn linn4441.90%120.00%
guenter roeckguenter roeck65.71%120.00%
michal simekmichal simek21.90%120.00%
raphael teysseyreraphael teysseyre21.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 ribaldaricardo ribalda2475.00%375.00%
john linnjohn 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.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("%s: error in probe function with status %d\n", np->full_name, status); return status; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
ricardo ribaldaricardo ribalda14338.24%220.00%
michal simekmichal simek14237.97%330.00%
john linnjohn linn6918.45%110.00%
gernot vormayrgernot vormayr154.01%110.00%
linus walleijlinus walleij41.07%220.00%
anton vorontsovanton vorontsov10.27%110.00%
Total374100.00%10100.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 linnjohn linn1275.00%150.00%
ricardo ribaldaricardo ribalda425.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 ribaldaricardo ribalda15100.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 ribaldaricardo ribalda59743.20%627.27%
john linnjohn linn51237.05%14.55%
michal simekmichal simek23016.64%627.27%
gernot vormayrgernot vormayr151.09%14.55%
linus walleijlinus walleij120.87%29.09%
guenter roeckguenter roeck60.43%14.55%
paul gortmakerpaul gortmaker30.22%14.55%
tejun heotejun heo30.22%14.55%
raphael teysseyreraphael teysseyre20.14%14.55%
jingoo hanjingoo han10.07%14.55%
anton vorontsovanton vorontsov10.07%14.55%
bill pembertonbill pemberton0.00%00.00%
Total1382100.00%22100.00%
Directory: drivers/gpio
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}