Linux Audio

Check our new training course

Embedded Linux training

Mar 10-20, 2025, special US time zones
Register
Loading...
v3.1
  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
 26#include <linux/init.h>
 27#include <linux/kernel.h>
 28#include <linux/module.h>
 29#include <linux/errno.h>
 30#include <linux/acpi.h>
 31#include <linux/pci.h>
 32#include <linux/mfd/core.h>
 33
 34#define SMBASE		0x40
 35#define SMBUS_IO_SIZE	64
 36
 37#define GPIOBASE	0x44
 38#define GPIO_IO_SIZE	64
 
 39
 40#define WDTBASE		0x84
 41#define WDT_IO_SIZE	64
 42
 43static struct resource smbus_sch_resource = {
 44		.flags = IORESOURCE_IO,
 45};
 46
 47
 48static struct resource gpio_sch_resource = {
 49		.flags = IORESOURCE_IO,
 50};
 51
 52static struct mfd_cell lpc_sch_cells[] = {
 53	{
 54		.name = "isch_smbus",
 55		.num_resources = 1,
 56		.resources = &smbus_sch_resource,
 57	},
 58	{
 59		.name = "sch_gpio",
 60		.num_resources = 1,
 61		.resources = &gpio_sch_resource,
 62	},
 63};
 64
 65static struct resource wdt_sch_resource = {
 66		.flags = IORESOURCE_IO,
 67};
 68
 69static struct mfd_cell tunnelcreek_cells[] = {
 70	{
 71		.name = "tunnelcreek_wdt",
 72		.num_resources = 1,
 73		.resources = &wdt_sch_resource,
 74	},
 75};
 76
 77static struct pci_device_id lpc_sch_ids[] = {
 78	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) },
 79	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ITC_LPC) },
 
 80	{ 0, }
 81};
 82MODULE_DEVICE_TABLE(pci, lpc_sch_ids);
 83
 84static int __devinit lpc_sch_probe(struct pci_dev *dev,
 85				const struct pci_device_id *id)
 86{
 87	unsigned int base_addr_cfg;
 88	unsigned short base_addr;
 89	int i;
 90	int ret;
 91
 92	pci_read_config_dword(dev, SMBASE, &base_addr_cfg);
 93	if (!(base_addr_cfg & (1 << 31))) {
 94		dev_err(&dev->dev, "Decode of the SMBus I/O range disabled\n");
 95		return -ENODEV;
 96	}
 97	base_addr = (unsigned short)base_addr_cfg;
 98	if (base_addr == 0) {
 99		dev_err(&dev->dev, "I/O space for SMBus uninitialized\n");
100		return -ENODEV;
101	}
102
103	smbus_sch_resource.start = base_addr;
104	smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1;
105
106	pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg);
107	if (!(base_addr_cfg & (1 << 31))) {
108		dev_err(&dev->dev, "Decode of the GPIO I/O range disabled\n");
109		return -ENODEV;
110	}
111	base_addr = (unsigned short)base_addr_cfg;
112	if (base_addr == 0) {
113		dev_err(&dev->dev, "I/O space for GPIO uninitialized\n");
114		return -ENODEV;
115	}
116
117	gpio_sch_resource.start = base_addr;
118	gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1;
 
 
 
 
119
120	for (i=0; i < ARRAY_SIZE(lpc_sch_cells); i++)
121		lpc_sch_cells[i].id = id->device;
122
123	ret = mfd_add_devices(&dev->dev, 0,
124			lpc_sch_cells, ARRAY_SIZE(lpc_sch_cells), NULL, 0);
125	if (ret)
126		goto out_dev;
127
128	if (id->device == PCI_DEVICE_ID_INTEL_ITC_LPC) {
 
129		pci_read_config_dword(dev, WDTBASE, &base_addr_cfg);
130		if (!(base_addr_cfg & (1 << 31))) {
131			dev_err(&dev->dev, "Decode of the WDT I/O range disabled\n");
132			ret = -ENODEV;
133			goto out_dev;
134		}
135		base_addr = (unsigned short)base_addr_cfg;
136		if (base_addr == 0) {
137			dev_err(&dev->dev, "I/O space for WDT uninitialized\n");
138			ret = -ENODEV;
139			goto out_dev;
140		}
141
142		wdt_sch_resource.start = base_addr;
143		wdt_sch_resource.end = base_addr + WDT_IO_SIZE - 1;
144
145		for (i = 0; i < ARRAY_SIZE(tunnelcreek_cells); i++)
146			tunnelcreek_cells[i].id = id->device;
147
148		ret = mfd_add_devices(&dev->dev, 0, tunnelcreek_cells,
149			ARRAY_SIZE(tunnelcreek_cells), NULL, 0);
150	}
151
152	return ret;
153out_dev:
154	mfd_remove_devices(&dev->dev);
155	return ret;
156}
157
158static void __devexit lpc_sch_remove(struct pci_dev *dev)
159{
160	mfd_remove_devices(&dev->dev);
161}
162
163static struct pci_driver lpc_sch_driver = {
164	.name		= "lpc_sch",
165	.id_table	= lpc_sch_ids,
166	.probe		= lpc_sch_probe,
167	.remove		= __devexit_p(lpc_sch_remove),
168};
169
170static int __init lpc_sch_init(void)
171{
172	return pci_register_driver(&lpc_sch_driver);
173}
174
175static void __exit lpc_sch_exit(void)
176{
177	pci_unregister_driver(&lpc_sch_driver);
178}
179
180module_init(lpc_sch_init);
181module_exit(lpc_sch_exit);
182
183MODULE_AUTHOR("Denis Turischev <denis@compulab.co.il>");
184MODULE_DESCRIPTION("LPC interface for Intel Poulsbo SCH");
185MODULE_LICENSE("GPL");
v3.5.6
  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
 26#include <linux/init.h>
 27#include <linux/kernel.h>
 28#include <linux/module.h>
 29#include <linux/errno.h>
 30#include <linux/acpi.h>
 31#include <linux/pci.h>
 32#include <linux/mfd/core.h>
 33
 34#define SMBASE		0x40
 35#define SMBUS_IO_SIZE	64
 36
 37#define GPIOBASE	0x44
 38#define GPIO_IO_SIZE	64
 39#define GPIO_IO_SIZE_CENTERTON	128
 40
 41#define WDTBASE		0x84
 42#define WDT_IO_SIZE	64
 43
 44static struct resource smbus_sch_resource = {
 45		.flags = IORESOURCE_IO,
 46};
 47
 48
 49static struct resource gpio_sch_resource = {
 50		.flags = IORESOURCE_IO,
 51};
 52
 53static struct mfd_cell lpc_sch_cells[] = {
 54	{
 55		.name = "isch_smbus",
 56		.num_resources = 1,
 57		.resources = &smbus_sch_resource,
 58	},
 59	{
 60		.name = "sch_gpio",
 61		.num_resources = 1,
 62		.resources = &gpio_sch_resource,
 63	},
 64};
 65
 66static struct resource wdt_sch_resource = {
 67		.flags = IORESOURCE_IO,
 68};
 69
 70static struct mfd_cell tunnelcreek_cells[] = {
 71	{
 72		.name = "ie6xx_wdt",
 73		.num_resources = 1,
 74		.resources = &wdt_sch_resource,
 75	},
 76};
 77
 78static DEFINE_PCI_DEVICE_TABLE(lpc_sch_ids) = {
 79	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) },
 80	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ITC_LPC) },
 81	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CENTERTON_ILB) },
 82	{ 0, }
 83};
 84MODULE_DEVICE_TABLE(pci, lpc_sch_ids);
 85
 86static int __devinit lpc_sch_probe(struct pci_dev *dev,
 87				const struct pci_device_id *id)
 88{
 89	unsigned int base_addr_cfg;
 90	unsigned short base_addr;
 91	int i;
 92	int ret;
 93
 94	pci_read_config_dword(dev, SMBASE, &base_addr_cfg);
 95	if (!(base_addr_cfg & (1 << 31))) {
 96		dev_err(&dev->dev, "Decode of the SMBus I/O range disabled\n");
 97		return -ENODEV;
 98	}
 99	base_addr = (unsigned short)base_addr_cfg;
100	if (base_addr == 0) {
101		dev_err(&dev->dev, "I/O space for SMBus uninitialized\n");
102		return -ENODEV;
103	}
104
105	smbus_sch_resource.start = base_addr;
106	smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1;
107
108	pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg);
109	if (!(base_addr_cfg & (1 << 31))) {
110		dev_err(&dev->dev, "Decode of the GPIO I/O range disabled\n");
111		return -ENODEV;
112	}
113	base_addr = (unsigned short)base_addr_cfg;
114	if (base_addr == 0) {
115		dev_err(&dev->dev, "I/O space for GPIO uninitialized\n");
116		return -ENODEV;
117	}
118
119	gpio_sch_resource.start = base_addr;
120
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
126	for (i=0; i < ARRAY_SIZE(lpc_sch_cells); i++)
127		lpc_sch_cells[i].id = id->device;
128
129	ret = mfd_add_devices(&dev->dev, 0,
130			lpc_sch_cells, ARRAY_SIZE(lpc_sch_cells), NULL, 0);
131	if (ret)
132		goto out_dev;
133
134	if (id->device == PCI_DEVICE_ID_INTEL_ITC_LPC
135	 || id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) {
136		pci_read_config_dword(dev, WDTBASE, &base_addr_cfg);
137		if (!(base_addr_cfg & (1 << 31))) {
138			dev_err(&dev->dev, "Decode of the WDT I/O range disabled\n");
139			ret = -ENODEV;
140			goto out_dev;
141		}
142		base_addr = (unsigned short)base_addr_cfg;
143		if (base_addr == 0) {
144			dev_err(&dev->dev, "I/O space for WDT uninitialized\n");
145			ret = -ENODEV;
146			goto out_dev;
147		}
148
149		wdt_sch_resource.start = base_addr;
150		wdt_sch_resource.end = base_addr + WDT_IO_SIZE - 1;
151
152		for (i = 0; i < ARRAY_SIZE(tunnelcreek_cells); i++)
153			tunnelcreek_cells[i].id = id->device;
154
155		ret = mfd_add_devices(&dev->dev, 0, tunnelcreek_cells,
156			ARRAY_SIZE(tunnelcreek_cells), NULL, 0);
157	}
158
159	return ret;
160out_dev:
161	mfd_remove_devices(&dev->dev);
162	return ret;
163}
164
165static void __devexit lpc_sch_remove(struct pci_dev *dev)
166{
167	mfd_remove_devices(&dev->dev);
168}
169
170static struct pci_driver lpc_sch_driver = {
171	.name		= "lpc_sch",
172	.id_table	= lpc_sch_ids,
173	.probe		= lpc_sch_probe,
174	.remove		= __devexit_p(lpc_sch_remove),
175};
176
177module_pci_driver(lpc_sch_driver);
 
 
 
 
 
 
 
 
 
 
 
178
179MODULE_AUTHOR("Denis Turischev <denis@compulab.co.il>");
180MODULE_DESCRIPTION("LPC interface for Intel Poulsbo SCH");
181MODULE_LICENSE("GPL");