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 dev_err(i2c->dev, "failed to enable clock\n"); 49 return err; 50 } 51 52 err = clk_set_rate(i2c->clk, 20000000); 53 if (err) { 54 dev_err(i2c->dev, "failed to set clock = 20Mhz\n"); 55 clk_disable_unprepare(i2c->clk); 56 return err; 57 } 58 59 writew(0, i2c->base + VIAI2C_REG_CR); 60 writew(MCR_APB_166M, i2c->base + VIAI2C_REG_MCR); 61 writew(VIAI2C_ISR_MASK_ALL, i2c->base + VIAI2C_REG_ISR); 62 writew(VIAI2C_IMR_ENABLE_ALL, i2c->base + VIAI2C_REG_IMR); 63 writew(VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR); 64 readw(i2c->base + VIAI2C_REG_CSR); /* read clear */ 65 writew(VIAI2C_ISR_MASK_ALL, i2c->base + VIAI2C_REG_ISR); 66 67 if (i2c->tcr == VIAI2C_TCR_FAST) 68 writew(SCL_TIMEOUT(128) | TR_HS, i2c->base + VIAI2C_REG_TR); 69 else 70 writew(SCL_TIMEOUT(128) | TR_STD, i2c->base + VIAI2C_REG_TR); 71 72 return 0; 73 } 74 75 static irqreturn_t wmt_i2c_isr(int irq, void *data) 76 { 77 struct viai2c *i2c = data; 78 u8 status; 79 80 /* save the status and write-clear it */ 81 status = readw(i2c->base + VIAI2C_REG_ISR); 82 writew(status, i2c->base + VIAI2C_REG_ISR); 83 84 i2c->ret = 0; 85 if (status & VIAI2C_ISR_NACK_ADDR) 86 i2c->ret = -EIO; 87 88 if (status & VIAI2C_ISR_SCL_TIMEOUT) 89 i2c->ret = -ETIMEDOUT; 90 91 if (!i2c->ret) 92 i2c->ret = viai2c_irq_xfer(i2c); 93 94 /* All the data has been successfully transferred or error occurred */ 95 if (i2c->ret) 96 complete(&i2c->complete); 97 98 return IRQ_HANDLED; 99 } 100 101 static int wmt_i2c_probe(struct platform_device *pdev) 102 { 103 struct device_node *np = pdev->dev.of_node; 104 struct viai2c *i2c; 105 struct i2c_adapter *adap; 106 int err; 107 u32 clk_rate; 108 109 err = viai2c_init(pdev, &i2c, VIAI2C_PLAT_WMT); 110 if (err) 111 return err; 112 113 i2c->irq = platform_get_irq(pdev, 0); 114 if (i2c->irq < 0) 115 return i2c->irq; 116 117 err = devm_request_irq(&pdev->dev, i2c->irq, wmt_i2c_isr, 118 0, pdev->name, i2c); 119 if (err) 120 return dev_err_probe(&pdev->dev, err, 121 "failed to request irq %i\n", i2c->irq); 122 123 i2c->clk = of_clk_get(np, 0); 124 if (IS_ERR(i2c->clk)) { 125 dev_err(&pdev->dev, "unable to request clock\n"); 126 return PTR_ERR(i2c->clk); 127 } 128 129 err = of_property_read_u32(np, "clock-frequency", &clk_rate); 130 if (!err && clk_rate == I2C_MAX_FAST_MODE_FREQ) 131 i2c->tcr = VIAI2C_TCR_FAST; 132 133 adap = &i2c->adapter; 134 i2c_set_adapdata(adap, i2c); 135 strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name)); 136 adap->owner = THIS_MODULE; 137 adap->algo = &wmt_i2c_algo; 138 adap->dev.parent = &pdev->dev; 139 adap->dev.of_node = pdev->dev.of_node; 140 141 err = wmt_i2c_reset_hardware(i2c); 142 if (err) { 143 dev_err(&pdev->dev, "error initializing hardware\n"); 144 return err; 145 } 146 147 err = i2c_add_adapter(adap); 148 if (err) 149 /* wmt_i2c_reset_hardware() enables i2c_dev->clk */ 150 clk_disable_unprepare(i2c->clk); 151 152 return err; 153 } 154 155 static void wmt_i2c_remove(struct platform_device *pdev) 156 { 157 struct viai2c *i2c = platform_get_drvdata(pdev); 158 159 /* Disable interrupts, clock and delete adapter */ 160 writew(0, i2c->base + VIAI2C_REG_IMR); 161 clk_disable_unprepare(i2c->clk); 162 i2c_del_adapter(&i2c->adapter); 163 } 164 165 static const struct of_device_id wmt_i2c_dt_ids[] = { 166 { .compatible = "wm,wm8505-i2c" }, 167 { /* Sentinel */ }, 168 }; 169 170 static struct platform_driver wmt_i2c_driver = { 171 .probe = wmt_i2c_probe, 172 .remove = wmt_i2c_remove, 173 .driver = { 174 .name = "wmt-i2c", 175 .of_match_table = wmt_i2c_dt_ids, 176 }, 177 }; 178 179 module_platform_driver(wmt_i2c_driver); 180 181 MODULE_DESCRIPTION("Wondermedia I2C controller driver"); 182 MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>"); 183 MODULE_LICENSE("GPL"); 184 MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids); 185