Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
[deliverable/linux.git] / drivers / mfd / lpc_sch.c
CommitLineData
e82c60ae
DT
1/*
2 * lpc_sch.c - LPC interface for Intel Poulsbo SCH
3 *
4 * LPC bridge function of the Intel SCH contains many other
5 * functional units, such as Interrupt controllers, Timers,
6 * Power Management, System Management, GPIO, RTC, and LPC
7 * Configuration Registers.
8 *
9 * Copyright (c) 2010 CompuLab Ltd
10 * Author: Denis Turischev <denis@compulab.co.il>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License 2 as published
14 * by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; see the file COPYING. If not, write to
23 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
e82c60ae
DT
26#include <linux/kernel.h>
27#include <linux/module.h>
28#include <linux/errno.h>
29#include <linux/acpi.h>
30#include <linux/pci.h>
31#include <linux/mfd/core.h>
32
33#define SMBASE 0x40
34#define SMBUS_IO_SIZE 64
35
36#define GPIOBASE 0x44
37#define GPIO_IO_SIZE 64
8ee3c2a7 38#define GPIO_IO_SIZE_CENTERTON 128
e82c60ae 39
19921ef6
AS
40#define WDTBASE 0x84
41#define WDT_IO_SIZE 64
42
e82c60ae
DT
43static struct resource smbus_sch_resource = {
44 .flags = IORESOURCE_IO,
45};
46
e82c60ae
DT
47static struct resource gpio_sch_resource = {
48 .flags = IORESOURCE_IO,
49};
50
19921ef6
AS
51static struct resource wdt_sch_resource = {
52 .flags = IORESOURCE_IO,
53};
54
5829e9b6
DH
55static struct mfd_cell lpc_sch_cells[3];
56
57static struct mfd_cell isch_smbus_cell = {
58 .name = "isch_smbus",
59 .num_resources = 1,
60 .resources = &smbus_sch_resource,
6bfd1e63 61 .ignore_resource_conflicts = true,
5829e9b6
DH
62};
63
64static struct mfd_cell sch_gpio_cell = {
65 .name = "sch_gpio",
66 .num_resources = 1,
67 .resources = &gpio_sch_resource,
6bfd1e63 68 .ignore_resource_conflicts = true,
5829e9b6
DH
69};
70
71static struct mfd_cell wdt_sch_cell = {
72 .name = "ie6xx_wdt",
73 .num_resources = 1,
74 .resources = &wdt_sch_resource,
6bfd1e63 75 .ignore_resource_conflicts = true,
19921ef6
AS
76};
77
36fcd06c 78static const struct pci_device_id lpc_sch_ids[] = {
e82c60ae 79 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) },
e967f77d 80 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ITC_LPC) },
8ee3c2a7 81 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CENTERTON_ILB) },
e82c60ae
DT
82 { 0, }
83};
84MODULE_DEVICE_TABLE(pci, lpc_sch_ids);
85
f791be49 86static int lpc_sch_probe(struct pci_dev *dev,
e82c60ae
DT
87 const struct pci_device_id *id)
88{
89 unsigned int base_addr_cfg;
90 unsigned short base_addr;
5829e9b6 91 int i, cells = 0;
19921ef6 92 int ret;
e82c60ae
DT
93
94 pci_read_config_dword(dev, SMBASE, &base_addr_cfg);
5829e9b6
DH
95 base_addr = 0;
96 if (!(base_addr_cfg & (1 << 31)))
97 dev_warn(&dev->dev, "Decode of the SMBus I/O range disabled\n");
98 else
99 base_addr = (unsigned short)base_addr_cfg;
e82c60ae 100
e82c60ae 101 if (base_addr == 0) {
5829e9b6
DH
102 dev_warn(&dev->dev, "I/O space for SMBus uninitialized\n");
103 } else {
104 lpc_sch_cells[cells++] = isch_smbus_cell;
105 smbus_sch_resource.start = base_addr;
106 smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1;
e82c60ae
DT
107 }
108
5829e9b6
DH
109 pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg);
110 base_addr = 0;
111 if (!(base_addr_cfg & (1 << 31)))
112 dev_warn(&dev->dev, "Decode of the GPIO I/O range disabled\n");
8ee3c2a7 113 else
5829e9b6 114 base_addr = (unsigned short)base_addr_cfg;
e967f77d 115
5829e9b6
DH
116 if (base_addr == 0) {
117 dev_warn(&dev->dev, "I/O space for GPIO uninitialized\n");
118 } else {
119 lpc_sch_cells[cells++] = sch_gpio_cell;
120 gpio_sch_resource.start = base_addr;
121 if (id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB)
122 gpio_sch_resource.end = base_addr + GPIO_IO_SIZE_CENTERTON - 1;
123 else
124 gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1;
125 }
19921ef6 126
8ee3c2a7 127 if (id->device == PCI_DEVICE_ID_INTEL_ITC_LPC
5829e9b6 128 || id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) {
19921ef6 129 pci_read_config_dword(dev, WDTBASE, &base_addr_cfg);
5829e9b6
DH
130 base_addr = 0;
131 if (!(base_addr_cfg & (1 << 31)))
132 dev_warn(&dev->dev, "Decode of the WDT I/O range disabled\n");
133 else
134 base_addr = (unsigned short)base_addr_cfg;
135 if (base_addr == 0)
136 dev_warn(&dev->dev, "I/O space for WDT uninitialized\n");
137 else {
138 lpc_sch_cells[cells++] = wdt_sch_cell;
139 wdt_sch_resource.start = base_addr;
140 wdt_sch_resource.end = base_addr + WDT_IO_SIZE - 1;
19921ef6 141 }
5829e9b6 142 }
19921ef6 143
5829e9b6
DH
144 if (WARN_ON(cells > ARRAY_SIZE(lpc_sch_cells))) {
145 dev_err(&dev->dev, "Cell count exceeds array size");
146 return -ENODEV;
147 }
19921ef6 148
5829e9b6
DH
149 if (cells == 0) {
150 dev_err(&dev->dev, "All decode registers disabled.\n");
151 return -ENODEV;
19921ef6
AS
152 }
153
5829e9b6
DH
154 for (i = 0; i < cells; i++)
155 lpc_sch_cells[i].id = id->device;
156
157 ret = mfd_add_devices(&dev->dev, 0, lpc_sch_cells, cells, NULL, 0, NULL);
158 if (ret)
159 mfd_remove_devices(&dev->dev);
160
19921ef6 161 return ret;
e82c60ae
DT
162}
163
4740f73f 164static void lpc_sch_remove(struct pci_dev *dev)
e82c60ae
DT
165{
166 mfd_remove_devices(&dev->dev);
167}
168
169static struct pci_driver lpc_sch_driver = {
170 .name = "lpc_sch",
171 .id_table = lpc_sch_ids,
172 .probe = lpc_sch_probe,
84449216 173 .remove = lpc_sch_remove,
e82c60ae
DT
174};
175
38a36f5a 176module_pci_driver(lpc_sch_driver);
e82c60ae
DT
177
178MODULE_AUTHOR("Denis Turischev <denis@compulab.co.il>");
179MODULE_DESCRIPTION("LPC interface for Intel Poulsbo SCH");
180MODULE_LICENSE("GPL");
This page took 0.317063 seconds and 5 git commands to generate.