cregit-Linux how code gets into the kernel

Release 4.17 drivers/pinctrl/pinctrl-ocelot.c

Directory: drivers/pinctrl
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
 * Microsemi SoCs pinctrl driver
 *
 * Author: <alexandre.belloni@free-electrons.com>
 * License: Dual MIT/GPL
 * Copyright (c) 2017 Microsemi Corporation
 */

#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>

#include "core.h"
#include "pinconf.h"
#include "pinmux.h"


#define OCELOT_GPIO_OUT_SET	0x0

#define OCELOT_GPIO_OUT_CLR	0x4

#define OCELOT_GPIO_OUT		0x8

#define OCELOT_GPIO_IN		0xc

#define OCELOT_GPIO_OE		0x10

#define OCELOT_GPIO_INTR	0x14

#define OCELOT_GPIO_INTR_ENA	0x18

#define OCELOT_GPIO_INTR_IDENT	0x1c

#define OCELOT_GPIO_ALT0	0x20

#define OCELOT_GPIO_ALT1	0x24

#define OCELOT_GPIO_SD_MAP	0x28


#define OCELOT_PINS		22

#define OCELOT_FUNC_PER_PIN	4


enum {
	
FUNC_NONE,
	
FUNC_GPIO,
	
FUNC_IRQ0_IN,
	
FUNC_IRQ0_OUT,
	
FUNC_IRQ1_IN,
	
FUNC_IRQ1_OUT,
	
FUNC_MIIM1,
	
FUNC_PCI_WAKE,
	
FUNC_PTP0,
	
FUNC_PTP1,
	
FUNC_PTP2,
	
FUNC_PTP3,
	
FUNC_PWM,
	
FUNC_RECO_CLK0,
	
FUNC_RECO_CLK1,
	
FUNC_SFP0,
	
FUNC_SFP1,
	
FUNC_SFP2,
	
FUNC_SFP3,
	
FUNC_SFP4,
	
FUNC_SFP5,
	
FUNC_SG0,
	
FUNC_SI,
	
FUNC_TACHO,
	
FUNC_TWI,
	
FUNC_TWI_SCL_M,
	
FUNC_UART,
	
FUNC_UART2,
	
FUNC_MAX
};


static const char *const ocelot_function_names[] = {
	[FUNC_NONE]		= "none",
	[FUNC_GPIO]		= "gpio",
	[FUNC_IRQ0_IN]		= "irq0_in",
	[FUNC_IRQ0_OUT]		= "irq0_out",
	[FUNC_IRQ1_IN]		= "irq1_in",
	[FUNC_IRQ1_OUT]		= "irq1_out",
	[FUNC_MIIM1]		= "miim1",
	[FUNC_PCI_WAKE]		= "pci_wake",
	[FUNC_PTP0]		= "ptp0",
	[FUNC_PTP1]		= "ptp1",
	[FUNC_PTP2]		= "ptp2",
	[FUNC_PTP3]		= "ptp3",
	[FUNC_PWM]		= "pwm",
	[FUNC_RECO_CLK0]	= "reco_clk0",
	[FUNC_RECO_CLK1]	= "reco_clk1",
	[FUNC_SFP0]		= "sfp0",
	[FUNC_SFP1]		= "sfp1",
	[FUNC_SFP2]		= "sfp2",
	[FUNC_SFP3]		= "sfp3",
	[FUNC_SFP4]		= "sfp4",
	[FUNC_SFP5]		= "sfp5",
	[FUNC_SG0]		= "sg0",
	[FUNC_SI]		= "si",
	[FUNC_TACHO]		= "tacho",
	[FUNC_TWI]		= "twi",
	[FUNC_TWI_SCL_M]	= "twi_scl_m",
	[FUNC_UART]		= "uart",
	[FUNC_UART2]		= "uart2",
};


struct ocelot_pmx_func {
	
const char **groups;
	
unsigned int ngroups;
};


struct ocelot_pin_caps {
	
unsigned int pin;
	
unsigned char functions[OCELOT_FUNC_PER_PIN];
};


struct ocelot_pinctrl {
	
struct device *dev;
	
struct pinctrl_dev *pctl;
	
struct gpio_chip gpio_chip;
	
struct regmap *map;
	
struct ocelot_pmx_func func[FUNC_MAX];
};


#define OCELOT_P(p, f0, f1, f2)						\
static struct ocelot_pin_caps ocelot_pin_##p = {                        \
        .pin = p,                                                       \
        .functions = {                                                  \
                        FUNC_GPIO, FUNC_##f0, FUNC_##f1, FUNC_##f2,     \
        },                                                              \
}

