1/* 2 * Intel Quark MFD PCI driver for I2C & GPIO 3 * 4 * Copyright(c) 2014 Intel Corporation. 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms and conditions of the GNU General Public License, 8 * version 2, as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 * more details. 14 * 15 * Intel Quark PCI device for I2C and GPIO controller sharing the same 16 * PCI function. This PCI driver will split the 2 devices into their 17 * respective drivers. 18 */ 19 20#include <linux/kernel.h> 21#include <linux/module.h> 22#include <linux/pci.h> 23#include <linux/mfd/core.h> 24#include <linux/clkdev.h> 25#include <linux/clk-provider.h> 26#include <linux/dmi.h> 27#include <linux/platform_data/gpio-dwapb.h> 28#include <linux/platform_data/i2c-designware.h> 29 30/* PCI BAR for register base address */ 31#define MFD_I2C_BAR 0 32#define MFD_GPIO_BAR 1 33 34/* ACPI _ADR value to match the child node */ 35#define MFD_ACPI_MATCH_GPIO 0ULL 36#define MFD_ACPI_MATCH_I2C 1ULL 37 38/* The base GPIO number under GPIOLIB framework */ 39#define INTEL_QUARK_MFD_GPIO_BASE 8 40 41/* The default number of South-Cluster GPIO on Quark. */ 42#define INTEL_QUARK_MFD_NGPIO 8 43 44/* The DesignWare GPIO ports on Quark. */ 45#define INTEL_QUARK_GPIO_NPORTS 1 46 47#define INTEL_QUARK_IORES_MEM 0 48#define INTEL_QUARK_IORES_IRQ 1 49 50#define INTEL_QUARK_I2C_CONTROLLER_CLK "i2c_designware.0" 51 52/* The Quark I2C controller source clock */ 53#define INTEL_QUARK_I2C_CLK_HZ 33000000 54 55#define INTEL_QUARK_I2C_NCLK 1 56 57struct intel_quark_mfd { 58 struct pci_dev *pdev; 59 struct clk *i2c_clk; 60 struct clk_lookup *i2c_clk_lookup; 61}; 62 63struct i2c_mode_info { 64 const char *name; 65 unsigned int i2c_scl_freq; 66}; 67 68static const struct i2c_mode_info platform_i2c_mode_info[] = { 69 { 70 .name = "Galileo", 71 .i2c_scl_freq = 100000, 72 }, 73 { 74 .name = "GalileoGen2", 75 .i2c_scl_freq = 400000, 76 }, 77 {} 78}; 79 80static struct resource intel_quark_i2c_res[] = { 81 [INTEL_QUARK_IORES_MEM] = { 82 .flags = IORESOURCE_MEM, 83 }, 84 [INTEL_QUARK_IORES_IRQ] = { 85 .flags = IORESOURCE_IRQ, 86 }, 87}; 88 89static struct mfd_cell_acpi_match intel_quark_acpi_match_i2c = { 90 .adr = MFD_ACPI_MATCH_I2C, 91}; 92 93static struct resource intel_quark_gpio_res[] = { 94 [INTEL_QUARK_IORES_MEM] = { 95 .flags = IORESOURCE_MEM, 96 }, 97}; 98 99static struct mfd_cell_acpi_match intel_quark_acpi_match_gpio = { 100 .adr = MFD_ACPI_MATCH_GPIO, 101}; 102 103static struct mfd_cell intel_quark_mfd_cells[] = { 104 { 105 .id = MFD_GPIO_BAR, 106 .name = "gpio-dwapb", 107 .acpi_match = &intel_quark_acpi_match_gpio, 108 .num_resources = ARRAY_SIZE(intel_quark_gpio_res), 109 .resources = intel_quark_gpio_res, 110 .ignore_resource_conflicts = true, 111 }, 112 { 113 .id = MFD_I2C_BAR, 114 .name = "i2c_designware", 115 .acpi_match = &intel_quark_acpi_match_i2c, 116 .num_resources = ARRAY_SIZE(intel_quark_i2c_res), 117 .resources = intel_quark_i2c_res, 118 .ignore_resource_conflicts = true, 119 }, 120}; 121 122static const struct pci_device_id intel_quark_mfd_ids[] = { 123 { PCI_VDEVICE(INTEL, 0x0934), }, 124 {}, 125}; 126MODULE_DEVICE_TABLE(pci, intel_quark_mfd_ids); 127 128static int intel_quark_register_i2c_clk(struct intel_quark_mfd *quark_mfd) 129{ 130 struct pci_dev *pdev = quark_mfd->pdev; 131 struct clk_lookup *i2c_clk_lookup; 132 struct clk *i2c_clk; 133 int ret; 134 135 i2c_clk_lookup = devm_kcalloc(&pdev->dev, INTEL_QUARK_I2C_NCLK, 136 sizeof(*i2c_clk_lookup), GFP_KERNEL); 137 if (!i2c_clk_lookup) 138 return -ENOMEM; 139 140 i2c_clk_lookup[0].dev_id = INTEL_QUARK_I2C_CONTROLLER_CLK; 141 142 i2c_clk = clk_register_fixed_rate(&pdev->dev, 143 INTEL_QUARK_I2C_CONTROLLER_CLK, NULL, 144 CLK_IS_ROOT, INTEL_QUARK_I2C_CLK_HZ); 145 146 quark_mfd->i2c_clk_lookup = i2c_clk_lookup; 147 quark_mfd->i2c_clk = i2c_clk; 148 149 ret = clk_register_clkdevs(i2c_clk, i2c_clk_lookup, 150 INTEL_QUARK_I2C_NCLK); 151 if (ret) 152 dev_err(&pdev->dev, "Fixed clk register failed: %d\n", ret); 153 154 return ret; 155} 156 157static void intel_quark_unregister_i2c_clk(struct pci_dev *pdev) 158{ 159 struct intel_quark_mfd *quark_mfd = dev_get_drvdata(&pdev->dev); 160 161 if (!quark_mfd->i2c_clk || !quark_mfd->i2c_clk_lookup) 162 return; 163 164 clkdev_drop(quark_mfd->i2c_clk_lookup); 165 clk_unregister(quark_mfd->i2c_clk); 166} 167 168static int intel_quark_i2c_setup(struct pci_dev *pdev, struct mfd_cell *cell) 169{ 170 const char *board_name = dmi_get_system_info(DMI_BOARD_NAME); 171 const struct i2c_mode_info *info; 172 struct dw_i2c_platform_data *pdata; 173 struct resource *res = (struct resource *)cell->resources; 174 struct device *dev = &pdev->dev; 175 176 res[INTEL_QUARK_IORES_MEM].start = 177 pci_resource_start(pdev, MFD_I2C_BAR); 178 res[INTEL_QUARK_IORES_MEM].end = 179 pci_resource_end(pdev, MFD_I2C_BAR); 180 181 res[INTEL_QUARK_IORES_IRQ].start = pdev->irq; 182 res[INTEL_QUARK_IORES_IRQ].end = pdev->irq; 183 184 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 185 if (!pdata) 186 return -ENOMEM; 187 188 /* Normal mode by default */ 189 pdata->i2c_scl_freq = 100000; 190 191 if (board_name) { 192 for (info = platform_i2c_mode_info; info->name; info++) { 193 if (!strcmp(board_name, info->name)) { 194 pdata->i2c_scl_freq = info->i2c_scl_freq; 195 break; 196 } 197 } 198 } 199 200 cell->platform_data = pdata; 201 cell->pdata_size = sizeof(*pdata); 202 203 return 0; 204} 205 206static int intel_quark_gpio_setup(struct pci_dev *pdev, struct mfd_cell *cell) 207{ 208 struct dwapb_platform_data *pdata; 209 struct resource *res = (struct resource *)cell->resources; 210 struct device *dev = &pdev->dev; 211 212 res[INTEL_QUARK_IORES_MEM].start = 213 pci_resource_start(pdev, MFD_GPIO_BAR); 214 res[INTEL_QUARK_IORES_MEM].end = 215 pci_resource_end(pdev, MFD_GPIO_BAR); 216 217 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 218 if (!pdata) 219 return -ENOMEM; 220 221 /* For intel quark x1000, it has only one port: portA */ 222 pdata->nports = INTEL_QUARK_GPIO_NPORTS; 223 pdata->properties = devm_kcalloc(dev, pdata->nports, 224 sizeof(*pdata->properties), 225 GFP_KERNEL); 226 if (!pdata->properties) 227 return -ENOMEM; 228 229 /* Set the properties for portA */ 230 pdata->properties->node = NULL; 231 pdata->properties->name = "intel-quark-x1000-gpio-portA"; 232 pdata->properties->idx = 0; 233 pdata->properties->ngpio = INTEL_QUARK_MFD_NGPIO; 234 pdata->properties->gpio_base = INTEL_QUARK_MFD_GPIO_BASE; 235 pdata->properties->irq = pdev->irq; 236 pdata->properties->irq_shared = true; 237 238 cell->platform_data = pdata; 239 cell->pdata_size = sizeof(*pdata); 240 241 return 0; 242} 243 244static int intel_quark_mfd_probe(struct pci_dev *pdev, 245 const struct pci_device_id *id) 246{ 247 struct intel_quark_mfd *quark_mfd; 248 int ret; 249 250 ret = pcim_enable_device(pdev); 251 if (ret) 252 return ret; 253 254 quark_mfd = devm_kzalloc(&pdev->dev, sizeof(*quark_mfd), GFP_KERNEL); 255 if (!quark_mfd) 256 return -ENOMEM; 257 quark_mfd->pdev = pdev; 258 259 ret = intel_quark_register_i2c_clk(quark_mfd); 260 if (ret) 261 return ret; 262 263 dev_set_drvdata(&pdev->dev, quark_mfd); 264 265 ret = intel_quark_i2c_setup(pdev, &intel_quark_mfd_cells[1]); 266 if (ret) 267 return ret; 268 269 ret = intel_quark_gpio_setup(pdev, &intel_quark_mfd_cells[0]); 270 if (ret) 271 return ret; 272 273 return mfd_add_devices(&pdev->dev, 0, intel_quark_mfd_cells, 274 ARRAY_SIZE(intel_quark_mfd_cells), NULL, 0, 275 NULL); 276} 277 278static void intel_quark_mfd_remove(struct pci_dev *pdev) 279{ 280 intel_quark_unregister_i2c_clk(pdev); 281 mfd_remove_devices(&pdev->dev); 282} 283 284static struct pci_driver intel_quark_mfd_driver = { 285 .name = "intel_quark_mfd_i2c_gpio", 286 .id_table = intel_quark_mfd_ids, 287 .probe = intel_quark_mfd_probe, 288 .remove = intel_quark_mfd_remove, 289}; 290 291module_pci_driver(intel_quark_mfd_driver); 292 293MODULE_AUTHOR("Raymond Tan <raymond.tan@intel.com>"); 294MODULE_DESCRIPTION("Intel Quark MFD PCI driver for I2C & GPIO"); 295MODULE_LICENSE("GPL v2"); 296