Blame view
drivers/mfd/lpc_sch.c
4.78 KB
9f8068503 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
e82c60ae7 mfd: Introduce lp... |
2 3 4 5 6 7 8 9 10 |
/* * lpc_sch.c - LPC interface for Intel Poulsbo SCH * * LPC bridge function of the Intel SCH contains many other * functional units, such as Interrupt controllers, Timers, * Power Management, System Management, GPIO, RTC, and LPC * Configuration Registers. * * Copyright (c) 2010 CompuLab Ltd |
85de80e8d mfd: lpc_sch: Rem... |
11 |
* Copyright (c) 2014 Intel Corp. |
e82c60ae7 mfd: Introduce lp... |
12 |
* Author: Denis Turischev <denis@compulab.co.il> |
e82c60ae7 mfd: Introduce lp... |
13 |
*/ |
e82c60ae7 mfd: Introduce lp... |
14 15 16 17 18 19 20 21 22 23 24 25 |
#include <linux/kernel.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/acpi.h> #include <linux/pci.h> #include <linux/mfd/core.h> #define SMBASE 0x40 #define SMBUS_IO_SIZE 64 #define GPIOBASE 0x44 #define GPIO_IO_SIZE 64 |
8ee3c2a79 lpc_sch: Add Inte... |
26 |
#define GPIO_IO_SIZE_CENTERTON 128 |
e82c60ae7 mfd: Introduce lp... |
27 |
|
ec689a8a8 mfd: lpc_sch: Add... |
28 29 |
/* Intel Quark X1000 GPIO IRQ Number */ #define GPIO_IRQ_QUARK_X1000 9 |
19921ef61 mfd: Add tunnelcr... |
30 31 |
#define WDTBASE 0x84 #define WDT_IO_SIZE 64 |
b24512c86 mfd: lpc_sch: Red... |
32 33 34 35 |
enum sch_chipsets { LPC_SCH = 0, /* Intel Poulsbo SCH */ LPC_ITC, /* Intel Tunnel Creek */ LPC_CENTERTON, /* Intel Centerton */ |
ec689a8a8 mfd: lpc_sch: Add... |
36 |
LPC_QUARK_X1000, /* Intel Quark X1000 */ |
e82c60ae7 mfd: Introduce lp... |
37 |
}; |
b24512c86 mfd: lpc_sch: Red... |
38 39 40 41 |
struct lpc_sch_info { unsigned int io_size_smbus; unsigned int io_size_gpio; unsigned int io_size_wdt; |
ec689a8a8 mfd: lpc_sch: Add... |
42 |
int irq_gpio; |
e82c60ae7 mfd: Introduce lp... |
43 |
}; |
b24512c86 mfd: lpc_sch: Red... |
44 45 46 47 |
static struct lpc_sch_info sch_chipset_info[] = { [LPC_SCH] = { .io_size_smbus = SMBUS_IO_SIZE, .io_size_gpio = GPIO_IO_SIZE, |
ec689a8a8 mfd: lpc_sch: Add... |
48 |
.irq_gpio = -1, |
b24512c86 mfd: lpc_sch: Red... |
49 50 51 52 53 |
}, [LPC_ITC] = { .io_size_smbus = SMBUS_IO_SIZE, .io_size_gpio = GPIO_IO_SIZE, .io_size_wdt = WDT_IO_SIZE, |
ec689a8a8 mfd: lpc_sch: Add... |
54 |
.irq_gpio = -1, |
b24512c86 mfd: lpc_sch: Red... |
55 56 57 58 59 |
}, [LPC_CENTERTON] = { .io_size_smbus = SMBUS_IO_SIZE, .io_size_gpio = GPIO_IO_SIZE_CENTERTON, .io_size_wdt = WDT_IO_SIZE, |
ec689a8a8 mfd: lpc_sch: Add... |
60 61 62 63 64 |
.irq_gpio = -1, }, [LPC_QUARK_X1000] = { .io_size_gpio = GPIO_IO_SIZE, .irq_gpio = GPIO_IRQ_QUARK_X1000, |
c68a8658a mfd: lpc_sch: Ena... |
65 |
.io_size_wdt = WDT_IO_SIZE, |
b24512c86 mfd: lpc_sch: Red... |
66 |
}, |
19921ef61 mfd: Add tunnelcr... |
67 |
}; |
36fcd06c4 mfd: Remove DEFIN... |
68 |
static const struct pci_device_id lpc_sch_ids[] = { |
b24512c86 mfd: lpc_sch: Red... |
69 70 71 |
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC), LPC_SCH }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ITC_LPC), LPC_ITC }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CENTERTON_ILB), LPC_CENTERTON }, |
ec689a8a8 mfd: lpc_sch: Add... |
72 |
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_QUARK_X1000_ILB), LPC_QUARK_X1000 }, |
e82c60ae7 mfd: Introduce lp... |
73 74 75 |
{ 0, } }; MODULE_DEVICE_TABLE(pci, lpc_sch_ids); |
b24512c86 mfd: lpc_sch: Red... |
76 77 78 79 80 |
#define LPC_NO_RESOURCE 1 #define LPC_SKIP_RESOURCE 2 static int lpc_sch_get_io(struct pci_dev *pdev, int where, const char *name, struct resource *res, int size) |
e82c60ae7 mfd: Introduce lp... |
81 82 83 |
{ unsigned int base_addr_cfg; unsigned short base_addr; |
b24512c86 mfd: lpc_sch: Red... |
84 85 86 87 |
if (size == 0) return LPC_NO_RESOURCE; pci_read_config_dword(pdev, where, &base_addr_cfg); |
5829e9b64 mfd: lpc_sch: Acc... |
88 89 |
base_addr = 0; if (!(base_addr_cfg & (1 << 31))) |
b24512c86 mfd: lpc_sch: Red... |
90 91 92 |
dev_warn(&pdev->dev, "Decode of the %s I/O range disabled ", name); |
5829e9b64 mfd: lpc_sch: Acc... |
93 94 |
else base_addr = (unsigned short)base_addr_cfg; |
e82c60ae7 mfd: Introduce lp... |
95 |
|
e82c60ae7 mfd: Introduce lp... |
96 |
if (base_addr == 0) { |
b24512c86 mfd: lpc_sch: Red... |
97 98 99 |
dev_warn(&pdev->dev, "I/O space for %s uninitialized ", name); return LPC_SKIP_RESOURCE; |
e82c60ae7 mfd: Introduce lp... |
100 |
} |
b24512c86 mfd: lpc_sch: Red... |
101 102 103 |
res->start = base_addr; res->end = base_addr + size - 1; res->flags = IORESOURCE_IO; |
e967f77d9 mfd: Add Tunnel C... |
104 |
|
b24512c86 mfd: lpc_sch: Red... |
105 106 |
return 0; } |
19921ef61 mfd: Add tunnelcr... |
107 |
|
b24512c86 mfd: lpc_sch: Red... |
108 |
static int lpc_sch_populate_cell(struct pci_dev *pdev, int where, |
ec689a8a8 mfd: lpc_sch: Add... |
109 110 |
const char *name, int size, int irq, int id, struct mfd_cell *cell) |
b24512c86 mfd: lpc_sch: Red... |
111 112 113 |
{ struct resource *res; int ret; |
19921ef61 mfd: Add tunnelcr... |
114 |
|
ec689a8a8 mfd: lpc_sch: Add... |
115 |
res = devm_kcalloc(&pdev->dev, 2, sizeof(*res), GFP_KERNEL); |
b24512c86 mfd: lpc_sch: Red... |
116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
if (!res) return -ENOMEM; ret = lpc_sch_get_io(pdev, where, name, res, size); if (ret) return ret; memset(cell, 0, sizeof(*cell)); cell->name = name; cell->resources = res; cell->num_resources = 1; cell->ignore_resource_conflicts = true; cell->id = id; |
ec689a8a8 mfd: lpc_sch: Add... |
130 131 132 133 134 135 136 137 138 139 140 |
/* Check if we need to add an IRQ resource */ if (irq < 0) return 0; res++; res->start = irq; res->end = irq; res->flags = IORESOURCE_IRQ; cell->num_resources++; |
b24512c86 mfd: lpc_sch: Red... |
141 142 143 144 145 146 147 148 149 150 151 |
return 0; } static int lpc_sch_probe(struct pci_dev *dev, const struct pci_device_id *id) { struct mfd_cell lpc_sch_cells[3]; struct lpc_sch_info *info = &sch_chipset_info[id->driver_data]; unsigned int cells = 0; int ret; ret = lpc_sch_populate_cell(dev, SMBASE, "isch_smbus", |
ec689a8a8 mfd: lpc_sch: Add... |
152 |
info->io_size_smbus, -1, |
b24512c86 mfd: lpc_sch: Red... |
153 154 155 156 157 158 159 |
id->device, &lpc_sch_cells[cells]); if (ret < 0) return ret; if (ret == 0) cells++; ret = lpc_sch_populate_cell(dev, GPIOBASE, "sch_gpio", |
ec689a8a8 mfd: lpc_sch: Add... |
160 |
info->io_size_gpio, info->irq_gpio, |
b24512c86 mfd: lpc_sch: Red... |
161 162 163 164 165 166 167 |
id->device, &lpc_sch_cells[cells]); if (ret < 0) return ret; if (ret == 0) cells++; ret = lpc_sch_populate_cell(dev, WDTBASE, "ie6xx_wdt", |
ec689a8a8 mfd: lpc_sch: Add... |
168 |
info->io_size_wdt, -1, |
b24512c86 mfd: lpc_sch: Red... |
169 170 171 172 173 |
id->device, &lpc_sch_cells[cells]); if (ret < 0) return ret; if (ret == 0) cells++; |
19921ef61 mfd: Add tunnelcr... |
174 |
|
5829e9b64 mfd: lpc_sch: Acc... |
175 176 177 178 |
if (cells == 0) { dev_err(&dev->dev, "All decode registers disabled. "); return -ENODEV; |
19921ef61 mfd: Add tunnelcr... |
179 |
} |
bde3e706a mfd: lpc_sch: Don... |
180 |
return mfd_add_devices(&dev->dev, 0, lpc_sch_cells, cells, NULL, 0, NULL); |
e82c60ae7 mfd: Introduce lp... |
181 |
} |
4740f73fe mfd: remove use o... |
182 |
static void lpc_sch_remove(struct pci_dev *dev) |
e82c60ae7 mfd: Introduce lp... |
183 184 185 186 187 188 189 190 |
{ mfd_remove_devices(&dev->dev); } static struct pci_driver lpc_sch_driver = { .name = "lpc_sch", .id_table = lpc_sch_ids, .probe = lpc_sch_probe, |
84449216b mfd: remove use o... |
191 |
.remove = lpc_sch_remove, |
e82c60ae7 mfd: Introduce lp... |
192 |
}; |
38a36f5a6 mfd: Use module_p... |
193 |
module_pci_driver(lpc_sch_driver); |
e82c60ae7 mfd: Introduce lp... |
194 195 196 197 |
MODULE_AUTHOR("Denis Turischev <denis@compulab.co.il>"); MODULE_DESCRIPTION("LPC interface for Intel Poulsbo SCH"); MODULE_LICENSE("GPL"); |