OCELOT_P(0,  SG0,       NONE,      NONE);
OCELOT_P(1,  SG0,       NONE,      NONE);
OCELOT_P(2,  SG0,       NONE,      NONE);
OCELOT_P(3,  SG0,       NONE,      NONE);
OCELOT_P(4,  IRQ0_IN,   IRQ0_OUT,  TWI);
OCELOT_P(5,  IRQ1_IN,   IRQ1_OUT,  PCI_WAKE);
OCELOT_P(6,  UART,      TWI_SCL_M, NONE);
OCELOT_P(7,  UART,      TWI_SCL_M, NONE);
OCELOT_P(8,  SI,        TWI_SCL_M, IRQ0_OUT);
OCELOT_P(9,  SI,        TWI_SCL_M, IRQ1_OUT);
OCELOT_P(10, PTP2,      TWI_SCL_M, SFP0);
OCELOT_P(11, PTP3,      TWI_SCL_M, SFP1);
OCELOT_P(12, UART2,     TWI_SCL_M, SFP2);
OCELOT_P(13, UART2,     TWI_SCL_M, SFP3);
OCELOT_P(14, MIIM1,     TWI_SCL_M, SFP4);
OCELOT_P(15, MIIM1,     TWI_SCL_M, SFP5);
OCELOT_P(16, TWI,       NONE,      SI);
OCELOT_P(17, TWI,       TWI_SCL_M, SI);
OCELOT_P(18, PTP0,      TWI_SCL_M, NONE);
OCELOT_P(19, PTP1,      TWI_SCL_M, NONE);
OCELOT_P(20, RECO_CLK0, TACHO,     NONE);
OCELOT_P(21, RECO_CLK1, PWM,       NONE);


#define OCELOT_PIN(n) {                                               \
        .number = n,                                            \
        .name = "GPIO_"#n,                                      \
        .drv_data = &ocelot_pin_##n                             \
}


static const struct pinctrl_pin_desc ocelot_pins[] = {
	OCELOT_PIN(0),
	OCELOT_PIN(1),
	OCELOT_PIN(2),
	OCELOT_PIN(3),
	OCELOT_PIN(4),
	OCELOT_PIN(5),
	OCELOT_PIN(6),
	OCELOT_PIN(7),
	OCELOT_PIN(8),
	OCELOT_PIN(9),
	OCELOT_PIN(10),
	OCELOT_PIN(11),
	OCELOT_PIN(12),
	OCELOT_PIN(13),
	OCELOT_PIN(14),
	OCELOT_PIN(15),
	OCELOT_PIN(16),
	OCELOT_PIN(17),
	OCELOT_PIN(18),
	OCELOT_PIN(19),
	OCELOT_PIN(20),
	OCELOT_PIN(21),
};


static int ocelot_get_functions_count(struct pinctrl_dev *pctldev) { return ARRAY_SIZE(ocelot_function_names); }

Contributors

PersonTokensPropCommitsCommitProp
Alexandre Belloni17100.00%1100.00%
Total17100.00%1100.00%


static const char *ocelot_get_function_name(struct pinctrl_dev *pctldev, unsigned int function) { return ocelot_function_names[function]; }

Contributors

PersonTokensPropCommitsCommitProp
Alexandre Belloni23100.00%1100.00%
Total23100.00%1100.00%


static int ocelot_get_function_groups(struct pinctrl_dev *pctldev, unsigned int function, const char *const **groups, unsigned *const num_groups) { struct ocelot_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); *groups = info->func[function].groups; *num_groups = info->func[function].ngroups; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Alexandre Belloni65100.00%1100.00%
Total65100.00%1100.00%


static int ocelot_pin_function_idx(unsigned int pin, unsigned int function) { struct ocelot_pin_caps *p = ocelot_pins[pin].drv_data; int i; for (i = 0; i < OCELOT_FUNC_PER_PIN; i++) { if (function == p->functions[i]) return i; } return -1; }

Contributors

PersonTokensPropCommitsCommitProp
Alexandre Belloni62100.00%1100.00%
Total62100.00%1100.00%


