168af512aSJan Glauber /* 268af512aSJan Glauber * (C) Copyright 2009-2010 368af512aSJan Glauber * Nokia Siemens Networks, michael.lawnick.ext@nsn.com 468af512aSJan Glauber * 568af512aSJan Glauber * Portions Copyright (C) 2010 - 2016 Cavium, Inc. 668af512aSJan Glauber * 768af512aSJan Glauber * This is a driver for the i2c adapter in Cavium Networks' OCTEON processors. 868af512aSJan Glauber * 968af512aSJan Glauber * This file is licensed under the terms of the GNU General Public 1068af512aSJan Glauber * License version 2. This program is licensed "as is" without any 1168af512aSJan Glauber * warranty of any kind, whether express or implied. 1268af512aSJan Glauber */ 1368af512aSJan Glauber 1468af512aSJan Glauber #include <linux/atomic.h> 15caa505f2SJan Glauber #include <linux/delay.h> 16caa505f2SJan Glauber #include <linux/i2c.h> 1768af512aSJan Glauber #include <linux/interrupt.h> 18caa505f2SJan Glauber #include <linux/io.h> 1968af512aSJan Glauber #include <linux/kernel.h> 2068af512aSJan Glauber #include <linux/module.h> 21caa505f2SJan Glauber #include <linux/of.h> 22caa505f2SJan Glauber #include <linux/platform_device.h> 2368af512aSJan Glauber #include <linux/sched.h> 2468af512aSJan Glauber #include <linux/slab.h> 2568af512aSJan Glauber 2668af512aSJan Glauber #include <asm/octeon/octeon.h> 27ad83665bSJan Glauber #include "i2c-octeon-core.h" 2868af512aSJan Glauber 2968af512aSJan Glauber #define DRV_NAME "i2c-octeon" 3068af512aSJan Glauber 3168af512aSJan Glauber /** 3268af512aSJan Glauber * octeon_i2c_int_enable - enable the CORE interrupt 3368af512aSJan Glauber * @i2c: The struct octeon_i2c 3468af512aSJan Glauber * 3568af512aSJan Glauber * The interrupt will be asserted when there is non-STAT_IDLE state in 3668af512aSJan Glauber * the SW_TWSI_EOP_TWSI_STAT register. 3768af512aSJan Glauber */ 3868af512aSJan Glauber static void octeon_i2c_int_enable(struct octeon_i2c *i2c) 3968af512aSJan Glauber { 4068af512aSJan Glauber octeon_i2c_write_int(i2c, TWSI_INT_CORE_EN); 4168af512aSJan Glauber } 4268af512aSJan Glauber 4368af512aSJan Glauber /* disable the CORE interrupt */ 4468af512aSJan Glauber static void octeon_i2c_int_disable(struct octeon_i2c *i2c) 4568af512aSJan Glauber { 4668af512aSJan Glauber /* clear TS/ST/IFLG events */ 4768af512aSJan Glauber octeon_i2c_write_int(i2c, 0); 4868af512aSJan Glauber } 4968af512aSJan Glauber 5068af512aSJan Glauber /** 5168af512aSJan Glauber * octeon_i2c_int_enable78 - enable the CORE interrupt 5268af512aSJan Glauber * @i2c: The struct octeon_i2c 5368af512aSJan Glauber * 5468af512aSJan Glauber * The interrupt will be asserted when there is non-STAT_IDLE state in the 5568af512aSJan Glauber * SW_TWSI_EOP_TWSI_STAT register. 5668af512aSJan Glauber */ 5768af512aSJan Glauber static void octeon_i2c_int_enable78(struct octeon_i2c *i2c) 5868af512aSJan Glauber { 5968af512aSJan Glauber atomic_inc_return(&i2c->int_enable_cnt); 6068af512aSJan Glauber enable_irq(i2c->irq); 6168af512aSJan Glauber } 6268af512aSJan Glauber 6368af512aSJan Glauber static void __octeon_i2c_irq_disable(atomic_t *cnt, int irq) 6468af512aSJan Glauber { 6568af512aSJan Glauber int count; 6668af512aSJan Glauber 6768af512aSJan Glauber /* 6868af512aSJan Glauber * The interrupt can be disabled in two places, but we only 6968af512aSJan Glauber * want to make the disable_irq_nosync() call once, so keep 7068af512aSJan Glauber * track with the atomic variable. 7168af512aSJan Glauber */ 7268af512aSJan Glauber count = atomic_dec_if_positive(cnt); 7368af512aSJan Glauber if (count >= 0) 7468af512aSJan Glauber disable_irq_nosync(irq); 7568af512aSJan Glauber } 7668af512aSJan Glauber 7768af512aSJan Glauber /* disable the CORE interrupt */ 7868af512aSJan Glauber static void octeon_i2c_int_disable78(struct octeon_i2c *i2c) 7968af512aSJan Glauber { 8068af512aSJan Glauber __octeon_i2c_irq_disable(&i2c->int_enable_cnt, i2c->irq); 8168af512aSJan Glauber } 8268af512aSJan Glauber 8368af512aSJan Glauber /** 8468af512aSJan Glauber * octeon_i2c_hlc_int_enable78 - enable the ST interrupt 8568af512aSJan Glauber * @i2c: The struct octeon_i2c 8668af512aSJan Glauber * 8768af512aSJan Glauber * The interrupt will be asserted when there is non-STAT_IDLE state in 8868af512aSJan Glauber * the SW_TWSI_EOP_TWSI_STAT register. 8968af512aSJan Glauber */ 9068af512aSJan Glauber static void octeon_i2c_hlc_int_enable78(struct octeon_i2c *i2c) 9168af512aSJan Glauber { 9268af512aSJan Glauber atomic_inc_return(&i2c->hlc_int_enable_cnt); 9368af512aSJan Glauber enable_irq(i2c->hlc_irq); 9468af512aSJan Glauber } 9568af512aSJan Glauber 9668af512aSJan Glauber /* disable the ST interrupt */ 9768af512aSJan Glauber static void octeon_i2c_hlc_int_disable78(struct octeon_i2c *i2c) 9868af512aSJan Glauber { 9968af512aSJan Glauber __octeon_i2c_irq_disable(&i2c->hlc_int_enable_cnt, i2c->hlc_irq); 10068af512aSJan Glauber } 10168af512aSJan Glauber 10268af512aSJan Glauber /* HLC interrupt service routine */ 10368af512aSJan Glauber static irqreturn_t octeon_i2c_hlc_isr78(int irq, void *dev_id) 10468af512aSJan Glauber { 10568af512aSJan Glauber struct octeon_i2c *i2c = dev_id; 10668af512aSJan Glauber 10768af512aSJan Glauber i2c->hlc_int_disable(i2c); 10868af512aSJan Glauber wake_up(&i2c->queue); 10968af512aSJan Glauber 11068af512aSJan Glauber return IRQ_HANDLED; 11168af512aSJan Glauber } 11268af512aSJan Glauber 11368af512aSJan Glauber static void octeon_i2c_hlc_int_enable(struct octeon_i2c *i2c) 11468af512aSJan Glauber { 11568af512aSJan Glauber octeon_i2c_write_int(i2c, TWSI_INT_ST_EN); 11668af512aSJan Glauber } 11768af512aSJan Glauber 11868af512aSJan Glauber static u32 octeon_i2c_functionality(struct i2c_adapter *adap) 11968af512aSJan Glauber { 12068af512aSJan Glauber return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) | 12168af512aSJan Glauber I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_SMBUS_BLOCK_PROC_CALL; 12268af512aSJan Glauber } 12368af512aSJan Glauber 12468af512aSJan Glauber static const struct i2c_algorithm octeon_i2c_algo = { 12568af512aSJan Glauber .master_xfer = octeon_i2c_xfer, 12668af512aSJan Glauber .functionality = octeon_i2c_functionality, 12768af512aSJan Glauber }; 12868af512aSJan Glauber 129329430ccSBhumika Goyal static const struct i2c_adapter octeon_i2c_ops = { 13068af512aSJan Glauber .owner = THIS_MODULE, 13168af512aSJan Glauber .name = "OCTEON adapter", 13268af512aSJan Glauber .algo = &octeon_i2c_algo, 13368af512aSJan Glauber }; 13468af512aSJan Glauber 13568af512aSJan Glauber static int octeon_i2c_probe(struct platform_device *pdev) 13668af512aSJan Glauber { 13768af512aSJan Glauber struct device_node *node = pdev->dev.of_node; 13868af512aSJan Glauber int irq, result = 0, hlc_irq = 0; 13968af512aSJan Glauber struct octeon_i2c *i2c; 14068af512aSJan Glauber bool cn78xx_style; 14168af512aSJan Glauber 14268af512aSJan Glauber cn78xx_style = of_device_is_compatible(node, "cavium,octeon-7890-twsi"); 14368af512aSJan Glauber if (cn78xx_style) { 14468af512aSJan Glauber hlc_irq = platform_get_irq(pdev, 0); 14568af512aSJan Glauber if (hlc_irq < 0) 14668af512aSJan Glauber return hlc_irq; 14768af512aSJan Glauber 14868af512aSJan Glauber irq = platform_get_irq(pdev, 2); 14968af512aSJan Glauber if (irq < 0) 15068af512aSJan Glauber return irq; 15168af512aSJan Glauber } else { 15268af512aSJan Glauber /* All adaptors have an irq. */ 15368af512aSJan Glauber irq = platform_get_irq(pdev, 0); 15468af512aSJan Glauber if (irq < 0) 15568af512aSJan Glauber return irq; 15668af512aSJan Glauber } 15768af512aSJan Glauber 15868af512aSJan Glauber i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); 15968af512aSJan Glauber if (!i2c) { 16068af512aSJan Glauber result = -ENOMEM; 16168af512aSJan Glauber goto out; 16268af512aSJan Glauber } 16368af512aSJan Glauber i2c->dev = &pdev->dev; 16468af512aSJan Glauber 16597d97004SJan Glauber i2c->roff.sw_twsi = 0x00; 16697d97004SJan Glauber i2c->roff.twsi_int = 0x10; 16797d97004SJan Glauber i2c->roff.sw_twsi_ext = 0x18; 16897d97004SJan Glauber 169e0442d76SDejin Zheng i2c->twsi_base = devm_platform_ioremap_resource(pdev, 0); 17068af512aSJan Glauber if (IS_ERR(i2c->twsi_base)) { 17168af512aSJan Glauber result = PTR_ERR(i2c->twsi_base); 17268af512aSJan Glauber goto out; 17368af512aSJan Glauber } 17468af512aSJan Glauber 17568af512aSJan Glauber /* 17668af512aSJan Glauber * "clock-rate" is a legacy binding, the official binding is 17768af512aSJan Glauber * "clock-frequency". Try the official one first and then 17868af512aSJan Glauber * fall back if it doesn't exist. 17968af512aSJan Glauber */ 18068af512aSJan Glauber if (of_property_read_u32(node, "clock-frequency", &i2c->twsi_freq) && 18168af512aSJan Glauber of_property_read_u32(node, "clock-rate", &i2c->twsi_freq)) { 18268af512aSJan Glauber dev_err(i2c->dev, 18368af512aSJan Glauber "no I2C 'clock-rate' or 'clock-frequency' property\n"); 18468af512aSJan Glauber result = -ENXIO; 18568af512aSJan Glauber goto out; 18668af512aSJan Glauber } 18768af512aSJan Glauber 18868af512aSJan Glauber i2c->sys_freq = octeon_get_io_clock_rate(); 18968af512aSJan Glauber 19068af512aSJan Glauber init_waitqueue_head(&i2c->queue); 19168af512aSJan Glauber 19268af512aSJan Glauber i2c->irq = irq; 19368af512aSJan Glauber 19468af512aSJan Glauber if (cn78xx_style) { 19568af512aSJan Glauber i2c->hlc_irq = hlc_irq; 19668af512aSJan Glauber 19768af512aSJan Glauber i2c->int_enable = octeon_i2c_int_enable78; 19868af512aSJan Glauber i2c->int_disable = octeon_i2c_int_disable78; 19968af512aSJan Glauber i2c->hlc_int_enable = octeon_i2c_hlc_int_enable78; 20068af512aSJan Glauber i2c->hlc_int_disable = octeon_i2c_hlc_int_disable78; 20168af512aSJan Glauber 20268af512aSJan Glauber irq_set_status_flags(i2c->irq, IRQ_NOAUTOEN); 20368af512aSJan Glauber irq_set_status_flags(i2c->hlc_irq, IRQ_NOAUTOEN); 20468af512aSJan Glauber 20568af512aSJan Glauber result = devm_request_irq(&pdev->dev, i2c->hlc_irq, 20668af512aSJan Glauber octeon_i2c_hlc_isr78, 0, 20768af512aSJan Glauber DRV_NAME, i2c); 20868af512aSJan Glauber if (result < 0) { 20968af512aSJan Glauber dev_err(i2c->dev, "failed to attach interrupt\n"); 21068af512aSJan Glauber goto out; 21168af512aSJan Glauber } 21268af512aSJan Glauber } else { 21368af512aSJan Glauber i2c->int_enable = octeon_i2c_int_enable; 21468af512aSJan Glauber i2c->int_disable = octeon_i2c_int_disable; 21568af512aSJan Glauber i2c->hlc_int_enable = octeon_i2c_hlc_int_enable; 21668af512aSJan Glauber i2c->hlc_int_disable = octeon_i2c_int_disable; 21768af512aSJan Glauber } 21868af512aSJan Glauber 21968af512aSJan Glauber result = devm_request_irq(&pdev->dev, i2c->irq, 22068af512aSJan Glauber octeon_i2c_isr, 0, DRV_NAME, i2c); 22168af512aSJan Glauber if (result < 0) { 22268af512aSJan Glauber dev_err(i2c->dev, "failed to attach interrupt\n"); 22368af512aSJan Glauber goto out; 22468af512aSJan Glauber } 22568af512aSJan Glauber 22668af512aSJan Glauber if (OCTEON_IS_MODEL(OCTEON_CN38XX)) 22768af512aSJan Glauber i2c->broken_irq_check = true; 22868af512aSJan Glauber 22968af512aSJan Glauber result = octeon_i2c_init_lowlevel(i2c); 23068af512aSJan Glauber if (result) { 23168af512aSJan Glauber dev_err(i2c->dev, "init low level failed\n"); 23268af512aSJan Glauber goto out; 23368af512aSJan Glauber } 23468af512aSJan Glauber 23568af512aSJan Glauber octeon_i2c_set_clock(i2c); 23668af512aSJan Glauber 23768af512aSJan Glauber i2c->adap = octeon_i2c_ops; 23868af512aSJan Glauber i2c->adap.timeout = msecs_to_jiffies(2); 23968af512aSJan Glauber i2c->adap.retries = 5; 24068af512aSJan Glauber i2c->adap.bus_recovery_info = &octeon_i2c_recovery_info; 24168af512aSJan Glauber i2c->adap.dev.parent = &pdev->dev; 24268af512aSJan Glauber i2c->adap.dev.of_node = node; 24368af512aSJan Glauber i2c_set_adapdata(&i2c->adap, i2c); 24468af512aSJan Glauber platform_set_drvdata(pdev, i2c); 24568af512aSJan Glauber 24668af512aSJan Glauber result = i2c_add_adapter(&i2c->adap); 24768af512aSJan Glauber if (result < 0) 24868af512aSJan Glauber goto out; 24968af512aSJan Glauber dev_info(i2c->dev, "probed\n"); 25068af512aSJan Glauber return 0; 25168af512aSJan Glauber 25268af512aSJan Glauber out: 25368af512aSJan Glauber return result; 25468af512aSJan Glauber }; 25568af512aSJan Glauber 256*e190a0c3SUwe Kleine-König static void octeon_i2c_remove(struct platform_device *pdev) 25768af512aSJan Glauber { 25868af512aSJan Glauber struct octeon_i2c *i2c = platform_get_drvdata(pdev); 25968af512aSJan Glauber 26068af512aSJan Glauber i2c_del_adapter(&i2c->adap); 26168af512aSJan Glauber }; 26268af512aSJan Glauber 26368af512aSJan Glauber static const struct of_device_id octeon_i2c_match[] = { 26468af512aSJan Glauber { .compatible = "cavium,octeon-3860-twsi", }, 26568af512aSJan Glauber { .compatible = "cavium,octeon-7890-twsi", }, 26668af512aSJan Glauber {}, 26768af512aSJan Glauber }; 26868af512aSJan Glauber MODULE_DEVICE_TABLE(of, octeon_i2c_match); 26968af512aSJan Glauber 27068af512aSJan Glauber static struct platform_driver octeon_i2c_driver = { 27168af512aSJan Glauber .probe = octeon_i2c_probe, 272*e190a0c3SUwe Kleine-König .remove_new = octeon_i2c_remove, 27368af512aSJan Glauber .driver = { 27468af512aSJan Glauber .name = DRV_NAME, 27568af512aSJan Glauber .of_match_table = octeon_i2c_match, 27668af512aSJan Glauber }, 27768af512aSJan Glauber }; 27868af512aSJan Glauber 27968af512aSJan Glauber module_platform_driver(octeon_i2c_driver); 28068af512aSJan Glauber 28168af512aSJan Glauber MODULE_AUTHOR("Michael Lawnick <michael.lawnick.ext@nsn.com>"); 28268af512aSJan Glauber MODULE_DESCRIPTION("I2C-Bus adapter for Cavium OCTEON processors"); 28368af512aSJan Glauber MODULE_LICENSE("GPL"); 284