Blame view

drivers/gpio/gpio-exar.c 5.34 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
6596e59e6   Sudip Mukherjee   gpio: exar: add g...
2
3
4
5
  /*
   * GPIO driver for Exar XR17V35X chip
   *
   * Copyright (C) 2015 Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>
6596e59e6   Sudip Mukherjee   gpio: exar: add g...
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   */
  #include <linux/bitops.h>
  #include <linux/device.h>
  #include <linux/gpio/driver.h>
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/pci.h>
  #include <linux/platform_device.h>
  
  #define EXAR_OFFSET_MPIOLVL_LO 0x90
  #define EXAR_OFFSET_MPIOSEL_LO 0x93
  #define EXAR_OFFSET_MPIOLVL_HI 0x96
  #define EXAR_OFFSET_MPIOSEL_HI 0x99
  
  #define DRIVER_NAME "gpio_exar"
  
  static DEFINE_IDA(ida_index);
  
  struct exar_gpio_chip {
  	struct gpio_chip gpio_chip;
  	struct mutex lock;
  	int index;
  	void __iomem *regs;
  	char name[20];
380b1e2f3   Jan Kiszka   gpio-exar/8250-ex...
31
  	unsigned int first_pin;
6596e59e6   Sudip Mukherjee   gpio: exar: add g...
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
  };
  
  static void exar_update(struct gpio_chip *chip, unsigned int reg, int val,
  			unsigned int offset)
  {
  	struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
  	int temp;
  
  	mutex_lock(&exar_gpio->lock);
  	temp = readb(exar_gpio->regs + reg);
  	temp &= ~BIT(offset);
  	if (val)
  		temp |= BIT(offset);
  	writeb(temp, exar_gpio->regs + reg);
  	mutex_unlock(&exar_gpio->lock);
  }
  
  static int exar_set_direction(struct gpio_chip *chip, int direction,
  			      unsigned int offset)
  {
380b1e2f3   Jan Kiszka   gpio-exar/8250-ex...
52
53
54
55
  	struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
  	unsigned int addr = (offset + exar_gpio->first_pin) / 8 ?
  		EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;
  	unsigned int bit  = (offset + exar_gpio->first_pin) % 8;
6596e59e6   Sudip Mukherjee   gpio: exar: add g...
56

380b1e2f3   Jan Kiszka   gpio-exar/8250-ex...
57
  	exar_update(chip, addr, direction, bit);
6596e59e6   Sudip Mukherjee   gpio: exar: add g...
58
59
  	return 0;
  }
6596e59e6   Sudip Mukherjee   gpio: exar: add g...
60
61
62
63
64
65
66
67
  static int exar_get(struct gpio_chip *chip, unsigned int reg)
  {
  	struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
  	int value;
  
  	mutex_lock(&exar_gpio->lock);
  	value = readb(exar_gpio->regs + reg);
  	mutex_unlock(&exar_gpio->lock);
7f45a875d   Jan Kiszka   gpio: exar: Fix r...
68
  	return value;
6596e59e6   Sudip Mukherjee   gpio: exar: add g...
69
70
71
72
  }
  
  static int exar_get_direction(struct gpio_chip *chip, unsigned int offset)
  {
380b1e2f3   Jan Kiszka   gpio-exar/8250-ex...
73
74
75
76
  	struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
  	unsigned int addr = (offset + exar_gpio->first_pin) / 8 ?
  		EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;
  	unsigned int bit  = (offset + exar_gpio->first_pin) % 8;
6596e59e6   Sudip Mukherjee   gpio: exar: add g...
77

e42615ec2   Matti Vaittinen   gpio: Use new GPI...
78
79
80
81
  	if (exar_get(chip, addr) & BIT(bit))
  		return GPIO_LINE_DIRECTION_IN;
  
  	return GPIO_LINE_DIRECTION_OUT;
6596e59e6   Sudip Mukherjee   gpio: exar: add g...
82
83
84
85
  }
  
  static int exar_get_value(struct gpio_chip *chip, unsigned int offset)
  {
380b1e2f3   Jan Kiszka   gpio-exar/8250-ex...
86
87
88
89
  	struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
  	unsigned int addr = (offset + exar_gpio->first_pin) / 8 ?
  		EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO;
  	unsigned int bit  = (offset + exar_gpio->first_pin) % 8;
6596e59e6   Sudip Mukherjee   gpio: exar: add g...
90

380b1e2f3   Jan Kiszka   gpio-exar/8250-ex...
91
  	return !!(exar_get(chip, addr) & BIT(bit));
6596e59e6   Sudip Mukherjee   gpio: exar: add g...
92
93
94
95
96
  }
  
  static void exar_set_value(struct gpio_chip *chip, unsigned int offset,
  			   int value)
  {
380b1e2f3   Jan Kiszka   gpio-exar/8250-ex...
97
98
99
100
  	struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
  	unsigned int addr = (offset + exar_gpio->first_pin) / 8 ?
  		EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO;
  	unsigned int bit  = (offset + exar_gpio->first_pin) % 8;
6596e59e6   Sudip Mukherjee   gpio: exar: add g...
101

380b1e2f3   Jan Kiszka   gpio-exar/8250-ex...
102
  	exar_update(chip, addr, value, bit);
6596e59e6   Sudip Mukherjee   gpio: exar: add g...
103
  }
eddeae073   Axel Lin   gpio: exar: Set p...
104
105
106
107
108
109
110
111
112
113
114
  static int exar_direction_output(struct gpio_chip *chip, unsigned int offset,
  				 int value)
  {
  	exar_set_value(chip, offset, value);
  	return exar_set_direction(chip, 0, offset);
  }
  
  static int exar_direction_input(struct gpio_chip *chip, unsigned int offset)
  {
  	return exar_set_direction(chip, 1, offset);
  }
