1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Wondermedia I2C Controller Driver 4 * 5 * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz> 6 * 7 * Derived from GPLv2+ licensed source: 8 * - Copyright (C) 2008 WonderMedia Technologies, Inc. 9 */ 10 11 #include <linux/clk.h> 12 #include <linux/of.h> 13 #include <linux/of_address.h> 14 #include "i2c-viai2c-common.h" 15 16 #define REG_SLAVE_CR 0x10 17 #define REG_SLAVE_SR 0x12 18 #define REG_SLAVE_ISR 0x14 19 #define REG_SLAVE_IMR 0x16 20 #define REG_SLAVE_DR 0x18 21 #define REG_SLAVE_TR 0x1A 22 23 /* REG_TR */ 24 #define SCL_TIMEOUT(x) (((x) & 0xFF) << 8) 25 #define TR_STD 0x0064 26 #define TR_HS 0x0019 27 28 /* REG_MCR */ 29 #define MCR_APB_96M 7 30 #define MCR_APB_166M 12 31 32 static u32 wmt_i2c_func(struct i2c_adapter *adap) 33 { 34 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART; 35 } 36 37 static const struct i2c_algorithm wmt_i2c_algo = { 38 .xfer = viai2c_xfer, 39 .functionality = wmt_i2c_func, 40 }; 41 42 static int wmt_i2c_reset_hardware(struct viai2c *i2c) 43 { 44 int err; 45 46 err = clk_prepare_enable(i2c->clk); 47 if (err) 48 return dev_err_probe(i2c->dev, err, "failed to enable clock\n"); 49 50 err = clk_set_rate(i2c->clk, 20000000); 51 if (err) { 52 clk_disable_unprepare(i2c->clk); 53 return dev_err_probe(i2c->dev, err, "failed to set clock = 20Mhz\n"); 54 } 55 56 writew(0, i2c->base + VIAI2C_REG_CR); 57 writew(MCR_APB_166M, i2c->base + VIAI2C_REG_MCR); 58 writew(VIAI2C_ISR_MASK_ALL, i2c->base + VIAI2C_REG_ISR); 59 writew(VIAI2C_IMR_ENABLE_ALL, i2c->base + VIAI2C_REG_IMR); 60 writew(VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR); 61 readw(i2c->base + VIAI2C_REG_CSR); /* read clear */ 62 writew(VIAI2C_ISR_MASK_ALL, i2c->base + VIAI2C_REG_ISR); 63 64 if (i2c->tcr == VIAI2C_TCR_FAST) 65 writew(SCL_TIMEOUT(128) | TR_HS, i2c->base + VIAI2C_REG_TR); 66 else 67 writew(SCL_TIMEOUT(128) | TR_STD, i2c->base + VIAI2C_REG_TR); 68 69 return 0; 70 } 71 72 static irqreturn_t wmt_i2c_isr(int irq, void *data) 73 { 74 struct viai2c *i2c = data; 75 u8 status; 76 77 /* save the status and write-clear it */ 78 status = readw(i2c->base + VIAI2C_REG_ISR); 79 writew(status, i2c->base + VIAI2C_REG_ISR); 80 81 i2c->ret = 0; 82 if (status & VIAI2C_ISR_NACK_ADDR) 83 i2c->ret = -EIO; 84 85 if (status & VIAI2C_ISR_SCL_TIMEOUT) 86 i2c->ret = -ETIMEDOUT; 87 88 if (!i2c->ret) 89 i2c->ret = viai2c_irq_xfer(i2c); 90 91 /* All the data has been successfully transferred or error occurred */ 92 if (i2c->ret) 93 complete(&i2c->complete); 94 95 return IRQ_HANDLED; 96 } 97 98 static int wmt_i2c_probe(struct platform_device *pdev) 99 { 100 struct device_node *np = pdev->dev.of_node; 101 struct viai2c *i2c; 102 struct i2c_adapter *adap; 103 int err; 104 u32 clk_rate; 105 106 err = viai2c_init(pdev, &i2c, VIAI2C_PLAT_WMT); 107 if (err) 108 return err; 109 110 i2c->irq = platform_get_irq(pdev, 0); 111 if (i2c->irq < 0) 112 return i2c->irq; 113 114 err = devm_request_irq(&pdev->dev, i2c->irq, wmt_i2c_isr, 115 0, pdev->name, i2c); 116 if (err) 117 return dev_err_probe(&pdev->dev, err, 118 "failed to request irq %i\n", i2c->irq); 119 120 i2c->clk = of_clk_get(np, 0); 121 if (IS_ERR(i2c->clk)) 122 return dev_err_probe(&pdev->dev, PTR_ERR(i2c->clk), 123 "unable to request clock\n"); 124 125 err = of_property_read_u32(np, "clock-frequency", &clk_rate); 126 if (!err && clk_rate == I2C_MAX_FAST_MODE_FREQ) 127 i2c->tcr = VIAI2C_TCR_FAST; 128 129 adap = &i2c->adapter; 130 i2c_set_adapdata(adap, i2c); 131 strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name)); 132 adap->owner = THIS_MODULE; 133 adap->algo = &wmt_i2c_algo; 134 adap->dev.parent = &pdev->dev; 135 adap->dev.of_node = pdev->dev.of_node; 136 137 err = wmt_i2c_reset_hardware(i2c); 138 if (err) 139 return err; 140 141 err = i2c_add_adapter(adap); 142 if (err) 143 /* wmt_i2c_reset_hardware() enables i2c_dev->clk */ 144 clk_disable_unprepare(i2c->clk); 145 146 return err; 147 } 148 149 static void wmt_i2c_remove(struct platform_device *pdev) 150 { 151 struct viai2c *i2c = platform_get_drvdata(pdev); 152 153 /* Disable interrupts, clock and delete adapter */ 154 writew(0, i2c->base + VIAI2C_REG_IMR); 155 clk_disable_unprepare(i2c->clk); 156 i2c_del_adapter(&i2c->adapter); 157 } 158 159 static const struct of_device_id wmt_i2c_dt_ids[] = { 160 { .compatible = "wm,wm8505-i2c" }, 161 { /* Sentinel */ }, 162 }; 163 164 static struct platform_driver wmt_i2c_driver = { 165 .probe = wmt_i2c_probe, 166 .remove = wmt_i2c_remove, 167 .driver = { 168 .name = "wmt-i2c", 169 .of_match_table = wmt_i2c_dt_ids, 170 }, 171 }; 172 173 module_platform_driver(wmt_i2c_driver); 174 175 MODULE_DESCRIPTION("Wondermedia I2C controller driver"); 176 MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>"); 177 MODULE_LICENSE("GPL"); 178 MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids); 179