Blame view
drivers/mfd/intel_quark_i2c_gpio.c
6.95 KB
2025cf9e1 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
60ae5b9f5 mfd: intel_quark_... |
2 3 4 5 6 |
/* * Intel Quark MFD PCI driver for I2C & GPIO * * Copyright(c) 2014 Intel Corporation. * |
60ae5b9f5 mfd: intel_quark_... |
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
* Intel Quark PCI device for I2C and GPIO controller sharing the same * PCI function. This PCI driver will split the 2 devices into their * respective drivers. */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/mfd/core.h> #include <linux/clkdev.h> #include <linux/clk-provider.h> #include <linux/dmi.h> #include <linux/platform_data/gpio-dwapb.h> #include <linux/platform_data/i2c-designware.h> /* PCI BAR for register base address */ #define MFD_I2C_BAR 0 #define MFD_GPIO_BAR 1 |
918fe70cf mfd: intel_quark_... |
25 26 27 |
/* ACPI _ADR value to match the child node */ #define MFD_ACPI_MATCH_GPIO 0ULL #define MFD_ACPI_MATCH_I2C 1ULL |
60ae5b9f5 mfd: intel_quark_... |
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
/* The base GPIO number under GPIOLIB framework */ #define INTEL_QUARK_MFD_GPIO_BASE 8 /* The default number of South-Cluster GPIO on Quark. */ #define INTEL_QUARK_MFD_NGPIO 8 /* The DesignWare GPIO ports on Quark. */ #define INTEL_QUARK_GPIO_NPORTS 1 #define INTEL_QUARK_IORES_MEM 0 #define INTEL_QUARK_IORES_IRQ 1 #define INTEL_QUARK_I2C_CONTROLLER_CLK "i2c_designware.0" /* The Quark I2C controller source clock */ #define INTEL_QUARK_I2C_CLK_HZ 33000000 |
60ae5b9f5 mfd: intel_quark_... |
44 |
struct intel_quark_mfd { |
9caac8863 mfd: intel_quark_... |
45 |
struct device *dev; |
60ae5b9f5 mfd: intel_quark_... |
46 47 48 |
struct clk *i2c_clk; struct clk_lookup *i2c_clk_lookup; }; |
b518d4adb mfd: intel_quark_... |
49 |
static const struct dmi_system_id dmi_platform_info[] = { |
60ae5b9f5 mfd: intel_quark_... |
50 |
{ |
b518d4adb mfd: intel_quark_... |
51 52 53 54 |
.matches = { DMI_EXACT_MATCH(DMI_BOARD_NAME, "Galileo"), }, .driver_data = (void *)100000, |
60ae5b9f5 mfd: intel_quark_... |
55 56 |
}, { |
b518d4adb mfd: intel_quark_... |
57 58 59 60 |
.matches = { DMI_EXACT_MATCH(DMI_BOARD_NAME, "GalileoGen2"), }, .driver_data = (void *)400000, |
60ae5b9f5 mfd: intel_quark_... |
61 |
}, |
842086d2b mfd: intel_quark_... |
62 63 64 |
{ .matches = { DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"), |
842086d2b mfd: intel_quark_... |
65 66 67 |
}, .driver_data = (void *)400000, }, |
bafc1face mfd: intel_quark_... |
68 |
{} |
60ae5b9f5 mfd: intel_quark_... |
69 70 71 72 73 74 75 76 77 78 |
}; static struct resource intel_quark_i2c_res[] = { [INTEL_QUARK_IORES_MEM] = { .flags = IORESOURCE_MEM, }, [INTEL_QUARK_IORES_IRQ] = { .flags = IORESOURCE_IRQ, }, }; |
918fe70cf mfd: intel_quark_... |
79 80 81 |
static struct mfd_cell_acpi_match intel_quark_acpi_match_i2c = { .adr = MFD_ACPI_MATCH_I2C, }; |
60ae5b9f5 mfd: intel_quark_... |
82 83 84 85 86 |
static struct resource intel_quark_gpio_res[] = { [INTEL_QUARK_IORES_MEM] = { .flags = IORESOURCE_MEM, }, }; |
918fe70cf mfd: intel_quark_... |
87 88 89 |
static struct mfd_cell_acpi_match intel_quark_acpi_match_gpio = { .adr = MFD_ACPI_MATCH_GPIO, }; |
60ae5b9f5 mfd: intel_quark_... |
90 91 |
static struct mfd_cell intel_quark_mfd_cells[] = { { |
60ae5b9f5 mfd: intel_quark_... |
92 93 |
.id = MFD_GPIO_BAR, .name = "gpio-dwapb", |
918fe70cf mfd: intel_quark_... |
94 |
.acpi_match = &intel_quark_acpi_match_gpio, |
60ae5b9f5 mfd: intel_quark_... |
95 96 97 98 |
.num_resources = ARRAY_SIZE(intel_quark_gpio_res), .resources = intel_quark_gpio_res, .ignore_resource_conflicts = true, }, |
236fd469f mfd: intel_quark_... |
99 100 101 |
{ .id = MFD_I2C_BAR, .name = "i2c_designware", |
918fe70cf mfd: intel_quark_... |
102 |
.acpi_match = &intel_quark_acpi_match_i2c, |
236fd469f mfd: intel_quark_... |
103 104 105 106 |
.num_resources = ARRAY_SIZE(intel_quark_i2c_res), .resources = intel_quark_i2c_res, .ignore_resource_conflicts = true, }, |
60ae5b9f5 mfd: intel_quark_... |
107 108 109 110 111 112 113 |
}; static const struct pci_device_id intel_quark_mfd_ids[] = { { PCI_VDEVICE(INTEL, 0x0934), }, {}, }; MODULE_DEVICE_TABLE(pci, intel_quark_mfd_ids); |
9caac8863 mfd: intel_quark_... |
114 |
static int intel_quark_register_i2c_clk(struct device *dev) |
60ae5b9f5 mfd: intel_quark_... |
115 |
{ |
9caac8863 mfd: intel_quark_... |
116 |
struct intel_quark_mfd *quark_mfd = dev_get_drvdata(dev); |
60ae5b9f5 mfd: intel_quark_... |
117 |
struct clk *i2c_clk; |
60ae5b9f5 mfd: intel_quark_... |
118 |
|
9caac8863 mfd: intel_quark_... |
119 |
i2c_clk = clk_register_fixed_rate(dev, |
60ae5b9f5 mfd: intel_quark_... |
120 |
INTEL_QUARK_I2C_CONTROLLER_CLK, NULL, |
36a0c0884 mfd: intel_quark_... |
121 |
0, INTEL_QUARK_I2C_CLK_HZ); |
c4726abce mfd: intel_quark_... |
122 123 |
if (IS_ERR(i2c_clk)) return PTR_ERR(i2c_clk); |
60ae5b9f5 mfd: intel_quark_... |
124 |
|
60ae5b9f5 mfd: intel_quark_... |
125 |
quark_mfd->i2c_clk = i2c_clk; |
c4726abce mfd: intel_quark_... |
126 127 |
quark_mfd->i2c_clk_lookup = clkdev_create(i2c_clk, NULL, INTEL_QUARK_I2C_CONTROLLER_CLK); |
60ae5b9f5 mfd: intel_quark_... |
128 |
|
c4726abce mfd: intel_quark_... |
129 |
if (!quark_mfd->i2c_clk_lookup) { |
7f0c5ae18 mfd: intel_quark_... |
130 |
clk_unregister(quark_mfd->i2c_clk); |
9caac8863 mfd: intel_quark_... |
131 132 |
dev_err(dev, "Fixed clk register failed "); |
c4726abce mfd: intel_quark_... |
133 134 |
return -ENOMEM; } |
60ae5b9f5 mfd: intel_quark_... |
135 |
|
c4726abce mfd: intel_quark_... |
136 |
return 0; |
60ae5b9f5 mfd: intel_quark_... |
137 |
} |
9caac8863 mfd: intel_quark_... |
138 |
static void intel_quark_unregister_i2c_clk(struct device *dev) |
60ae5b9f5 mfd: intel_quark_... |
139 |
{ |
9caac8863 mfd: intel_quark_... |
140 |
struct intel_quark_mfd *quark_mfd = dev_get_drvdata(dev); |
60ae5b9f5 mfd: intel_quark_... |
141 |
|
7f0c5ae18 mfd: intel_quark_... |
142 |
if (!quark_mfd->i2c_clk_lookup) |
60ae5b9f5 mfd: intel_quark_... |
143 144 145 146 147 148 149 150 |
return; clkdev_drop(quark_mfd->i2c_clk_lookup); clk_unregister(quark_mfd->i2c_clk); } static int intel_quark_i2c_setup(struct pci_dev *pdev, struct mfd_cell *cell) { |
b518d4adb mfd: intel_quark_... |
151 |
const struct dmi_system_id *dmi_id; |
60ae5b9f5 mfd: intel_quark_... |
152 153 154 |
struct dw_i2c_platform_data *pdata; struct resource *res = (struct resource *)cell->resources; struct device *dev = &pdev->dev; |
60ae5b9f5 mfd: intel_quark_... |
155 156 157 158 159 160 161 162 163 164 165 166 |
res[INTEL_QUARK_IORES_MEM].start = pci_resource_start(pdev, MFD_I2C_BAR); res[INTEL_QUARK_IORES_MEM].end = pci_resource_end(pdev, MFD_I2C_BAR); res[INTEL_QUARK_IORES_IRQ].start = pdev->irq; res[INTEL_QUARK_IORES_IRQ].end = pdev->irq; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; |
bafc1face mfd: intel_quark_... |
167 168 |
/* Normal mode by default */ pdata->i2c_scl_freq = 100000; |
b518d4adb mfd: intel_quark_... |
169 170 171 |
dmi_id = dmi_first_match(dmi_platform_info); if (dmi_id) pdata->i2c_scl_freq = (uintptr_t)dmi_id->driver_data; |
60ae5b9f5 mfd: intel_quark_... |
172 173 174 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 |
cell->platform_data = pdata; cell->pdata_size = sizeof(*pdata); return 0; } static int intel_quark_gpio_setup(struct pci_dev *pdev, struct mfd_cell *cell) { struct dwapb_platform_data *pdata; struct resource *res = (struct resource *)cell->resources; struct device *dev = &pdev->dev; res[INTEL_QUARK_IORES_MEM].start = pci_resource_start(pdev, MFD_GPIO_BAR); res[INTEL_QUARK_IORES_MEM].end = pci_resource_end(pdev, MFD_GPIO_BAR); pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; /* For intel quark x1000, it has only one port: portA */ pdata->nports = INTEL_QUARK_GPIO_NPORTS; pdata->properties = devm_kcalloc(dev, pdata->nports, sizeof(*pdata->properties), GFP_KERNEL); if (!pdata->properties) return -ENOMEM; /* Set the properties for portA */ |
4ba8cfa79 gpio: dwapb: conv... |
203 |
pdata->properties->fwnode = NULL; |
60ae5b9f5 mfd: intel_quark_... |
204 205 206 |
pdata->properties->idx = 0; pdata->properties->ngpio = INTEL_QUARK_MFD_NGPIO; pdata->properties->gpio_base = INTEL_QUARK_MFD_GPIO_BASE; |
e6ca26abd gpio: dwapb: Add ... |
207 |
pdata->properties->irq[0] = pdev->irq; |
60ae5b9f5 mfd: intel_quark_... |
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
pdata->properties->irq_shared = true; cell->platform_data = pdata; cell->pdata_size = sizeof(*pdata); return 0; } static int intel_quark_mfd_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct intel_quark_mfd *quark_mfd; int ret; ret = pcim_enable_device(pdev); if (ret) return ret; quark_mfd = devm_kzalloc(&pdev->dev, sizeof(*quark_mfd), GFP_KERNEL); if (!quark_mfd) return -ENOMEM; |
60ae5b9f5 mfd: intel_quark_... |
229 |
|
9caac8863 mfd: intel_quark_... |
230 |
quark_mfd->dev = &pdev->dev; |
7f0c5ae18 mfd: intel_quark_... |
231 |
dev_set_drvdata(&pdev->dev, quark_mfd); |
60ae5b9f5 mfd: intel_quark_... |
232 |
|
9caac8863 mfd: intel_quark_... |
233 |
ret = intel_quark_register_i2c_clk(&pdev->dev); |
60ae5b9f5 mfd: intel_quark_... |
234 235 |
if (ret) return ret; |
236fd469f mfd: intel_quark_... |
236 |
ret = intel_quark_i2c_setup(pdev, &intel_quark_mfd_cells[1]); |
60ae5b9f5 mfd: intel_quark_... |
237 |
if (ret) |
7f0c5ae18 mfd: intel_quark_... |
238 |
goto err_unregister_i2c_clk; |
60ae5b9f5 mfd: intel_quark_... |
239 |
|
236fd469f mfd: intel_quark_... |
240 |
ret = intel_quark_gpio_setup(pdev, &intel_quark_mfd_cells[0]); |
60ae5b9f5 mfd: intel_quark_... |
241 |
if (ret) |
7f0c5ae18 mfd: intel_quark_... |
242 |
goto err_unregister_i2c_clk; |
60ae5b9f5 mfd: intel_quark_... |
243 |
|
7f0c5ae18 mfd: intel_quark_... |
244 245 246 247 248 249 250 |
ret = mfd_add_devices(&pdev->dev, 0, intel_quark_mfd_cells, ARRAY_SIZE(intel_quark_mfd_cells), NULL, 0, NULL); if (ret) goto err_unregister_i2c_clk; return 0; |
60ae5b9f5 mfd: intel_quark_... |
251 |
|
7f0c5ae18 mfd: intel_quark_... |
252 |
err_unregister_i2c_clk: |
9caac8863 mfd: intel_quark_... |
253 |
intel_quark_unregister_i2c_clk(&pdev->dev); |
7f0c5ae18 mfd: intel_quark_... |
254 |
return ret; |
60ae5b9f5 mfd: intel_quark_... |
255 256 257 258 |
} static void intel_quark_mfd_remove(struct pci_dev *pdev) { |
9caac8863 mfd: intel_quark_... |
259 |
intel_quark_unregister_i2c_clk(&pdev->dev); |
60ae5b9f5 mfd: intel_quark_... |
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
mfd_remove_devices(&pdev->dev); } static struct pci_driver intel_quark_mfd_driver = { .name = "intel_quark_mfd_i2c_gpio", .id_table = intel_quark_mfd_ids, .probe = intel_quark_mfd_probe, .remove = intel_quark_mfd_remove, }; module_pci_driver(intel_quark_mfd_driver); MODULE_AUTHOR("Raymond Tan <raymond.tan@intel.com>"); MODULE_DESCRIPTION("Intel Quark MFD PCI driver for I2C & GPIO"); MODULE_LICENSE("GPL v2"); |