intel_quark_i2c_gpio.c (8183B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Intel Quark MFD PCI driver for I2C & GPIO 4 * 5 * Copyright(c) 2014 Intel Corporation. 6 * 7 * Intel Quark PCI device for I2C and GPIO controller sharing the same 8 * PCI function. This PCI driver will split the 2 devices into their 9 * respective drivers. 10 */ 11 12#include <linux/kernel.h> 13#include <linux/module.h> 14#include <linux/pci.h> 15#include <linux/mfd/core.h> 16#include <linux/clkdev.h> 17#include <linux/clk-provider.h> 18#include <linux/dmi.h> 19#include <linux/i2c.h> 20#include <linux/property.h> 21 22/* PCI BAR for register base address */ 23#define MFD_I2C_BAR 0 24#define MFD_GPIO_BAR 1 25 26/* ACPI _ADR value to match the child node */ 27#define MFD_ACPI_MATCH_GPIO 0ULL 28#define MFD_ACPI_MATCH_I2C 1ULL 29 30#define INTEL_QUARK_IORES_MEM 0 31#define INTEL_QUARK_IORES_IRQ 1 32 33#define INTEL_QUARK_I2C_CONTROLLER_CLK "i2c_designware.0" 34 35/* The Quark I2C controller source clock */ 36#define INTEL_QUARK_I2C_CLK_HZ 33000000 37 38struct intel_quark_mfd { 39 struct clk *i2c_clk; 40 struct clk_lookup *i2c_clk_lookup; 41}; 42 43static const struct property_entry intel_quark_i2c_controller_standard_properties[] = { 44 PROPERTY_ENTRY_U32("clock-frequency", I2C_MAX_STANDARD_MODE_FREQ), 45 { } 46}; 47 48static const struct software_node intel_quark_i2c_controller_standard_node = { 49 .name = "intel-quark-i2c-controller", 50 .properties = intel_quark_i2c_controller_standard_properties, 51}; 52 53static const struct property_entry intel_quark_i2c_controller_fast_properties[] = { 54 PROPERTY_ENTRY_U32("clock-frequency", I2C_MAX_FAST_MODE_FREQ), 55 { } 56}; 57 58static const struct software_node intel_quark_i2c_controller_fast_node = { 59 .name = "intel-quark-i2c-controller", 60 .properties = intel_quark_i2c_controller_fast_properties, 61}; 62 63static const struct dmi_system_id dmi_platform_info[] = { 64 { 65 .matches = { 66 DMI_EXACT_MATCH(DMI_BOARD_NAME, "Galileo"), 67 }, 68 .driver_data = (void *)&intel_quark_i2c_controller_standard_node, 69 }, 70 { 71 .matches = { 72 DMI_EXACT_MATCH(DMI_BOARD_NAME, "GalileoGen2"), 73 }, 74 .driver_data = (void *)&intel_quark_i2c_controller_fast_node, 75 }, 76 { 77 .matches = { 78 DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"), 79 }, 80 .driver_data = (void *)&intel_quark_i2c_controller_fast_node, 81 }, 82 {} 83}; 84 85/* This is used as a place holder and will be modified at run-time */ 86static struct resource intel_quark_i2c_res[] = { 87 [INTEL_QUARK_IORES_MEM] = { 88 .flags = IORESOURCE_MEM, 89 }, 90 [INTEL_QUARK_IORES_IRQ] = { 91 .flags = IORESOURCE_IRQ, 92 }, 93}; 94 95static struct mfd_cell_acpi_match intel_quark_acpi_match_i2c = { 96 .adr = MFD_ACPI_MATCH_I2C, 97}; 98 99/* This is used as a place holder and will be modified at run-time */ 100static struct resource intel_quark_gpio_res[] = { 101 [INTEL_QUARK_IORES_MEM] = { 102 .flags = IORESOURCE_MEM, 103 }, 104 [INTEL_QUARK_IORES_IRQ] = { 105 .flags = IORESOURCE_IRQ, 106 }, 107}; 108 109static struct mfd_cell_acpi_match intel_quark_acpi_match_gpio = { 110 .adr = MFD_ACPI_MATCH_GPIO, 111}; 112 113static const struct software_node intel_quark_gpio_controller_node = { 114 .name = "intel-quark-gpio-controller", 115}; 116 117static const struct property_entry intel_quark_gpio_portA_properties[] = { 118 PROPERTY_ENTRY_U32("reg", 0), 119 PROPERTY_ENTRY_U32("snps,nr-gpios", 8), 120 PROPERTY_ENTRY_U32("gpio-base", 8), 121 { } 122}; 123 124static const struct software_node intel_quark_gpio_portA_node = { 125 .name = "portA", 126 .parent = &intel_quark_gpio_controller_node, 127 .properties = intel_quark_gpio_portA_properties, 128}; 129 130static const struct software_node *intel_quark_gpio_node_group[] = { 131 &intel_quark_gpio_controller_node, 132 &intel_quark_gpio_portA_node, 133 NULL 134}; 135 136static struct mfd_cell intel_quark_mfd_cells[] = { 137 [MFD_I2C_BAR] = { 138 .id = MFD_I2C_BAR, 139 .name = "i2c_designware", 140 .acpi_match = &intel_quark_acpi_match_i2c, 141 .num_resources = ARRAY_SIZE(intel_quark_i2c_res), 142 .resources = intel_quark_i2c_res, 143 .ignore_resource_conflicts = true, 144 }, 145 [MFD_GPIO_BAR] = { 146 .id = MFD_GPIO_BAR, 147 .name = "gpio-dwapb", 148 .acpi_match = &intel_quark_acpi_match_gpio, 149 .num_resources = ARRAY_SIZE(intel_quark_gpio_res), 150 .resources = intel_quark_gpio_res, 151 .ignore_resource_conflicts = true, 152 }, 153}; 154 155static const struct pci_device_id intel_quark_mfd_ids[] = { 156 { PCI_VDEVICE(INTEL, 0x0934), }, 157 {}, 158}; 159MODULE_DEVICE_TABLE(pci, intel_quark_mfd_ids); 160 161static int intel_quark_register_i2c_clk(struct device *dev) 162{ 163 struct intel_quark_mfd *quark_mfd = dev_get_drvdata(dev); 164 struct clk *i2c_clk; 165 166 i2c_clk = clk_register_fixed_rate(dev, 167 INTEL_QUARK_I2C_CONTROLLER_CLK, NULL, 168 0, INTEL_QUARK_I2C_CLK_HZ); 169 if (IS_ERR(i2c_clk)) 170 return PTR_ERR(i2c_clk); 171 172 quark_mfd->i2c_clk = i2c_clk; 173 quark_mfd->i2c_clk_lookup = clkdev_create(i2c_clk, NULL, 174 INTEL_QUARK_I2C_CONTROLLER_CLK); 175 176 if (!quark_mfd->i2c_clk_lookup) { 177 clk_unregister(quark_mfd->i2c_clk); 178 dev_err(dev, "Fixed clk register failed\n"); 179 return -ENOMEM; 180 } 181 182 return 0; 183} 184 185static void intel_quark_unregister_i2c_clk(struct device *dev) 186{ 187 struct intel_quark_mfd *quark_mfd = dev_get_drvdata(dev); 188 189 if (!quark_mfd->i2c_clk_lookup) 190 return; 191 192 clkdev_drop(quark_mfd->i2c_clk_lookup); 193 clk_unregister(quark_mfd->i2c_clk); 194} 195 196static int intel_quark_i2c_setup(struct pci_dev *pdev) 197{ 198 struct mfd_cell *cell = &intel_quark_mfd_cells[MFD_I2C_BAR]; 199 struct resource *res = intel_quark_i2c_res; 200 const struct dmi_system_id *dmi_id; 201 202 res[INTEL_QUARK_IORES_MEM].start = pci_resource_start(pdev, MFD_I2C_BAR); 203 res[INTEL_QUARK_IORES_MEM].end = pci_resource_end(pdev, MFD_I2C_BAR); 204 205 res[INTEL_QUARK_IORES_IRQ].start = pci_irq_vector(pdev, 0); 206 res[INTEL_QUARK_IORES_IRQ].end = pci_irq_vector(pdev, 0); 207 208 /* Normal mode by default */ 209 cell->swnode = &intel_quark_i2c_controller_standard_node; 210 211 dmi_id = dmi_first_match(dmi_platform_info); 212 if (dmi_id) 213 cell->swnode = (struct software_node *)dmi_id->driver_data; 214 215 return 0; 216} 217 218static int intel_quark_gpio_setup(struct pci_dev *pdev) 219{ 220 struct mfd_cell *cell = &intel_quark_mfd_cells[MFD_GPIO_BAR]; 221 struct resource *res = intel_quark_gpio_res; 222 int ret; 223 224 res[INTEL_QUARK_IORES_MEM].start = pci_resource_start(pdev, MFD_GPIO_BAR); 225 res[INTEL_QUARK_IORES_MEM].end = pci_resource_end(pdev, MFD_GPIO_BAR); 226 227 res[INTEL_QUARK_IORES_IRQ].start = pci_irq_vector(pdev, 0); 228 res[INTEL_QUARK_IORES_IRQ].end = pci_irq_vector(pdev, 0); 229 230 ret = software_node_register_node_group(intel_quark_gpio_node_group); 231 if (ret) 232 return ret; 233 234 cell->swnode = &intel_quark_gpio_controller_node; 235 return 0; 236} 237 238static int intel_quark_mfd_probe(struct pci_dev *pdev, 239 const struct pci_device_id *id) 240{ 241 struct intel_quark_mfd *quark_mfd; 242 int ret; 243 244 ret = pcim_enable_device(pdev); 245 if (ret) 246 return ret; 247 248 quark_mfd = devm_kzalloc(&pdev->dev, sizeof(*quark_mfd), GFP_KERNEL); 249 if (!quark_mfd) 250 return -ENOMEM; 251 252 dev_set_drvdata(&pdev->dev, quark_mfd); 253 254 ret = intel_quark_register_i2c_clk(&pdev->dev); 255 if (ret) 256 return ret; 257 258 pci_set_master(pdev); 259 260 /* This driver only requires 1 IRQ vector */ 261 ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); 262 if (ret < 0) 263 goto err_unregister_i2c_clk; 264 265 ret = intel_quark_i2c_setup(pdev); 266 if (ret) 267 goto err_free_irq_vectors; 268 269 ret = intel_quark_gpio_setup(pdev); 270 if (ret) 271 goto err_free_irq_vectors; 272 273 ret = mfd_add_devices(&pdev->dev, 0, intel_quark_mfd_cells, 274 ARRAY_SIZE(intel_quark_mfd_cells), NULL, 0, 275 NULL); 276 if (ret) 277 goto err_unregister_gpio_node_group; 278 279 return 0; 280 281err_unregister_gpio_node_group: 282 software_node_unregister_node_group(intel_quark_gpio_node_group); 283err_free_irq_vectors: 284 pci_free_irq_vectors(pdev); 285err_unregister_i2c_clk: 286 intel_quark_unregister_i2c_clk(&pdev->dev); 287 return ret; 288} 289 290static void intel_quark_mfd_remove(struct pci_dev *pdev) 291{ 292 mfd_remove_devices(&pdev->dev); 293 software_node_unregister_node_group(intel_quark_gpio_node_group); 294 pci_free_irq_vectors(pdev); 295 intel_quark_unregister_i2c_clk(&pdev->dev); 296} 297 298static struct pci_driver intel_quark_mfd_driver = { 299 .name = "intel_quark_mfd_i2c_gpio", 300 .id_table = intel_quark_mfd_ids, 301 .probe = intel_quark_mfd_probe, 302 .remove = intel_quark_mfd_remove, 303}; 304 305module_pci_driver(intel_quark_mfd_driver); 306 307MODULE_AUTHOR("Raymond Tan <raymond.tan@intel.com>"); 308MODULE_DESCRIPTION("Intel Quark MFD PCI driver for I2C & GPIO"); 309MODULE_LICENSE("GPL v2");