mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-18 23:09:29 +02:00
Replace devm_kasprintf() with dev_name() for the chip label. dev_name() returns a stable pointer to the device name, so the separate allocation and -ENOMEM check can be dropped. Using dev_name() seems to be common for GPIO labels. Signed-off-by: Rosen Penev <rosenp@gmail.com> Reviewed-by: Linus Walleij <linusw@kernel.org> Signed-off-by: Madhavan Srinivasan <maddy@linux.ibm.com> Link: https://patch.msgid.link/20260803223539.86303-9-rosenp@gmail.com
209 lines
4.7 KiB
C
209 lines
4.7 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* PPC44x gpio driver
|
|
*
|
|
* Copyright (c) 2008 Harris Corporation
|
|
* Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
|
|
* Copyright (c) MontaVista Software, Inc. 2008.
|
|
*
|
|
* Author: Steve Falco <sfalco@harris.com>
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/init.h>
|
|
#include <linux/io.h>
|
|
#include <linux/of.h>
|
|
#include <linux/gpio/generic.h>
|
|
#include <linux/types.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/platform_device.h>
|
|
|
|
#define GPIO_MASK(gpio) (0x80000000 >> (gpio))
|
|
#define GPIO_MASK2(gpio) (0xc0000000 >> (((gpio) % 16) * 2))
|
|
|
|
/* Physical GPIO register layout */
|
|
struct ppc44x_gpio {
|
|
__be32 or;
|
|
__be32 tcr;
|
|
__be32 osrl;
|
|
__be32 osrh;
|
|
__be32 tsrl;
|
|
__be32 tsrh;
|
|
__be32 odr;
|
|
__be32 ir;
|
|
__be32 rr1;
|
|
__be32 rr2;
|
|
__be32 rr3;
|
|
__be32 reserved1;
|
|
__be32 isr1l;
|
|
__be32 isr1h;
|
|
__be32 isr2l;
|
|
__be32 isr2h;
|
|
__be32 isr3l;
|
|
__be32 isr3h;
|
|
};
|
|
|
|
struct ppc44x_gpio_chip {
|
|
struct gpio_generic_chip chip;
|
|
void __iomem *regs;
|
|
};
|
|
|
|
static inline void ppc44x_clrbits32(void __iomem *addr, u32 mask)
|
|
{
|
|
u32 val = ioread32be(addr);
|
|
|
|
val &= ~mask;
|
|
iowrite32be(val, addr);
|
|
}
|
|
|
|
static inline void ppc44x_setbits32(void __iomem *addr, u32 mask)
|
|
{
|
|
u32 val = ioread32be(addr);
|
|
|
|
val |= mask;
|
|
iowrite32be(val, addr);
|
|
}
|
|
|
|
/*
|
|
* GPIO LIB API implementation for GPIOs
|
|
*
|
|
* There are a maximum of 32 gpios in each gpio controller.
|
|
*/
|
|
|
|
static inline void
|
|
__ppc44x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
|
{
|
|
struct ppc44x_gpio_chip *chip = gpiochip_get_data(gc);
|
|
struct gpio_generic_chip *gen_gc = &chip->chip;
|
|
|
|
if (val)
|
|
gen_gc->sdata |= GPIO_MASK(gpio);
|
|
else
|
|
gen_gc->sdata &= ~GPIO_MASK(gpio);
|
|
|
|
gpio_generic_write_reg(gen_gc, gen_gc->reg_set, gen_gc->sdata);
|
|
}
|
|
|
|
static int ppc44x_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
|
|
{
|
|
struct ppc44x_gpio_chip *chip = gpiochip_get_data(gc);
|
|
struct gpio_generic_chip *gen_gc = &chip->chip;
|
|
struct ppc44x_gpio __iomem *regs = chip->regs;
|
|
|
|
guard(gpio_generic_lock_irqsave)(gen_gc);
|
|
|
|
/* Disable open-drain function */
|
|
ppc44x_clrbits32(®s->odr, GPIO_MASK(gpio));
|
|
|
|
/* Float the pin */
|
|
ppc44x_clrbits32(®s->tcr, GPIO_MASK(gpio));
|
|
gen_gc->sdir &= ~GPIO_MASK(gpio);
|
|
|
|
/* Bits 0-15 use TSRL/OSRL, bits 16-31 use TSRH/OSRH */
|
|
if (gpio < 16) {
|
|
ppc44x_clrbits32(®s->osrl, GPIO_MASK2(gpio));
|
|
ppc44x_clrbits32(®s->tsrl, GPIO_MASK2(gpio));
|
|
} else {
|
|
ppc44x_clrbits32(®s->osrh, GPIO_MASK2(gpio));
|
|
ppc44x_clrbits32(®s->tsrh, GPIO_MASK2(gpio));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ppc44x_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
|
|
{
|
|
struct ppc44x_gpio_chip *chip = gpiochip_get_data(gc);
|
|
struct gpio_generic_chip *gen_gc = &chip->chip;
|
|
struct ppc44x_gpio __iomem *regs = chip->regs;
|
|
|
|
guard(gpio_generic_lock_irqsave)(gen_gc);
|
|
|
|
/* First set initial value */
|
|
__ppc44x_gpio_set(gc, gpio, val);
|
|
|
|
/* Disable open-drain function */
|
|
ppc44x_clrbits32(®s->odr, GPIO_MASK(gpio));
|
|
|
|
/* Drive the pin */
|
|
ppc44x_setbits32(®s->tcr, GPIO_MASK(gpio));
|
|
gen_gc->sdir |= GPIO_MASK(gpio);
|
|
|
|
/* Bits 0-15 use TSRL, bits 16-31 use TSRH */
|
|
if (gpio < 16) {
|
|
ppc44x_clrbits32(®s->osrl, GPIO_MASK2(gpio));
|
|
ppc44x_clrbits32(®s->tsrl, GPIO_MASK2(gpio));
|
|
} else {
|
|
ppc44x_clrbits32(®s->osrh, GPIO_MASK2(gpio));
|
|
ppc44x_clrbits32(®s->tsrh, GPIO_MASK2(gpio));
|
|
}
|
|
|
|
pr_debug("%s: gpio: %d val: %d\n", __func__, gpio, val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ppc44x_gpio_probe(struct platform_device *ofdev)
|
|
{
|
|
struct device *dev = &ofdev->dev;
|
|
struct ppc44x_gpio __iomem *regs;
|
|
struct ppc44x_gpio_chip *chip;
|
|
struct gpio_generic_chip_config config;
|
|
struct gpio_chip *gc;
|
|
int ret;
|
|
|
|
regs = devm_platform_ioremap_resource(ofdev, 0);
|
|
if (IS_ERR(regs))
|
|
return PTR_ERR(regs);
|
|
|
|
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
|
|
if (!chip)
|
|
return -ENOMEM;
|
|
|
|
chip->regs = regs;
|
|
|
|
config = (struct gpio_generic_chip_config) {
|
|
.dev = dev,
|
|
.sz = 4,
|
|
.dat = ®s->ir,
|
|
.set = ®s->or,
|
|
.dirout = ®s->tcr,
|
|
.flags = GPIO_GENERIC_BIG_ENDIAN |
|
|
GPIO_GENERIC_BIG_ENDIAN_BYTE_ORDER,
|
|
};
|
|
|
|
ret = gpio_generic_chip_init(&chip->chip, &config);
|
|
if (ret)
|
|
return ret;
|
|
|
|
gc = &chip->chip.gc;
|
|
gc->label = dev_name(dev);
|
|
gc->parent = dev;
|
|
gc->direction_input = ppc44x_gpio_dir_in;
|
|
gc->direction_output = ppc44x_gpio_dir_out;
|
|
|
|
return devm_gpiochip_add_data(dev, gc, chip);
|
|
}
|
|
|
|
static const struct of_device_id ppc44x_gpio_match[] = {
|
|
{
|
|
.compatible = "ibm,ppc4xx-gpio",
|
|
},
|
|
{},
|
|
};
|
|
MODULE_DEVICE_TABLE(of, ppc44x_gpio_match);
|
|
|
|
static struct platform_driver ppc44x_gpio_driver = {
|
|
.probe = ppc44x_gpio_probe,
|
|
.driver = {
|
|
.name = "ppc44x-gpio",
|
|
.of_match_table = ppc44x_gpio_match,
|
|
},
|
|
};
|
|
|
|
MODULE_DESCRIPTION("PPC44x gpio driver");
|
|
MODULE_LICENSE("GPL");
|
|
|
|
module_platform_driver(ppc44x_gpio_driver);
|