6596e59e6   Sudip Mukherjee   gpio: exar: add g...
115
116
  static int gpio_exar_probe(struct platform_device *pdev)
  {
d3936d743   Jan Kiszka   gpio-exar/8250-ex...
117
  	struct pci_dev *pcidev = to_pci_dev(pdev->dev.parent);
6596e59e6   Sudip Mukherjee   gpio: exar: add g...
118
  	struct exar_gpio_chip *exar_gpio;
380b1e2f3   Jan Kiszka   gpio-exar/8250-ex...
119
  	u32 first_pin, ngpios;
6596e59e6   Sudip Mukherjee   gpio: exar: add g...
120
121
  	void __iomem *p;
  	int index, ret;
6596e59e6   Sudip Mukherjee   gpio: exar: add g...
122
  	/*
8847f5f9e   Jan Kiszka   gpio: exar: Fix i...
123
124
  	 * The UART driver must have mapped region 0 prior to registering this
  	 * device - use it.
6596e59e6   Sudip Mukherjee   gpio: exar: add g...
125
  	 */
8847f5f9e   Jan Kiszka   gpio: exar: Fix i...
126
  	p = pcim_iomap_table(pcidev)[0];
6596e59e6   Sudip Mukherjee   gpio: exar: add g...
127
128
  	if (!p)
  		return -ENOMEM;
a589e211b   Jan Kiszka   gpio: exar: Use c...
129
  	ret = device_property_read_u32(&pdev->dev, "exar,first-pin",
380b1e2f3   Jan Kiszka   gpio-exar/8250-ex...
130
131
132
133
134
135
136
  				       &first_pin);
  	if (ret)
  		return ret;
  
  	ret = device_property_read_u32(&pdev->dev, "ngpios", &ngpios);
  	if (ret)
  		return ret;
5dab5872e   Jan Kiszka   gpio: exar: Alloc...
137
  	exar_gpio = devm_kzalloc(&pdev->dev, sizeof(*exar_gpio), GFP_KERNEL);
6596e59e6   Sudip Mukherjee   gpio: exar: add g...
138
139
140
141
142
143
  	if (!exar_gpio)
  		return -ENOMEM;
  
  	mutex_init(&exar_gpio->lock);
  
  	index = ida_simple_get(&ida_index, 0, 0, GFP_KERNEL);
333830aa1   Takashi Iwai   gpio: exar: Fix b...
144
145
146
147
  	if (index < 0) {
  		ret = index;
  		goto err_mutex_destroy;
  	}
6596e59e6   Sudip Mukherjee   gpio: exar: add g...
148
149
150
  
  	sprintf(exar_gpio->name, "exar_gpio%d", index);
  	exar_gpio->gpio_chip.label = exar_gpio->name;
4076cf08a   Jan Kiszka   gpio-exar/8250-ex...
151
  	exar_gpio->gpio_chip.parent = &pdev->dev;
6596e59e6   Sudip Mukherjee   gpio: exar: add g...
152
153
154
155
156
157
  	exar_gpio->gpio_chip.direction_output = exar_direction_output;
  	exar_gpio->gpio_chip.direction_input = exar_direction_input;
  	exar_gpio->gpio_chip.get_direction = exar_get_direction;
  	exar_gpio->gpio_chip.get = exar_get_value;
  	exar_gpio->gpio_chip.set = exar_set_value;
  	exar_gpio->gpio_chip.base = -1;
380b1e2f3   Jan Kiszka   gpio-exar/8250-ex...
158
  	exar_gpio->gpio_chip.ngpio = ngpios;
6596e59e6   Sudip Mukherjee   gpio: exar: add g...
159
160
  	exar_gpio->regs = p;
  	exar_gpio->index = index;
380b1e2f3   Jan Kiszka   gpio-exar/8250-ex...
161
  	exar_gpio->first_pin = first_pin;
6596e59e6   Sudip Mukherjee   gpio: exar: add g...
162

5dab5872e   Jan Kiszka   gpio: exar: Alloc...
163
  	ret = devm_gpiochip_add_data(&pdev->dev,
6596e59e6   Sudip Mukherjee   gpio: exar: add g...
164
165
166
167
168
169
170
171
172
173
  				     &exar_gpio->gpio_chip, exar_gpio);
  	if (ret)
  		goto err_destroy;
  
  	platform_set_drvdata(pdev, exar_gpio);
  
  	return 0;
  
  err_destroy:
  	ida_simple_remove(&ida_index, index);
333830aa1   Takashi Iwai   gpio: exar: Fix b...
174
  err_mutex_destroy:
6596e59e6   Sudip Mukherjee   gpio: exar: add g...
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
  	mutex_destroy(&exar_gpio->lock);
  	return ret;
  }
  
  static int gpio_exar_remove(struct platform_device *pdev)
  {
  	struct exar_gpio_chip *exar_gpio = platform_get_drvdata(pdev);
  
  	ida_simple_remove(&ida_index, exar_gpio->index);
  	mutex_destroy(&exar_gpio->lock);
  
  	return 0;
  }
  
  static struct platform_driver gpio_exar_driver = {
  	.probe	= gpio_exar_probe,
  	.remove	= gpio_exar_remove,
  	.driver	= {
  		.name = DRIVER_NAME,
  	},
  };
  
  module_platform_driver(gpio_exar_driver);
  
  MODULE_ALIAS("platform:" DRIVER_NAME);
  MODULE_DESCRIPTION("Exar GPIO driver");
  MODULE_AUTHOR("Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>");
  MODULE_LICENSE("GPL");