Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(364)

Side by Side Diff: drivers/gpio/nm10_gpio.c

Issue 2231003: NM10 gpio driver implementation (Closed) Base URL: ssh://git@chromiumos-git/kernel.git
Patch Set: Minor changes to address review comments. Created 10 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « drivers/gpio/Makefile ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2010, The Chromium OS Authors
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 *
17 * This driver supports GPIO controller of the NM10 chip.
18 *
19 * The NM10 has many GPIO pins, the exact number depends on the configuration,
20 * as some of the pins can be used for other than GPIO purposes. The GPIO
21 * controller has provision of managing of up to 64 bits. Each bit can be
22 * configured as 'not available', (when for other than GPIO purposes), or a
23 * GPIO input/output.
24 *
25 * Even though NM10 provides the ability to change GPIO bits' directions, this
26 * driver does NOT allow to change the use of the bits. Whatever the system is
27 * strapped and/or configured by BIOS for is used by the driver.
28 *
29 * This driver plugs in into the existing linux gpio infrastructure and allows
30 * to instantiate all 64 bits (through writing into /sys/class/gpio/export)
31 * even though not all bits can be used. This simplifies bit mapping between
32 * hardware and software.
33 *
34 * Attempts to write into unsupported bits are silently ignored. Attempts to
35 * read unsupported bits return value of zero.
36 *
37 * For the lower 32 GPIO bits the NM10 provides the ability to 'blink'
38 * (alternate 1 and zero with 1Hz frequency at approximately 50% duty cycle)
39 * on output and invert level on input. This driver does not provide access
40 * these features.
41 *
42 * The NM10 GPIO controller is a part of the LPC PCI device, (PCI device ID
43 * 0x27bc). The GPIO register file is mapped to the IO space. An earlier Intel
44 * chip, the ICH7M south bridge, has a similar GPIO controller, it could be
45 * also supported by this driver.
46 *
47 * "Intel NM10 Family Express Chipset" datasheet of Dec 2009 (document number
48 * 322896-001) was used as a reference when writing this driver.
49 *
50 */
51
52 #include <linux/module.h>
53 #include <linux/pci.h>
54 #include <linux/gpio.h>
55
56 static char gpio_driver_name[] = "nm10_gpio";
57 static char gpio_driver_version[] = "0.04";
58
59 /* NM10 GPIO register file definitions, offsets in the IO space */
60 #define NM10_GPIO_USE_SEL 0
61 #define NM10_GPIO_IO_SEL 4
62 #define NM10_GPIO_LVL 0xc
63 #define NM10_GPIO_USE_SEL2 0x30
64 #define NM10_GPIO_IO_SEL2 0x34
65 #define NM10_GPIO_LVL2 0x38
66 #define NM10_GPIO_REG_FILE_SIZE 0x40
67
68 /* Structure describing one GPIO section in the nm10, accessing 32 GPIO bits. */
69 struct nm10_gpio_info {
70 u_char use_select_offset;
71 u_char io_select_offset;
72 u_char io_level_offset;
73 };
74
75 /* This array describes two NM10 GPIO sections */
76 const struct nm10_gpio_info nm10_gpio_sections[] = {
77 {NM10_GPIO_USE_SEL, NM10_GPIO_IO_SEL, NM10_GPIO_LVL},
78 {NM10_GPIO_USE_SEL2, NM10_GPIO_IO_SEL2, NM10_GPIO_LVL2},
79 };
80
81 #define NM10_GPIO_BITS_PER_SECTION 32
82 #define NM10_GPIO_SECTIONS ARRAY_SIZE(nm10_gpio_sections)
83 #define NM10_MAX_GPIO_BITS (NM10_GPIO_SECTIONS * NM10_GPIO_BITS_PER_SECTION)
84
85 /*
86 * Structure representing a single NM10 GPIO driver instance.
87 */
88 struct nm10_gpio {
89 struct gpio_chip chip;
90 u32 io_base; /* base IO space address of the GPIO register file */
91
92 /* cached contents of the GPIO bit selections, read during driver
93 * installation */
94 u32 cached_select[NM10_GPIO_SECTIONS];
95 };
96
97 /**
98 * nm10_gpio_get() - get value of a GPIO bit
99 * @chip: generic gpio chip handle associated with this module
100 * @offset: zero based GPIO bit number (in this controller's scope).
101 *
102 * Returns zero in cases when offset exceeds the chip's GPIO capacity, or the
103 * passed in bit not used for GPIO. If the offset is of a valid bit - returns
104 * a bitmask with the bit value matching the actual bit input state.
105 */
106 static int nm10_gpio_get(struct gpio_chip *chip, unsigned offset)
107 {
108 u8 section;
109 u32 bit;
110 struct nm10_gpio *pgpio = container_of(chip, struct nm10_gpio, chip);
111
112 section = offset / NM10_GPIO_BITS_PER_SECTION;
113 bit = BIT(offset % NM10_GPIO_BITS_PER_SECTION);
114
115 if (section >= NM10_GPIO_SECTIONS) {
116 printk(KERN_ERR "%s: bad offset %d\n",
117 gpio_driver_name, offset);
118 return 0;
119 }
120
121 if (!(bit & pgpio->cached_select[section])) {
122 return 0; /* this bit is not used for GPIO */
123 }
124 return inl(pgpio->io_base +
125 nm10_gpio_sections[section].io_level_offset) & bit;
126 }
127
128 /**
129 * nm10_gpio_set() - get value of a GPIO bit
130 * @chip: generic gpio chip handle associated with this module
131 * @offset: zero based GPIO bit number (in this controller's scope).
132 *
133 * If the offset is of a valid bit (used for GPIO output) - the bit state is
134 * changed to reflect the value. All other in range offset values are ignored.
135 */
136 static void nm10_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
137 {
138 u8 section;
139 u32 bit;
140 const struct nm10_gpio_info *pinfo;
141 struct nm10_gpio *pgpio = container_of(chip, struct nm10_gpio, chip);
142 u32 gpio_reg_value;
143
144 section = offset / NM10_GPIO_BITS_PER_SECTION;
145 bit = BIT(offset % NM10_GPIO_BITS_PER_SECTION);
146
147 if (section >= NM10_GPIO_SECTIONS) {
148 printk(KERN_ERR "%s: bad offset %d\n",
149 gpio_driver_name, offset);
150 }
151
152 if (!(bit & pgpio->cached_select[section])) {
153 return; /* this bit is not used for GPIO */
154 }
155
156 pinfo = nm10_gpio_sections + section;
157 if (inl(pgpio->io_base + pinfo->io_select_offset) & bit) {
158 return; /* this is an input bit */
159 }
160
161 gpio_reg_value = inl(pgpio->io_base + pinfo->io_level_offset);
162
163 if (value) {
164 gpio_reg_value |= bit;
165 } else {
166 gpio_reg_value &= ~bit;
167 }
168 outl(gpio_reg_value, pgpio->io_base + pinfo->io_level_offset);
169 }
170
171 static int __devinit nm10_gpio_probe(struct pci_dev *pdev,
172 const struct pci_device_id *id)
173 {
174 int retval, ii;
175 u32 value;
176 struct nm10_gpio *pgpio;
177
178 retval = pci_enable_device(pdev);
179 printk(KERN_INFO "%s version %s built on %s at %s\n", gpio_driver_name,
180 gpio_driver_version, __DATE__, __TIME__);
181
182 if (retval) {
183 goto done;
184 }
185
186 /* actual IO space offset of the GPIO block */
187 retval = pci_read_config_dword(pdev, 0x48, &value);
188 if (retval || !(value & 1)) {
189 dev_err(&pdev->dev,
190 "failed retrieving IO base addr, got %d(0x%x)\n",
191 retval, value);
192 goto err2;
193 }
194
195 value &= ~1; /* clear the IO space flag */
196 if (!request_region(value, NM10_GPIO_REG_FILE_SIZE, gpio_driver_name)) {
197 dev_err(&pdev->dev, "error requesting REGION\n");
198 retval = -ENOMEM;
199 goto err2;
200 }
201
202 pgpio = kzalloc(sizeof(struct nm10_gpio), GFP_KERNEL);
203 if (!pgpio) {
204 dev_err(&pdev->dev, "can't allocate nm10_gpio structure\n");
205 retval = -ENOMEM;
206 goto err3;
207 }
208
209 /* used to access GPIO bits on this chip */
210 pgpio->io_base = value;
211
212 pgpio->chip.base = -1;
213 pgpio->chip.label = dev_name(&pdev->dev);
214 pgpio->chip.get = nm10_gpio_get;
215 pgpio->chip.set = nm10_gpio_set;
216 pgpio->chip.ngpio = NM10_MAX_GPIO_BITS;
217 pgpio->chip.can_sleep = 0;
218 pci_set_drvdata(pdev, pgpio);
219
220 /* store GPIO configuration locally */
221 for (ii = 0; ii < ARRAY_SIZE(pgpio->cached_select); ii++) {
222 pgpio->cached_select[ii] = inl(pgpio->io_base +
223 nm10_gpio_sections[ii].
224 use_select_offset);
225 }
226
227 retval = gpiochip_add(&pgpio->chip);
228 if (!retval) {
229 goto done;
230 }
231
232 dev_err(&pdev->dev, "%s gpiochip_add error %d\n",
233 gpio_driver_name, retval);
234
235 kfree(pgpio);
236 err3:
237 release_region(value, NM10_GPIO_REG_FILE_SIZE);
238 err2:
239 pci_disable_device(pdev);
240 done:
241 if (retval) {
242 printk(KERN_ERR "%s failed!\n", gpio_driver_name);
243
244 }
245 return retval;
246 }
247
248 /**
249 * nm10_gpio_remove() - remove the NM10 gpio driver module.
250 * @pdev: pci device associated with this driver module
251 *
252 */
253 static void nm10_gpio_remove(struct pci_dev *pdev)
254 {
255 struct nm10_gpio *pgpio = pci_get_drvdata(pdev);
256 int base = pgpio->chip.base;
257
258 if (gpiochip_remove(&pgpio->chip)) {
259 printk(KERN_ERR "%s: failed removing!\n", gpio_driver_name);
260 return;
261 }
262
263 release_region(pgpio->io_base, NM10_GPIO_REG_FILE_SIZE);
264 pci_disable_device(pdev);
265 pci_set_drvdata(pdev, NULL);
266 kfree(pgpio);
267 printk(KERN_INFO "%s base %d removed\n", gpio_driver_name, base);
268 }
269
270 static struct pci_device_id nm10_gpio_ids[] = {
271 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TGP_LPC)},
272 {0,}
273 };
274
275 MODULE_DEVICE_TABLE(pci, nm10_gpio_ids);
276
277 static struct pci_driver nm10_gpio_pci_driver = {
278 .name = gpio_driver_name,
279 .id_table = nm10_gpio_ids,
280 .probe = nm10_gpio_probe,
281 .remove = nm10_gpio_remove
282 };
283
284 static int __init nm10_gpio_init(void)
285 {
286 return pci_register_driver(&nm10_gpio_pci_driver);
287 }
288
289 static void __exit nm10_gpio_exit(void)
290 {
291 pci_unregister_driver(&nm10_gpio_pci_driver);
292 }
293
294 module_init(nm10_gpio_init);
295 module_exit(nm10_gpio_exit);
296
297 MODULE_LICENSE("GPL");
298 MODULE_AUTHOR("The Chromium OS Authors");
299 MODULE_DESCRIPTION("NM10 GPIO driver");
OLDNEW
« no previous file with comments | « drivers/gpio/Makefile ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698