static int ocelot_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int selector, unsigned int group) { struct ocelot_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); struct ocelot_pin_caps *pin = ocelot_pins[group].drv_data; int f; f = ocelot_pin_function_idx(group, selector); if (f < 0) return -EINVAL; /* * f is encoded on two bits. * bit 0 of f goes in BIT(pin) of ALT0, bit 1 of f goes in BIT(pin) of * ALT1 * This is racy because both registers can't be updated at the same time * but it doesn't matter much for now. */ regmap_update_bits(info->map, OCELOT_GPIO_ALT0, BIT(pin->pin), f << pin->pin); regmap_update_bits(info->map, OCELOT_GPIO_ALT1, BIT(pin->pin), f << (pin->pin - 1)); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Alexandre Belloni115100.00%1100.00%
Total115100.00%1100.00%


static int ocelot_gpio_set_direction(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned int pin, bool input) { struct ocelot_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); regmap_update_bits(info->map, OCELOT_GPIO_OE, BIT(pin), input ? 0 : BIT(pin)); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Alexandre Belloni59100.00%2100.00%
Total59100.00%2100.00%


static int ocelot_gpio_request_enable(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned int offset) { struct ocelot_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); regmap_update_bits(info->map, OCELOT_GPIO_ALT0, BIT(offset), 0); regmap_update_bits(info->map, OCELOT_GPIO_ALT1, BIT(offset), 0); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Alexandre Belloni65100.00%1100.00%
Total65100.00%1100.00%

static const struct pinmux_ops ocelot_pmx_ops = { .get_functions_count = ocelot_get_functions_count, .get_function_name = ocelot_get_function_name, .get_function_groups = ocelot_get_function_groups, .set_mux = ocelot_pinmux_set_mux, .gpio_set_direction = ocelot_gpio_set_direction, .gpio_request_enable = ocelot_gpio_request_enable, };
static int ocelot_pctl_get_groups_count(struct pinctrl_dev *pctldev) { return ARRAY_SIZE(ocelot_pins); }

Contributors

PersonTokensPropCommitsCommitProp
Alexandre Belloni17100.00%1100.00%
Total17100.00%1100.00%


static const char *ocelot_pctl_get_group_name(struct pinctrl_dev *pctldev, unsigned int group) { return ocelot_pins[group].name; }

Contributors

PersonTokensPropCommitsCommitProp
Alexandre Belloni25100.00%1100.00%
Total25100.00%1100.00%


