Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Intel Quark MFD PCI driver for I2C & GPIO
0004  *
0005  * Copyright(c) 2014 Intel Corporation.
0006  *
0007  * Intel Quark PCI device for I2C and GPIO controller sharing the same
0008  * PCI function. This PCI driver will split the 2 devices into their
0009  * respective drivers.
0010  */
0011 
0012 #include <linux/kernel.h>
0013 #include <linux/module.h>
0014 #include <linux/pci.h>
0015 #include <linux/mfd/core.h>
0016 #include <linux/clkdev.h>
0017 #include <linux/clk-provider.h>
0018 #include <linux/dmi.h>
0019 #include <linux/i2c.h>
0020 #include <linux/property.h>
0021 
0022 /* PCI BAR for register base address */
0023 #define MFD_I2C_BAR     0
0024 #define MFD_GPIO_BAR        1
0025 
0026 /* ACPI _ADR value to match the child node */
0027 #define MFD_ACPI_MATCH_GPIO 0ULL
0028 #define MFD_ACPI_MATCH_I2C  1ULL
0029 
0030 #define INTEL_QUARK_IORES_MEM   0
0031 #define INTEL_QUARK_IORES_IRQ   1
0032 
0033 #define INTEL_QUARK_I2C_CONTROLLER_CLK "i2c_designware.0"
0034 
0035 /* The Quark I2C controller source clock */
0036 #define INTEL_QUARK_I2C_CLK_HZ  33000000
0037 
0038 struct intel_quark_mfd {
0039     struct clk      *i2c_clk;
0040     struct clk_lookup   *i2c_clk_lookup;
0041 };
0042 
0043 static const struct property_entry intel_quark_i2c_controller_standard_properties[] = {
0044     PROPERTY_ENTRY_U32("clock-frequency", I2C_MAX_STANDARD_MODE_FREQ),
0045     { }
0046 };
0047 
0048 static const struct software_node intel_quark_i2c_controller_standard_node = {
0049     .name = "intel-quark-i2c-controller",
0050     .properties = intel_quark_i2c_controller_standard_properties,
0051 };
0052 
0053 static const struct property_entry intel_quark_i2c_controller_fast_properties[] = {
0054     PROPERTY_ENTRY_U32("clock-frequency", I2C_MAX_FAST_MODE_FREQ),
0055     { }
0056 };
0057 
0058 static const struct software_node intel_quark_i2c_controller_fast_node = {
0059     .name = "intel-quark-i2c-controller",
0060     .properties = intel_quark_i2c_controller_fast_properties,
0061 };
0062 
0063 static const struct dmi_system_id dmi_platform_info[] = {
0064     {
0065         .matches = {
0066             DMI_EXACT_MATCH(DMI_BOARD_NAME, "Galileo"),
0067         },
0068         .driver_data = (void *)&intel_quark_i2c_controller_standard_node,
0069     },
0070     {
0071         .matches = {
0072             DMI_EXACT_MATCH(DMI_BOARD_NAME, "GalileoGen2"),
0073         },
0074         .driver_data = (void *)&intel_quark_i2c_controller_fast_node,
0075     },
0076     {
0077         .matches = {
0078             DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"),
0079         },
0080         .driver_data = (void *)&intel_quark_i2c_controller_fast_node,
0081     },
0082     {}
0083 };
0084 
0085 /* This is used as a place holder and will be modified at run-time */
0086 static struct resource intel_quark_i2c_res[] = {
0087     [INTEL_QUARK_IORES_MEM] = {
0088         .flags = IORESOURCE_MEM,
0089     },
0090     [INTEL_QUARK_IORES_IRQ] = {
0091         .flags = IORESOURCE_IRQ,
0092     },
0093 };
0094 
0095 static struct mfd_cell_acpi_match intel_quark_acpi_match_i2c = {
0096     .adr = MFD_ACPI_MATCH_I2C,
0097 };
0098 
0099 /* This is used as a place holder and will be modified at run-time */
0100 static struct resource intel_quark_gpio_res[] = {
0101     [INTEL_QUARK_IORES_MEM] = {
0102         .flags = IORESOURCE_MEM,
0103     },
0104     [INTEL_QUARK_IORES_IRQ] = {
0105         .flags = IORESOURCE_IRQ,
0106     },
0107 };
0108 
0109 static struct mfd_cell_acpi_match intel_quark_acpi_match_gpio = {
0110     .adr = MFD_ACPI_MATCH_GPIO,
0111 };
0112 
0113 static const struct software_node intel_quark_gpio_controller_node = {
0114     .name = "intel-quark-gpio-controller",
0115 };
0116 
0117 static const struct property_entry intel_quark_gpio_portA_properties[] = {
0118     PROPERTY_ENTRY_U32("reg", 0),
0119     PROPERTY_ENTRY_U32("snps,nr-gpios", 8),
0120     PROPERTY_ENTRY_U32("gpio-base", 8),
0121     { }
0122 };
0123 
0124 static const struct software_node intel_quark_gpio_portA_node = {
0125     .name = "portA",
0126     .parent = &intel_quark_gpio_controller_node,
0127     .properties = intel_quark_gpio_portA_properties,
0128 };
0129 
0130 static const struct software_node *intel_quark_gpio_node_group[] = {
0131     &intel_quark_gpio_controller_node,
0132     &intel_quark_gpio_portA_node,
0133     NULL
0134 };
0135 
0136 static struct mfd_cell intel_quark_mfd_cells[] = {
0137     [MFD_I2C_BAR] = {
0138         .id = MFD_I2C_BAR,
0139         .name = "i2c_designware",
0140         .acpi_match = &intel_quark_acpi_match_i2c,
0141         .num_resources = ARRAY_SIZE(intel_quark_i2c_res),
0142         .resources = intel_quark_i2c_res,
0143         .ignore_resource_conflicts = true,
0144     },
0145     [MFD_GPIO_BAR] = {
0146         .id = MFD_GPIO_BAR,
0147         .name = "gpio-dwapb",
0148         .acpi_match = &intel_quark_acpi_match_gpio,
0149         .num_resources = ARRAY_SIZE(intel_quark_gpio_res),
0150         .resources = intel_quark_gpio_res,
0151         .ignore_resource_conflicts = true,
0152     },
0153 };
0154 
0155 static const struct pci_device_id intel_quark_mfd_ids[] = {
0156     { PCI_VDEVICE(INTEL, 0x0934), },
0157     {},
0158 };
0159 MODULE_DEVICE_TABLE(pci, intel_quark_mfd_ids);
0160 
0161 static int intel_quark_register_i2c_clk(struct device *dev)
0162 {
0163     struct intel_quark_mfd *quark_mfd = dev_get_drvdata(dev);
0164     struct clk *i2c_clk;
0165 
0166     i2c_clk = clk_register_fixed_rate(dev,
0167                       INTEL_QUARK_I2C_CONTROLLER_CLK, NULL,
0168                       0, INTEL_QUARK_I2C_CLK_HZ);
0169     if (IS_ERR(i2c_clk))
0170         return PTR_ERR(i2c_clk);
0171 
0172     quark_mfd->i2c_clk = i2c_clk;
0173     quark_mfd->i2c_clk_lookup = clkdev_create(i2c_clk, NULL,
0174                         INTEL_QUARK_I2C_CONTROLLER_CLK);
0175 
0176     if (!quark_mfd->i2c_clk_lookup) {
0177         clk_unregister(quark_mfd->i2c_clk);
0178         dev_err(dev, "Fixed clk register failed\n");
0179         return -ENOMEM;
0180     }
0181 
0182     return 0;
0183 }
0184 
0185 static void intel_quark_unregister_i2c_clk(struct device *dev)
0186 {
0187     struct intel_quark_mfd *quark_mfd = dev_get_drvdata(dev);
0188 
0189     if (!quark_mfd->i2c_clk_lookup)
0190         return;
0191 
0192     clkdev_drop(quark_mfd->i2c_clk_lookup);
0193     clk_unregister(quark_mfd->i2c_clk);
0194 }
0195 
0196 static int intel_quark_i2c_setup(struct pci_dev *pdev)
0197 {
0198     struct mfd_cell *cell = &intel_quark_mfd_cells[MFD_I2C_BAR];
0199     struct resource *res = intel_quark_i2c_res;
0200     const struct dmi_system_id *dmi_id;
0201 
0202     res[INTEL_QUARK_IORES_MEM].start = pci_resource_start(pdev, MFD_I2C_BAR);
0203     res[INTEL_QUARK_IORES_MEM].end = pci_resource_end(pdev, MFD_I2C_BAR);
0204 
0205     res[INTEL_QUARK_IORES_IRQ].start = pci_irq_vector(pdev, 0);
0206     res[INTEL_QUARK_IORES_IRQ].end = pci_irq_vector(pdev, 0);
0207 
0208     /* Normal mode by default */
0209     cell->swnode = &intel_quark_i2c_controller_standard_node;
0210 
0211     dmi_id = dmi_first_match(dmi_platform_info);
0212     if (dmi_id)
0213         cell->swnode = (struct software_node *)dmi_id->driver_data;
0214 
0215     return 0;
0216 }
0217 
0218 static int intel_quark_gpio_setup(struct pci_dev *pdev)
0219 {
0220     struct mfd_cell *cell = &intel_quark_mfd_cells[MFD_GPIO_BAR];
0221     struct resource *res = intel_quark_gpio_res;
0222     int ret;
0223 
0224     res[INTEL_QUARK_IORES_MEM].start = pci_resource_start(pdev, MFD_GPIO_BAR);
0225     res[INTEL_QUARK_IORES_MEM].end = pci_resource_end(pdev, MFD_GPIO_BAR);
0226 
0227     res[INTEL_QUARK_IORES_IRQ].start = pci_irq_vector(pdev, 0);
0228     res[INTEL_QUARK_IORES_IRQ].end = pci_irq_vector(pdev, 0);
0229 
0230     ret = software_node_register_node_group(intel_quark_gpio_node_group);
0231     if (ret)
0232         return ret;
0233 
0234     cell->swnode = &intel_quark_gpio_controller_node;
0235     return 0;
0236 }
0237 
0238 static int intel_quark_mfd_probe(struct pci_dev *pdev,
0239                  const struct pci_device_id *id)
0240 {
0241     struct intel_quark_mfd *quark_mfd;
0242     int ret;
0243 
0244     ret = pcim_enable_device(pdev);
0245     if (ret)
0246         return ret;
0247 
0248     quark_mfd = devm_kzalloc(&pdev->dev, sizeof(*quark_mfd), GFP_KERNEL);
0249     if (!quark_mfd)
0250         return -ENOMEM;
0251 
0252     dev_set_drvdata(&pdev->dev, quark_mfd);
0253 
0254     ret = intel_quark_register_i2c_clk(&pdev->dev);
0255     if (ret)
0256         return ret;
0257 
0258     pci_set_master(pdev);
0259 
0260     /* This driver only requires 1 IRQ vector */
0261     ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
0262     if (ret < 0)
0263         goto err_unregister_i2c_clk;
0264 
0265     ret = intel_quark_i2c_setup(pdev);
0266     if (ret)
0267         goto err_free_irq_vectors;
0268 
0269     ret = intel_quark_gpio_setup(pdev);
0270     if (ret)
0271         goto err_free_irq_vectors;
0272 
0273     ret = mfd_add_devices(&pdev->dev, 0, intel_quark_mfd_cells,
0274                   ARRAY_SIZE(intel_quark_mfd_cells), NULL, 0,
0275                   NULL);
0276     if (ret)
0277         goto err_unregister_gpio_node_group;
0278 
0279     return 0;
0280 
0281 err_unregister_gpio_node_group:
0282     software_node_unregister_node_group(intel_quark_gpio_node_group);
0283 err_free_irq_vectors:
0284     pci_free_irq_vectors(pdev);
0285 err_unregister_i2c_clk:
0286     intel_quark_unregister_i2c_clk(&pdev->dev);
0287     return ret;
0288 }
0289 
0290 static void intel_quark_mfd_remove(struct pci_dev *pdev)
0291 {
0292     mfd_remove_devices(&pdev->dev);
0293     software_node_unregister_node_group(intel_quark_gpio_node_group);
0294     pci_free_irq_vectors(pdev);
0295     intel_quark_unregister_i2c_clk(&pdev->dev);
0296 }
0297 
0298 static struct pci_driver intel_quark_mfd_driver = {
0299     .name       = "intel_quark_mfd_i2c_gpio",
0300     .id_table   = intel_quark_mfd_ids,
0301     .probe      = intel_quark_mfd_probe,
0302     .remove     = intel_quark_mfd_remove,
0303 };
0304 
0305 module_pci_driver(intel_quark_mfd_driver);
0306 
0307 MODULE_AUTHOR("Raymond Tan <raymond.tan@intel.com>");
0308 MODULE_DESCRIPTION("Intel Quark MFD PCI driver for I2C & GPIO");
0309 MODULE_LICENSE("GPL v2");