^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * This file is subject to the terms and conditions of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * License. See the file "COPYING" in the main directory of this archive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2011, 2012 Cavium Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/gpio/driver.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <asm/octeon/octeon.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <asm/octeon/cvmx-gpio-defs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define RX_DAT 0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define TX_SET 0x88
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define TX_CLEAR 0x90
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * The address offset of the GPIO configuration register for a given
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * line.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static unsigned int bit_cfg_reg(unsigned int offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * The register stride is 8, with a discontinuity after the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * first 16.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) if (offset < 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) return 8 * offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) return 8 * (offset - 16) + 0x100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct octeon_gpio {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct gpio_chip chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) u64 register_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) static int octeon_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct octeon_gpio *gpio = gpiochip_get_data(chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) cvmx_write_csr(gpio->register_base + bit_cfg_reg(offset), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) static void octeon_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) struct octeon_gpio *gpio = gpiochip_get_data(chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) u64 mask = 1ull << offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) u64 reg = gpio->register_base + (value ? TX_SET : TX_CLEAR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) cvmx_write_csr(reg, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) static int octeon_gpio_dir_out(struct gpio_chip *chip, unsigned offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) int value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) struct octeon_gpio *gpio = gpiochip_get_data(chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) union cvmx_gpio_bit_cfgx cfgx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) octeon_gpio_set(chip, offset, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) cfgx.u64 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) cfgx.s.tx_oe = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) cvmx_write_csr(gpio->register_base + bit_cfg_reg(offset), cfgx.u64);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static int octeon_gpio_get(struct gpio_chip *chip, unsigned offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) struct octeon_gpio *gpio = gpiochip_get_data(chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) u64 read_bits = cvmx_read_csr(gpio->register_base + RX_DAT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) return ((1ull << offset) & read_bits) != 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static int octeon_gpio_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) struct octeon_gpio *gpio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) struct gpio_chip *chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) void __iomem *reg_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) if (!gpio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) chip = &gpio->chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) reg_base = devm_platform_ioremap_resource(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) if (IS_ERR(reg_base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return PTR_ERR(reg_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) gpio->register_base = (u64)reg_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) pdev->dev.platform_data = chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) chip->label = "octeon-gpio";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) chip->parent = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) chip->owner = THIS_MODULE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) chip->base = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) chip->can_sleep = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) chip->ngpio = 20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) chip->direction_input = octeon_gpio_dir_in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) chip->get = octeon_gpio_get;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) chip->direction_output = octeon_gpio_dir_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) chip->set = octeon_gpio_set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) err = devm_gpiochip_add_data(&pdev->dev, chip, gpio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) dev_info(&pdev->dev, "OCTEON GPIO driver probed.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) static const struct of_device_id octeon_gpio_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) .compatible = "cavium,octeon-3860-gpio",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) MODULE_DEVICE_TABLE(of, octeon_gpio_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) static struct platform_driver octeon_gpio_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) .name = "octeon_gpio",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) .of_match_table = octeon_gpio_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) .probe = octeon_gpio_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) module_platform_driver(octeon_gpio_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) MODULE_DESCRIPTION("Cavium Inc. OCTEON GPIO Driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) MODULE_AUTHOR("David Daney");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) MODULE_LICENSE("GPL");