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 */
octeon_i2c_int_enable(struct octeon_i2c * i2c)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 */
octeon_i2c_int_disable(struct octeon_i2c * i2c)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 */
octeon_i2c_int_enable78(struct octeon_i2c * i2c)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
__octeon_i2c_irq_disable(atomic_t * cnt,int irq)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 */
octeon_i2c_int_disable78(struct octeon_i2c * i2c)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 */
octeon_i2c_hlc_int_enable78(struct octeon_i2c * i2c)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 */
octeon_i2c_hlc_int_disable78(struct octeon_i2c * i2c)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 */
octeon_i2c_hlc_isr78(int irq,void * dev_id)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
octeon_i2c_hlc_int_enable(struct octeon_i2c * i2c)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
octeon_i2c_functionality(struct i2c_adapter * adap)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
octeon_i2c_probe(struct platform_device * pdev)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
octeon_i2c_remove(struct platform_device * pdev)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