1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * (C) Copyright 2013 4 * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc 5 */ 6 7#include <common.h> 8#include <i2c.h> 9#include <dm.h> 10#include <regmap.h> 11#include <log.h> 12#include <asm/global_data.h> 13#include <asm/unaligned.h> 14#include <linux/bitops.h> 15#include <linux/delay.h> 16 17struct ihs_i2c_priv { 18 uint speed; 19 struct regmap *map; 20}; 21 22struct ihs_i2c_regs { 23 u16 interrupt_status; 24 u16 interrupt_enable_control; 25 u16 write_mailbox_ext; 26 u16 write_mailbox; 27 u16 read_mailbox_ext; 28 u16 read_mailbox; 29}; 30 31#define ihs_i2c_set(map, member, val) \ 32 regmap_set(map, struct ihs_i2c_regs, member, val) 33 34#define ihs_i2c_get(map, member, valp) \ 35 regmap_get(map, struct ihs_i2c_regs, member, valp) 36 37enum { 38 I2CINT_ERROR_EV = BIT(13), 39 I2CINT_TRANSMIT_EV = BIT(14), 40 I2CINT_RECEIVE_EV = BIT(15), 41}; 42 43enum { 44 I2CMB_READ = 0 << 10, 45 I2CMB_WRITE = 1 << 10, 46 I2CMB_1BYTE = 0 << 11, 47 I2CMB_2BYTE = 1 << 11, 48 I2CMB_DONT_HOLD_BUS = 0 << 13, 49 I2CMB_HOLD_BUS = 1 << 13, 50 I2CMB_NATIVE = 2 << 14, 51}; 52 53enum { 54 I2COP_WRITE = 0, 55 I2COP_READ = 1, 56}; 57 58static int wait_for_int(struct udevice *dev, int read) 59{ 60 u16 val; 61 uint ctr = 0; 62 struct ihs_i2c_priv *priv = dev_get_priv(dev); 63 64 ihs_i2c_get(priv->map, interrupt_status, &val); 65 /* Wait until error or receive/transmit interrupt was raised */ 66 while (!(val & (I2CINT_ERROR_EV 67 | (read ? I2CINT_RECEIVE_EV : I2CINT_TRANSMIT_EV)))) { 68 udelay(10); 69 if (ctr++ > 5000) { 70 debug("%s: timed out\n", __func__); 71 return -ETIMEDOUT; 72 } 73 ihs_i2c_get(priv->map, interrupt_status, &val); 74 } 75 76 return (val & I2CINT_ERROR_EV) ? -EIO : 0; 77} 78 79static int ihs_i2c_transfer(struct udevice *dev, uchar chip, 80 uchar *buffer, int len, int read, bool is_last) 81{ 82 u16 val; 83 u16 data; 84 int res; 85 struct ihs_i2c_priv *priv = dev_get_priv(dev); 86 87 /* Clear interrupt status */ 88 data = I2CINT_ERROR_EV | I2CINT_RECEIVE_EV | I2CINT_TRANSMIT_EV; 89 ihs_i2c_set(priv->map, interrupt_status, data); 90 ihs_i2c_get(priv->map, interrupt_status, &val); 91 92 /* If we want to write and have data, write the bytes to the mailbox */ 93 if (!read && len) { 94 val = buffer[0]; 95 96 if (len > 1) 97 val |= buffer[1] << 8; 98 ihs_i2c_set(priv->map, write_mailbox_ext, val); 99 } 100 101 data = I2CMB_NATIVE 102 | (read ? 0 : I2CMB_WRITE) 103 | (chip << 1) 104 | ((len > 1) ? I2CMB_2BYTE : 0) 105 | (is_last ? 0 : I2CMB_HOLD_BUS); 106 107 ihs_i2c_set(priv->map, write_mailbox, data); 108 109 res = wait_for_int(dev, read); 110 if (res) { 111 if (res == -ETIMEDOUT) 112 debug("%s: time out while waiting for event\n", __func__); 113 114 return res; 115 } 116 117 /* If we want to read, get the bytes from the mailbox */ 118 if (read) { 119 ihs_i2c_get(priv->map, read_mailbox_ext, &val); 120 buffer[0] = val & 0xff; 121 if (len > 1) 122 buffer[1] = val >> 8; 123 } 124 125 return 0; 126} 127 128static int ihs_i2c_send_buffer(struct udevice *dev, uchar chip, u8 *data, int len, bool hold_bus, int read) 129{ 130 int res; 131 132 while (len) { 133 int transfer = min(len, 2); 134 bool is_last = len <= transfer; 135 136 res = ihs_i2c_transfer(dev, chip, data, transfer, read, 137 hold_bus ? false : is_last); 138 if (res) 139 return res; 140 141 data += transfer; 142 len -= transfer; 143 } 144 145 return 0; 146} 147 148static int ihs_i2c_address(struct udevice *dev, uchar chip, u8 *addr, int alen, 149 bool hold_bus) 150{ 151 return ihs_i2c_send_buffer(dev, chip, addr, alen, hold_bus, I2COP_WRITE); 152} 153 154static int ihs_i2c_access(struct udevice *dev, uchar chip, u8 *addr, 155 int alen, uchar *buffer, int len, int read) 156{ 157 int res; 158 159 /* Don't hold the bus if length of data to send/receive is zero */ 160 if (len <= 0) 161 return -EINVAL; 162 163 res = ihs_i2c_address(dev, chip, addr, alen, len); 164 if (res) 165 return res; 166 167 return ihs_i2c_send_buffer(dev, chip, buffer, len, false, read); 168} 169 170int ihs_i2c_probe(struct udevice *bus) 171{ 172 struct ihs_i2c_priv *priv = dev_get_priv(bus); 173 174 regmap_init_mem(dev_ofnode(bus), &priv->map); 175 176 return 0; 177} 178 179static int ihs_i2c_set_bus_speed(struct udevice *bus, uint speed) 180{ 181 struct ihs_i2c_priv *priv = dev_get_priv(bus); 182 183 if (speed != priv->speed && priv->speed != 0) 184 return -EINVAL; 185 186 priv->speed = speed; 187 188 return 0; 189} 190 191static int ihs_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs) 192{ 193 struct i2c_msg *dmsg, *omsg, dummy; 194 195 memset(&dummy, 0, sizeof(struct i2c_msg)); 196 197 /* We expect either two messages (one with an offset and one with the 198 * actual data) or one message (just data) 199 */ 200 if (nmsgs > 2 || nmsgs == 0) { 201 debug("%s: Only one or two messages are supported\n", __func__); 202 return -ENOTSUPP; 203 } 204 205 omsg = nmsgs == 1 ? &dummy : msg; 206 dmsg = nmsgs == 1 ? msg : msg + 1; 207 208 if (dmsg->flags & I2C_M_RD) 209 return ihs_i2c_access(bus, dmsg->addr, omsg->buf, 210 omsg->len, dmsg->buf, dmsg->len, 211 I2COP_READ); 212 else 213 return ihs_i2c_access(bus, dmsg->addr, omsg->buf, 214 omsg->len, dmsg->buf, dmsg->len, 215 I2COP_WRITE); 216} 217 218static int ihs_i2c_probe_chip(struct udevice *bus, u32 chip_addr, 219 u32 chip_flags) 220{ 221 uchar buffer[2]; 222 int res; 223 224 res = ihs_i2c_transfer(bus, chip_addr, buffer, 0, I2COP_READ, true); 225 if (res) 226 return res; 227 228 return 0; 229} 230 231static const struct dm_i2c_ops ihs_i2c_ops = { 232 .xfer = ihs_i2c_xfer, 233 .probe_chip = ihs_i2c_probe_chip, 234 .set_bus_speed = ihs_i2c_set_bus_speed, 235}; 236 237static const struct udevice_id ihs_i2c_ids[] = { 238 { .compatible = "gdsys,ihs_i2cmaster", }, 239 { /* sentinel */ } 240}; 241 242U_BOOT_DRIVER(i2c_ihs) = { 243 .name = "i2c_ihs", 244 .id = UCLASS_I2C, 245 .of_match = ihs_i2c_ids, 246 .probe = ihs_i2c_probe, 247 .priv_auto = sizeof(struct ihs_i2c_priv), 248 .ops = &ihs_i2c_ops, 249}; 250