cregit-Linux how code gets into the kernel

Release 4.7 drivers/gpio/gpio-syscon.c

Directory: drivers/gpio
/*
 *  SYSCON GPIO driver
 *
 *  Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
 *
 * 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.
 */

#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>


#define GPIO_SYSCON_FEAT_IN	BIT(0)

#define GPIO_SYSCON_FEAT_OUT	BIT(1)

#define GPIO_SYSCON_FEAT_DIR	BIT(2)

/* SYSCON driver is designed to use 32-bit wide registers */

#define SYSCON_REG_SIZE		(4)

#define SYSCON_REG_BITS		(SYSCON_REG_SIZE * 8)

/**
 * struct syscon_gpio_data - Configuration for the device.
 * compatible:          SYSCON driver compatible string.
 * flags:               Set of GPIO_SYSCON_FEAT_ flags:
 *                      GPIO_SYSCON_FEAT_IN:    GPIOs supports input,
 *                      GPIO_SYSCON_FEAT_OUT:   GPIOs supports output,
 *                      GPIO_SYSCON_FEAT_DIR:   GPIOs supports switch direction.
 * bit_count:           Number of bits used as GPIOs.
 * dat_bit_offset:      Offset (in bits) to the first GPIO bit.
 * dir_bit_offset:      Optional offset (in bits) to the first bit to switch
 *                      GPIO direction (Used with GPIO_SYSCON_FEAT_DIR flag).
 * set:         HW specific callback to assigns output value
 *                      for signal "offset"
 */


struct syscon_gpio_data {
	
const char	*compatible;
	
unsigned int	flags;
	
unsigned int	bit_count;
	
unsigned int	dat_bit_offset;
	
unsigned int	dir_bit_offset;
	
void		(*set)(struct gpio_chip *chip,
			       unsigned offset, int value);
};


struct syscon_gpio_priv {
	
struct gpio_chip		chip;
	
struct regmap			*syscon;
	
const struct syscon_gpio_data	*data;
	
u32				dreg_offset;
	
u32				dir_reg_offset;
};


