159243Sobrien// SPDX-License-Identifier: GPL-2.0+ 259243Sobrien/* 359243Sobrien * Driver for BCM63xx GPIO unit (pinctrl + GPIO) 459243Sobrien * 559243Sobrien * Copyright (C) 2021 ��lvaro Fern��ndez Rojas <noltari@gmail.com> 659243Sobrien * Copyright (C) 2016 Jonas Gorski <jonas.gorski@gmail.com> 759243Sobrien */ 859243Sobrien 959243Sobrien#include <linux/gpio/regmap.h> 1059243Sobrien#include <linux/mfd/syscon.h> 1159243Sobrien#include <linux/mod_devicetable.h> 1259243Sobrien#include <linux/of.h> 1359243Sobrien#include <linux/platform_device.h> 1459243Sobrien 1559243Sobrien#include "pinctrl-bcm63xx.h" 16100616Smp 1759243Sobrien#define BCM63XX_BANK_SIZE 4 1859243Sobrien 1959243Sobrien#define BCM63XX_DIROUT_REG 0x04 2059243Sobrien#define BCM63XX_DATA_REG 0x0c 2159243Sobrien 2259243Sobrienstatic int bcm63xx_reg_mask_xlate(struct gpio_regmap *gpio, 2359243Sobrien unsigned int base, unsigned int offset, 2459243Sobrien unsigned int *reg, unsigned int *mask) 2559243Sobrien{ 2659243Sobrien unsigned int line = offset % BCM63XX_BANK_GPIOS; 2759243Sobrien unsigned int stride = offset / BCM63XX_BANK_GPIOS; 2859243Sobrien 2959243Sobrien *reg = base - stride * BCM63XX_BANK_SIZE; 3059243Sobrien *mask = BIT(line); 3159243Sobrien 3259243Sobrien return 0; 3359243Sobrien} 3459243Sobrien 3559243Sobrienstatic const struct of_device_id bcm63xx_gpio_of_match[] = { 3659243Sobrien { .compatible = "brcm,bcm6318-gpio", }, 3769408Sache { .compatible = "brcm,bcm6328-gpio", }, 3859243Sobrien { .compatible = "brcm,bcm6358-gpio", }, 39167465Smp { .compatible = "brcm,bcm6362-gpio", }, 40167465Smp { .compatible = "brcm,bcm6368-gpio", }, 4169408Sache { .compatible = "brcm,bcm63268-gpio", }, 4259243Sobrien { /* sentinel */ } 4359243Sobrien}; 4459243Sobrien 4559243Sobrienstatic int bcm63xx_gpio_probe(struct device *dev, struct device_node *node, 4659243Sobrien const struct bcm63xx_pinctrl_soc *soc, 4759243Sobrien struct bcm63xx_pinctrl *pc) 4859243Sobrien{ 4959243Sobrien struct gpio_regmap_config grc = {0}; 5059243Sobrien 5159243Sobrien grc.parent = dev; 5259243Sobrien grc.fwnode = &node->fwnode; 5359243Sobrien grc.ngpio = soc->ngpios; 54145479Smp grc.ngpio_per_reg = BCM63XX_BANK_GPIOS; 55145479Smp grc.regmap = pc->regs; 56354195Sbrooks grc.reg_dat_base = BCM63XX_DATA_REG; 57145479Smp grc.reg_dir_out_base = BCM63XX_DIROUT_REG; 58145479Smp grc.reg_set_base = BCM63XX_DATA_REG; 59145479Smp grc.reg_mask_xlate = bcm63xx_reg_mask_xlate; 60167465Smp 6159243Sobrien return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &grc)); 62167465Smp} 63167465Smp 64167465Smpint bcm63xx_pinctrl_probe(struct platform_device *pdev, 6559243Sobrien const struct bcm63xx_pinctrl_soc *soc, 66167465Smp void *driver_data) 67167465Smp{ 68167465Smp struct device *dev = &pdev->dev; 6959243Sobrien struct bcm63xx_pinctrl *pc; 70167465Smp struct device_node *node; 71167465Smp int err; 7259243Sobrien 73167465Smp pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL); 74167465Smp if (!pc) 7559243Sobrien return -ENOMEM; 7659243Sobrien 7759243Sobrien platform_set_drvdata(pdev, pc); 7859243Sobrien 7959243Sobrien pc->dev = dev; 8059243Sobrien pc->driver_data = driver_data; 8159243Sobrien 82167465Smp pc->regs = syscon_node_to_regmap(dev->parent->of_node); 83167465Smp if (IS_ERR(pc->regs)) 84167465Smp return PTR_ERR(pc->regs); 8561524Sobrien 8661524Sobrien pc->pctl_desc.name = dev_name(dev); 8761524Sobrien pc->pctl_desc.pins = soc->pins; 8861524Sobrien pc->pctl_desc.npins = soc->npins; 8961524Sobrien pc->pctl_desc.pctlops = soc->pctl_ops; 9059243Sobrien pc->pctl_desc.pmxops = soc->pmx_ops; 9159243Sobrien pc->pctl_desc.owner = THIS_MODULE; 9259243Sobrien 9359243Sobrien pc->pctl_dev = devm_pinctrl_register(dev, &pc->pctl_desc, pc); 9459243Sobrien if (IS_ERR(pc->pctl_dev)) 95167465Smp return PTR_ERR(pc->pctl_dev); 9659243Sobrien 97167465Smp for_each_child_of_node(dev->parent->of_node, node) { 98167465Smp if (of_match_node(bcm63xx_gpio_of_match, node)) { 99167465Smp err = bcm63xx_gpio_probe(dev, node, soc, pc); 100145479Smp if (err) { 101145479Smp dev_err(dev, "could not add GPIO chip\n"); 10259243Sobrien of_node_put(node); 10359243Sobrien return err; 10459243Sobrien } 105167465Smp } 106167465Smp } 10759243Sobrien 108167465Smp return 0; 10959243Sobrien} 110167465Smp