static int ocelot_pctl_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group, const unsigned int **pins, unsigned int *num_pins) { *pins = &ocelot_pins[group].number; *num_pins = 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Alexandre Belloni46100.00%1100.00%
Total46100.00%1100.00%

static const struct pinctrl_ops ocelot_pctl_ops = { .get_groups_count = ocelot_pctl_get_groups_count, .get_group_name = ocelot_pctl_get_group_name, .get_group_pins = ocelot_pctl_get_group_pins, .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, .dt_free_map = pinconf_generic_dt_free_map, }; static struct pinctrl_desc ocelot_desc = { .name = "ocelot-pinctrl", .pins = ocelot_pins, .npins = ARRAY_SIZE(ocelot_pins), .pctlops = &ocelot_pctl_ops, .pmxops = &ocelot_pmx_ops, .owner = THIS_MODULE, };
static int ocelot_create_group_func_map(struct device *dev, struct ocelot_pinctrl *info) { u16 pins[ARRAY_SIZE(ocelot_pins)]; int f, npins, i; for (f = 0; f < FUNC_MAX; f++) { for (npins = 0, i = 0; i < ARRAY_SIZE(ocelot_pins); i++) { if (ocelot_pin_function_idx(i, f) >= 0) pins[npins++] = i; } info->func[f].ngroups = npins; info->func[f].groups = devm_kzalloc(dev, npins * sizeof(char *), GFP_KERNEL); if (!info->func[f].groups) return -ENOMEM; for (i = 0; i < npins; i++) info->func[f].groups[i] = ocelot_pins[pins[i]].name; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Alexandre Belloni177100.00%1100.00%
Total177100.00%1100.00%


static int ocelot_pinctrl_register(struct platform_device *pdev, struct ocelot_pinctrl *info) { int ret; ret = ocelot_create_group_func_map(&pdev->dev, info); if (ret) { dev_err(&pdev->dev, "Unable to create group func map.\n"); return ret; } info->pctl = devm_pinctrl_register(&pdev->dev, &ocelot_desc, info); if (IS_ERR(info->pctl)) { dev_err(&pdev->dev, "Failed to register pinctrl\n"); return PTR_ERR(info->pctl); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Alexandre Belloni99100.00%1100.00%
Total99100.00%1100.00%


static int ocelot_gpio_get(struct gpio_chip *chip, unsigned int offset) { struct ocelot_pinctrl *info = gpiochip_get_data(chip); unsigned int val; regmap_read(info->map, OCELOT_GPIO_IN, &val); return !!(val & BIT(offset)); }

Contributors

PersonTokensPropCommitsCommitProp
Alexandre Belloni53100.00%1100.00%
Total53100.00%1100.00%


static void ocelot_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) { struct ocelot_pinctrl *info = gpiochip_get_data(chip); if (value) regmap_write(info->map, OCELOT_GPIO_OUT_SET, BIT(offset)); else regmap_write(info->map, OCELOT_GPIO_OUT_CLR, BIT(offset)); }

Contributors

PersonTokensPropCommitsCommitProp
Alexandre Belloni61100.00%1100.00%
Total61100.00%1100.00%


static int ocelot_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) { struct ocelot_pinctrl *info = gpiochip_get_data(chip); unsigned int val; regmap_read(info->map, OCELOT_GPIO_OE, &val); return !(val & BIT(offset)); }

Contributors

PersonTokensPropCommitsCommitProp
Alexandre Belloni52100.00%1100.00%
Total52100.00%1100.00%


static int ocelot_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) { return pinctrl_gpio_direction_input(chip->base + offset); }

Contributors

PersonTokensPropCommitsCommitProp
Alexandre Belloni25100.00%1100.00%
Total25100.00%1100.00%


static int ocelot_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, int value) { struct ocelot_pinctrl *info = gpiochip_get_data(chip); unsigned int pin = BIT(offset); if (value) regmap_write(info->map, OCELOT_GPIO_OUT_SET, pin); else regmap_write(info->map, OCELOT_GPIO_OUT_CLR, pin); return pinctrl_gpio_direction_output(chip->base + offset); }

Contributors

PersonTokensPropCommitsCommitProp
Alexandre Belloni74100.00%1100.00%
Total74100.00%1100.00%

static const struct gpio_chip ocelot_gpiolib_chip = { .request = gpiochip_generic_request, .free = gpiochip_generic_free, .set = ocelot_gpio_set, .get = ocelot_gpio_get, .get_direction = ocelot_gpio_get_direction, .direction_input = ocelot_gpio_direction_input, .direction_output = ocelot_gpio_direction_output, .owner = THIS_MODULE, };
static int ocelot_gpiochip_register(struct platform_device *pdev, struct ocelot_pinctrl *info) { struct gpio_chip *gc; int ret; info->gpio_chip = ocelot_gpiolib_chip; gc = &info->gpio_chip; gc->ngpio = OCELOT_PINS; gc->parent = &pdev->dev; gc->base = 0; gc->of_node = info->dev->of_node; gc->label = "ocelot-gpio"; ret = devm_gpiochip_add_data(&pdev->dev, gc, info); if (ret) return ret; /* TODO: this can be used as an irqchip but no board is using that */ return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Alexandre Belloni99100.00%1100.00%
Total99100.00%1100.00%

static const struct regmap_config ocelot_pinctrl_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, .max_register = 0x64, }; static const struct of_device_id ocelot_pinctrl_of_match[] = { { .compatible = "mscc,ocelot-pinctrl" }, {}, };
static int ocelot_pinctrl_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct ocelot_pinctrl *info; void __iomem *base; int ret; info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; base = devm_ioremap_resource(dev, platform_get_resource(pdev, IORESOURCE_MEM, 0)); if (IS_ERR(base)) { dev_err(dev, "Failed to ioremap registers\n"); return PTR_ERR(base); } info->map = devm_regmap_init_mmio(dev, base, &ocelot_pinctrl_regmap_config); if (IS_ERR(info->map)) { dev_err(dev, "Failed to create regmap\n"); return PTR_ERR(info->map); } dev_set_drvdata(dev, info->map); info->dev = dev; ret = ocelot_pinctrl_register(pdev, info); if (ret) return ret; ret = ocelot_gpiochip_register(pdev, info); if (ret) return ret; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Alexandre Belloni18599.46%150.00%
Colin Ian King10.54%150.00%
Total186100.00%2100.00%

static struct platform_driver ocelot_pinctrl_driver = { .driver = { .name = "pinctrl-ocelot", .of_match_table = of_match_ptr(ocelot_pinctrl_of_match), .suppress_bind_attrs = true, }, .probe = ocelot_pinctrl_probe, }; builtin_platform_driver(ocelot_pinctrl_driver);

Overall Contributors

PersonTokensPropCommitsCommitProp
Alexandre Belloni234899.96%266.67%
Colin Ian King10.04%133.33%
Total2349100.00%3100.00%
Directory: drivers/pinctrl
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.