static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset) { struct syscon_gpio_priv *priv = gpiochip_get_data(chip); unsigned int val, offs; int ret; offs = priv->dreg_offset + priv->data->dat_bit_offset + offset; ret = regmap_read(priv->syscon, (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, &val); if (ret) return ret; return !!(val & BIT(offs % SYSCON_REG_BITS)); }

Contributors

PersonTokensPropCommitsCommitProp
alexander shiyanalexander shiyan7686.36%133.33%
grygorii strashkogrygorii strashko1112.50%133.33%
linus walleijlinus walleij11.14%133.33%
Total88100.00%3100.00%


static void syscon_gpio_set(struct gpio_chip *chip, unsigned offset, int val) { struct syscon_gpio_priv *priv = gpiochip_get_data(chip); unsigned int offs; offs = priv->dreg_offset + priv->data->dat_bit_offset + offset; regmap_update_bits(priv->syscon, (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, BIT(offs % SYSCON_REG_BITS), val ? BIT(offs % SYSCON_REG_BITS) : 0); }

Contributors

PersonTokensPropCommitsCommitProp
alexander shiyanalexander shiyan6988.46%133.33%
grygorii strashkogrygorii strashko810.26%133.33%
linus walleijlinus walleij11.28%133.33%
Total78100.00%3100.00%


static int syscon_gpio_dir_in(struct gpio_chip *chip, unsigned offset) { struct syscon_gpio_priv *priv = gpiochip_get_data(chip); if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) { unsigned int offs; offs = priv->dir_reg_offset + priv->data->dir_bit_offset + offset; regmap_update_bits(priv->syscon, (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, BIT(offs % SYSCON_REG_BITS), 0); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
alexander shiyanalexander shiyan7288.89%133.33%
grygorii strashkogrygorii strashko89.88%133.33%
linus walleijlinus walleij11.23%133.33%
Total81100.00%3100.00%


static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val) { struct syscon_gpio_priv *priv = gpiochip_get_data(chip); if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) { unsigned int offs; offs = priv->dir_reg_offset + priv->data->dir_bit_offset + offset; regmap_update_bits(priv->syscon, (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, BIT(offs % SYSCON_REG_BITS), BIT(offs % SYSCON_REG_BITS)); } priv->data->set(chip, offset, val); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
alexander shiyanalexander shiyan8886.27%125.00%
grygorii strashkogrygorii strashko1312.75%250.00%
linus walleijlinus walleij10.98%125.00%
Total102100.00%4100.00%

static const struct syscon_gpio_data clps711x_mctrl_gpio = { /* ARM CLPS711X SYSFLG1 Bits 8-10 */ .compatible = "cirrus,clps711x-syscon1", .flags = GPIO_SYSCON_FEAT_IN, .bit_count = 3, .dat_bit_offset = 0x40 * 8 + 8, }; #define KEYSTONE_LOCK_BIT BIT(0)
static void keystone_gpio_set(struct gpio_chip *chip, unsigned offset, int val) { struct syscon_gpio_priv *priv = gpiochip_get_data(chip); unsigned int offs; int ret; offs = priv->dreg_offset + priv->data->dat_bit_offset + offset; if (!val) return; ret = regmap_update_bits( priv->syscon, (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, BIT(offs % SYSCON_REG_BITS) | KEYSTONE_LOCK_BIT, BIT(offs % SYSCON_REG_BITS) | KEYSTONE_LOCK_BIT); if (ret < 0) dev_err(chip->parent, "gpio write failed ret(%d)\n", ret); }

Contributors

PersonTokensPropCommitsCommitProp
grygorii strashkogrygorii strashko10498.11%133.33%
linus walleijlinus walleij21.89%266.67%
Total106100.00%3100.00%

static const struct syscon_gpio_data keystone_dsp_gpio = { /* ARM Keystone 2 */ .compatible = NULL, .flags = GPIO_SYSCON_FEAT_OUT, .bit_count = 28, .dat_bit_offset = 4, .set = keystone_gpio_set, }; static const struct of_device_id syscon_gpio_ids[] = { { .compatible = "cirrus,clps711x-mctrl-gpio", .data = &clps711x_mctrl_gpio, }, { .compatible = "ti,keystone-dsp-gpio", .data = &keystone_dsp_gpio, }, { } }; MODULE_DEVICE_TABLE(of, syscon_gpio_ids);
static int syscon_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; const struct of_device_id *of_id; struct syscon_gpio_priv *priv; struct device_node *np = dev->of_node; int ret; of_id = of_match_device(syscon_gpio_ids, dev); if (!of_id) return -ENODEV; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; priv->data = of_id->data; if (priv->data->compatible) { priv->syscon = syscon_regmap_lookup_by_compatible( priv->data->compatible); if (IS_ERR(priv->syscon)) return PTR_ERR(priv->syscon); } else { priv->syscon = syscon_regmap_lookup_by_phandle(np, "gpio,syscon-dev"); if (IS_ERR(priv->syscon)) return PTR_ERR(priv->syscon); ret = of_property_read_u32_index(np, "gpio,syscon-dev", 1, &priv->dreg_offset); if (ret) dev_err(dev, "can't read the data register offset!\n"); priv->dreg_offset <<= 3; ret = of_property_read_u32_index(np, "gpio,syscon-dev", 2, &priv->dir_reg_offset); if (ret) dev_dbg(dev, "can't read the dir register offset!\n"); priv->dir_reg_offset <<= 3; } priv->chip.parent = dev; priv->chip.owner = THIS_MODULE; priv->chip.label = dev_name(dev); priv->chip.base = -1; priv->chip.ngpio = priv->data->bit_count; priv->chip.get = syscon_gpio_get; if (priv->data->flags & GPIO_SYSCON_FEAT_IN) priv->chip.direction_input = syscon_gpio_dir_in; if (priv->data->flags & GPIO_SYSCON_FEAT_OUT) { priv->chip.set = priv->data->set ? : syscon_gpio_set; priv->chip.direction_output = syscon_gpio_dir_out; } platform_set_drvdata(pdev, priv); return devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv); }

Contributors

PersonTokensPropCommitsCommitProp
alexander shiyanalexander shiyan21258.40%112.50%
grygorii strashkogrygorii strashko12634.71%337.50%
labbe corentinlabbe corentin184.96%112.50%
laxman dewanganlaxman dewangan51.38%112.50%
linus walleijlinus walleij20.55%225.00%
Total363100.00%8100.00%

static struct platform_driver syscon_gpio_driver = { .driver = { .name = "gpio-syscon", .of_match_table = syscon_gpio_ids, }, .probe = syscon_gpio_probe, }; module_platform_driver(syscon_gpio_driver); MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); MODULE_DESCRIPTION("SYSCON GPIO driver"); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
alexander shiyanalexander shiyan72065.63%111.11%
grygorii strashkogrygorii strashko34631.54%444.44%
labbe corentinlabbe corentin181.64%111.11%
linus walleijlinus walleij80.73%222.22%
laxman dewanganlaxman dewangan50.46%111.11%
Total1097100.00%9100.00%
Directory: drivers/gpio
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}