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