root/drivers/i2c/busses/i2c-thunderx-pcidrv.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. thunder_i2c_int_enable
  2. thunder_i2c_int_disable
  3. thunder_i2c_hlc_int_enable
  4. thunder_i2c_hlc_int_disable
  5. thunderx_i2c_functionality
  6. thunder_i2c_clock_enable
  7. thunder_i2c_clock_disable
  8. thunder_i2c_smbus_setup_of
  9. thunder_i2c_smbus_setup
  10. thunder_i2c_smbus_remove
  11. thunder_i2c_probe_pci
  12. thunder_i2c_remove_pci

   1 /*
   2  * Cavium ThunderX i2c driver.
   3  *
   4  * Copyright (C) 2015,2016 Cavium Inc.
   5  * Authors: Fred Martin <fmartin@caviumnetworks.com>
   6  *          Jan Glauber <jglauber@cavium.com>
   7  *
   8  * This file is licensed under the terms of the GNU General Public
   9  * License version 2. This program is licensed "as is" without any
  10  * warranty of any kind, whether express or implied.
  11  */
  12 
  13 #include <linux/acpi.h>
  14 #include <linux/clk.h>
  15 #include <linux/delay.h>
  16 #include <linux/i2c.h>
  17 #include <linux/i2c-smbus.h>
  18 #include <linux/interrupt.h>
  19 #include <linux/kernel.h>
  20 #include <linux/module.h>
  21 #include <linux/of_irq.h>
  22 #include <linux/pci.h>
  23 
  24 #include "i2c-octeon-core.h"
  25 
  26 #define DRV_NAME "i2c-thunderx"
  27 
  28 #define PCI_DEVICE_ID_THUNDER_TWSI      0xa012
  29 
  30 #define SYS_FREQ_DEFAULT                700000000
  31 
  32 #define TWSI_INT_ENA_W1C                0x1028
  33 #define TWSI_INT_ENA_W1S                0x1030
  34 
  35 /*
  36  * Enable the CORE interrupt.
  37  * The interrupt will be asserted when there is non-STAT_IDLE state in the
  38  * SW_TWSI_EOP_TWSI_STAT register.
  39  */
  40 static void thunder_i2c_int_enable(struct octeon_i2c *i2c)
  41 {
  42         octeon_i2c_writeq_flush(TWSI_INT_CORE_INT,
  43                                 i2c->twsi_base + TWSI_INT_ENA_W1S);
  44 }
  45 
  46 /*
  47  * Disable the CORE interrupt.
  48  */
  49 static void thunder_i2c_int_disable(struct octeon_i2c *i2c)
  50 {
  51         octeon_i2c_writeq_flush(TWSI_INT_CORE_INT,
  52                                 i2c->twsi_base + TWSI_INT_ENA_W1C);
  53 }
  54 
  55 static void thunder_i2c_hlc_int_enable(struct octeon_i2c *i2c)
  56 {
  57         octeon_i2c_writeq_flush(TWSI_INT_ST_INT | TWSI_INT_TS_INT,
  58                                 i2c->twsi_base + TWSI_INT_ENA_W1S);
  59 }
  60 
  61 static void thunder_i2c_hlc_int_disable(struct octeon_i2c *i2c)
  62 {
  63         octeon_i2c_writeq_flush(TWSI_INT_ST_INT | TWSI_INT_TS_INT,
  64                                 i2c->twsi_base + TWSI_INT_ENA_W1C);
  65 }
  66 
  67 static u32 thunderx_i2c_functionality(struct i2c_adapter *adap)
  68 {
  69         return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) |
  70                I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_SMBUS_BLOCK_PROC_CALL;
  71 }
  72 
  73 static const struct i2c_algorithm thunderx_i2c_algo = {
  74         .master_xfer = octeon_i2c_xfer,
  75         .functionality = thunderx_i2c_functionality,
  76 };
  77 
  78 static const struct i2c_adapter thunderx_i2c_ops = {
  79         .owner  = THIS_MODULE,
  80         .name   = "ThunderX adapter",
  81         .algo   = &thunderx_i2c_algo,
  82 };
  83 
  84 static void thunder_i2c_clock_enable(struct device *dev, struct octeon_i2c *i2c)
  85 {
  86         int ret;
  87 
  88         if (acpi_disabled) {
  89                 /* DT */
  90                 i2c->clk = clk_get(dev, NULL);
  91                 if (IS_ERR(i2c->clk)) {
  92                         i2c->clk = NULL;
  93                         goto skip;
  94                 }
  95 
  96                 ret = clk_prepare_enable(i2c->clk);
  97                 if (ret)
  98                         goto skip;
  99                 i2c->sys_freq = clk_get_rate(i2c->clk);
 100         } else {
 101                 /* ACPI */
 102                 device_property_read_u32(dev, "sclk", &i2c->sys_freq);
 103         }
 104 
 105 skip:
 106         if (!i2c->sys_freq)
 107                 i2c->sys_freq = SYS_FREQ_DEFAULT;
 108 }
 109 
 110 static void thunder_i2c_clock_disable(struct device *dev, struct clk *clk)
 111 {
 112         if (!clk)
 113                 return;
 114         clk_disable_unprepare(clk);
 115         clk_put(clk);
 116 }
 117 
 118 static int thunder_i2c_smbus_setup_of(struct octeon_i2c *i2c,
 119                                       struct device_node *node)
 120 {
 121         if (!node)
 122                 return -EINVAL;
 123 
 124         i2c->alert_data.irq = irq_of_parse_and_map(node, 0);
 125         if (!i2c->alert_data.irq)
 126                 return -EINVAL;
 127 
 128         i2c->ara = i2c_setup_smbus_alert(&i2c->adap, &i2c->alert_data);
 129         if (!i2c->ara)
 130                 return -ENODEV;
 131         return 0;
 132 }
 133 
 134 static int thunder_i2c_smbus_setup(struct octeon_i2c *i2c,
 135                                    struct device_node *node)
 136 {
 137         /* TODO: ACPI support */
 138         if (!acpi_disabled)
 139                 return -EOPNOTSUPP;
 140 
 141         return thunder_i2c_smbus_setup_of(i2c, node);
 142 }
 143 
 144 static void thunder_i2c_smbus_remove(struct octeon_i2c *i2c)
 145 {
 146         i2c_unregister_device(i2c->ara);
 147 }
 148 
 149 static int thunder_i2c_probe_pci(struct pci_dev *pdev,
 150                                  const struct pci_device_id *ent)
 151 {
 152         struct device *dev = &pdev->dev;
 153         struct octeon_i2c *i2c;
 154         int ret;
 155 
 156         i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
 157         if (!i2c)
 158                 return -ENOMEM;
 159 
 160         i2c->roff.sw_twsi = 0x1000;
 161         i2c->roff.twsi_int = 0x1010;
 162         i2c->roff.sw_twsi_ext = 0x1018;
 163 
 164         i2c->dev = dev;
 165         pci_set_drvdata(pdev, i2c);
 166         ret = pcim_enable_device(pdev);
 167         if (ret)
 168                 return ret;
 169 
 170         ret = pci_request_regions(pdev, DRV_NAME);
 171         if (ret)
 172                 return ret;
 173 
 174         i2c->twsi_base = pcim_iomap(pdev, 0, pci_resource_len(pdev, 0));
 175         if (!i2c->twsi_base)
 176                 return -EINVAL;
 177 
 178         thunder_i2c_clock_enable(dev, i2c);
 179         ret = device_property_read_u32(dev, "clock-frequency", &i2c->twsi_freq);
 180         if (ret)
 181                 i2c->twsi_freq = 100000;
 182 
 183         init_waitqueue_head(&i2c->queue);
 184 
 185         i2c->int_enable = thunder_i2c_int_enable;
 186         i2c->int_disable = thunder_i2c_int_disable;
 187         i2c->hlc_int_enable = thunder_i2c_hlc_int_enable;
 188         i2c->hlc_int_disable = thunder_i2c_hlc_int_disable;
 189 
 190         ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX);
 191         if (ret < 0)
 192                 goto error;
 193 
 194         ret = devm_request_irq(dev, pci_irq_vector(pdev, 0), octeon_i2c_isr, 0,
 195                                DRV_NAME, i2c);
 196         if (ret)
 197                 goto error;
 198 
 199         ret = octeon_i2c_init_lowlevel(i2c);
 200         if (ret)
 201                 goto error;
 202 
 203         octeon_i2c_set_clock(i2c);
 204 
 205         i2c->adap = thunderx_i2c_ops;
 206         i2c->adap.retries = 5;
 207         i2c->adap.class = I2C_CLASS_HWMON;
 208         i2c->adap.bus_recovery_info = &octeon_i2c_recovery_info;
 209         i2c->adap.dev.parent = dev;
 210         i2c->adap.dev.of_node = pdev->dev.of_node;
 211         snprintf(i2c->adap.name, sizeof(i2c->adap.name),
 212                  "Cavium ThunderX i2c adapter at %s", dev_name(dev));
 213         i2c_set_adapdata(&i2c->adap, i2c);
 214 
 215         ret = i2c_add_adapter(&i2c->adap);
 216         if (ret)
 217                 goto error;
 218 
 219         dev_info(i2c->dev, "Probed. Set system clock to %u\n", i2c->sys_freq);
 220 
 221         ret = thunder_i2c_smbus_setup(i2c, pdev->dev.of_node);
 222         if (ret)
 223                 dev_info(dev, "SMBUS alert not active on this bus\n");
 224 
 225         return 0;
 226 
 227 error:
 228         thunder_i2c_clock_disable(dev, i2c->clk);
 229         return ret;
 230 }
 231 
 232 static void thunder_i2c_remove_pci(struct pci_dev *pdev)
 233 {
 234         struct octeon_i2c *i2c = pci_get_drvdata(pdev);
 235 
 236         thunder_i2c_smbus_remove(i2c);
 237         thunder_i2c_clock_disable(&pdev->dev, i2c->clk);
 238         i2c_del_adapter(&i2c->adap);
 239 }
 240 
 241 static const struct pci_device_id thunder_i2c_pci_id_table[] = {
 242         { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVICE_ID_THUNDER_TWSI) },
 243         { 0, }
 244 };
 245 
 246 MODULE_DEVICE_TABLE(pci, thunder_i2c_pci_id_table);
 247 
 248 static struct pci_driver thunder_i2c_pci_driver = {
 249         .name           = DRV_NAME,
 250         .id_table       = thunder_i2c_pci_id_table,
 251         .probe          = thunder_i2c_probe_pci,
 252         .remove         = thunder_i2c_remove_pci,
 253 };
 254 
 255 module_pci_driver(thunder_i2c_pci_driver);
 256 
 257 MODULE_LICENSE("GPL");
 258 MODULE_AUTHOR("Fred Martin <fmartin@caviumnetworks.com>");
 259 MODULE_DESCRIPTION("I2C-Bus adapter for Cavium ThunderX SOC");

/* [<][>][^][v][top][bottom][index][help] */