xref: /OK3568_Linux_fs/kernel/drivers/gpio/gpio-octeon.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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