Blame view
drivers/i2c/busses/i2c-eg20t.c
24.5 KB
e9bc8fa5d i2c-eg20t: add dr... |
1 |
/* |
8956dc102 i2c-eg20t: Change... |
2 |
* Copyright (C) 2011 LAPIS Semiconductor Co., Ltd. |
e9bc8fa5d i2c-eg20t: add dr... |
3 4 5 6 7 8 9 10 11 |
* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. |
e9bc8fa5d i2c-eg20t: add dr... |
12 13 14 15 16 |
*/ #include <linux/module.h> #include <linux/kernel.h> #include <linux/delay.h> |
e9bc8fa5d i2c-eg20t: add dr... |
17 18 19 20 21 22 23 24 25 26 |
#include <linux/errno.h> #include <linux/i2c.h> #include <linux/fs.h> #include <linux/io.h> #include <linux/types.h> #include <linux/interrupt.h> #include <linux/jiffies.h> #include <linux/pci.h> #include <linux/mutex.h> #include <linux/ktime.h> |
6dbc2f35a i2c-eg20t: includ... |
27 |
#include <linux/slab.h> |
e9bc8fa5d i2c-eg20t: add dr... |
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
#define PCH_EVENT_SET 0 /* I2C Interrupt Event Set Status */ #define PCH_EVENT_NONE 1 /* I2C Interrupt Event Clear Status */ #define PCH_MAX_CLK 100000 /* Maximum Clock speed in MHz */ #define PCH_BUFFER_MODE_ENABLE 0x0002 /* flag for Buffer mode enable */ #define PCH_EEPROM_SW_RST_MODE_ENABLE 0x0008 /* EEPROM SW RST enable flag */ #define PCH_I2CSADR 0x00 /* I2C slave address register */ #define PCH_I2CCTL 0x04 /* I2C control register */ #define PCH_I2CSR 0x08 /* I2C status register */ #define PCH_I2CDR 0x0C /* I2C data register */ #define PCH_I2CMON 0x10 /* I2C bus monitor register */ #define PCH_I2CBC 0x14 /* I2C bus transfer rate setup counter */ #define PCH_I2CMOD 0x18 /* I2C mode register */ #define PCH_I2CBUFSLV 0x1C /* I2C buffer mode slave address register */ #define PCH_I2CBUFSUB 0x20 /* I2C buffer mode subaddress register */ #define PCH_I2CBUFFOR 0x24 /* I2C buffer mode format register */ #define PCH_I2CBUFCTL 0x28 /* I2C buffer mode control register */ #define PCH_I2CBUFMSK 0x2C /* I2C buffer mode interrupt mask register */ #define PCH_I2CBUFSTA 0x30 /* I2C buffer mode status register */ #define PCH_I2CBUFLEV 0x34 /* I2C buffer mode level register */ #define PCH_I2CESRFOR 0x38 /* EEPROM software reset mode format register */ #define PCH_I2CESRCTL 0x3C /* EEPROM software reset mode ctrl register */ #define PCH_I2CESRMSK 0x40 /* EEPROM software reset mode */ #define PCH_I2CESRSTA 0x44 /* EEPROM software reset mode status register */ #define PCH_I2CTMR 0x48 /* I2C timer register */ #define PCH_I2CSRST 0xFC /* I2C reset register */ #define PCH_I2CNF 0xF8 /* I2C noise filter register */ #define BUS_IDLE_TIMEOUT 20 #define PCH_I2CCTL_I2CMEN 0x0080 #define TEN_BIT_ADDR_DEFAULT 0xF000 #define TEN_BIT_ADDR_MASK 0xF0 #define PCH_START 0x0020 |
c249ac207 i2c-eg20t: Fix 10... |
62 |
#define PCH_RESTART 0x0004 |
e9bc8fa5d i2c-eg20t: add dr... |
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
#define PCH_ESR_START 0x0001 #define PCH_BUFF_START 0x1 #define PCH_REPSTART 0x0004 #define PCH_ACK 0x0008 #define PCH_GETACK 0x0001 #define CLR_REG 0x0 #define I2C_RD 0x1 #define I2CMCF_BIT 0x0080 #define I2CMIF_BIT 0x0002 #define I2CMAL_BIT 0x0010 #define I2CBMFI_BIT 0x0001 #define I2CBMAL_BIT 0x0002 #define I2CBMNA_BIT 0x0004 #define I2CBMTO_BIT 0x0008 #define I2CBMIS_BIT 0x0010 #define I2CESRFI_BIT 0X0001 #define I2CESRTO_BIT 0x0002 #define I2CESRFIIE_BIT 0x1 #define I2CESRTOIE_BIT 0x2 #define I2CBMDZ_BIT 0x0040 #define I2CBMAG_BIT 0x0020 #define I2CMBB_BIT 0x0020 #define BUFFER_MODE_MASK (I2CBMFI_BIT | I2CBMAL_BIT | I2CBMNA_BIT | \ I2CBMTO_BIT | I2CBMIS_BIT) #define I2C_ADDR_MSK 0xFF #define I2C_MSB_2B_MSK 0x300 #define FAST_MODE_CLK 400 #define FAST_MODE_EN 0x0001 #define SUB_ADDR_LEN_MAX 4 #define BUF_LEN_MAX 32 #define PCH_BUFFER_MODE 0x1 #define EEPROM_SW_RST_MODE 0x0002 #define NORMAL_INTR_ENBL 0x0300 #define EEPROM_RST_INTR_ENBL (I2CESRFIIE_BIT | I2CESRTOIE_BIT) #define EEPROM_RST_INTR_DISBL 0x0 #define BUFFER_MODE_INTR_ENBL 0x001F #define BUFFER_MODE_INTR_DISBL 0x0 #define NORMAL_MODE 0x0 #define BUFFER_MODE 0x1 #define EEPROM_SR_MODE 0x2 #define I2C_TX_MODE 0x0010 #define PCH_BUF_TX 0xFFF7 #define PCH_BUF_RD 0x0008 #define I2C_ERROR_MASK (I2CESRTO_EVENT | I2CBMIS_EVENT | I2CBMTO_EVENT | \ I2CBMNA_EVENT | I2CBMAL_EVENT | I2CMAL_EVENT) #define I2CMAL_EVENT 0x0001 #define I2CMCF_EVENT 0x0002 #define I2CBMFI_EVENT 0x0004 #define I2CBMAL_EVENT 0x0008 #define I2CBMNA_EVENT 0x0010 #define I2CBMTO_EVENT 0x0020 #define I2CBMIS_EVENT 0x0040 #define I2CESRFI_EVENT 0x0080 #define I2CESRTO_EVENT 0x0100 #define PCI_DEVICE_ID_PCH_I2C 0x8817 #define pch_dbg(adap, fmt, arg...) \ dev_dbg(adap->pch_adapter.dev.parent, "%s :" fmt, __func__, ##arg) #define pch_err(adap, fmt, arg...) \ dev_err(adap->pch_adapter.dev.parent, "%s :" fmt, __func__, ##arg) #define pch_pci_err(pdev, fmt, arg...) \ dev_err(&pdev->dev, "%s :" fmt, __func__, ##arg) #define pch_pci_dbg(pdev, fmt, arg...) \ dev_dbg(&pdev->dev, "%s :" fmt, __func__, ##arg) |
173442f27 i2c-eg20t: suppor... |
130 131 132 |
/* Set the number of I2C instance max Intel EG20T PCH : 1ch |
8956dc102 i2c-eg20t: Change... |
133 134 |
LAPIS Semiconductor ML7213 IOH : 2ch LAPIS Semiconductor ML7831 IOH : 1ch |
173442f27 i2c-eg20t: suppor... |
135 136 |
*/ #define PCH_I2C_MAX_DEV 2 |
e9bc8fa5d i2c-eg20t: add dr... |
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
/** * struct i2c_algo_pch_data - for I2C driver functionalities * @pch_adapter: stores the reference to i2c_adapter structure * @p_adapter_info: stores the reference to adapter_info structure * @pch_base_address: specifies the remapped base address * @pch_buff_mode_en: specifies if buffer mode is enabled * @pch_event_flag: specifies occurrence of interrupt events * @pch_i2c_xfer_in_progress: specifies whether the transfer is completed */ struct i2c_algo_pch_data { struct i2c_adapter pch_adapter; struct adapter_info *p_adapter_info; void __iomem *pch_base_address; int pch_buff_mode_en; u32 pch_event_flag; bool pch_i2c_xfer_in_progress; }; /** * struct adapter_info - This structure holds the adapter information for the PCH i2c controller * @pch_data: stores a list of i2c_algo_pch_data * @pch_i2c_suspended: specifies whether the system is suspended or not * perhaps with more lines and words. |
173442f27 i2c-eg20t: suppor... |
161 |
* @ch_num: specifies the number of i2c instance |
e9bc8fa5d i2c-eg20t: add dr... |
162 163 164 165 |
* * pch_data has as many elements as maximum I2C channels */ struct adapter_info { |
173442f27 i2c-eg20t: suppor... |
166 |
struct i2c_algo_pch_data pch_data[PCH_I2C_MAX_DEV]; |
e9bc8fa5d i2c-eg20t: add dr... |
167 |
bool pch_i2c_suspended; |
173442f27 i2c-eg20t: suppor... |
168 |
int ch_num; |
e9bc8fa5d i2c-eg20t: add dr... |
169 170 171 172 173 174 175 |
}; static int pch_i2c_speed = 100; /* I2C bus speed in Kbps */ static int pch_clk = 50000; /* specifies I2C clock speed in KHz */ static wait_queue_head_t pch_event; static DEFINE_MUTEX(pch_mutex); |
8956dc102 i2c-eg20t: Change... |
176 |
/* Definition for ML7213 by LAPIS Semiconductor */ |
173442f27 i2c-eg20t: suppor... |
177 178 |
#define PCI_VENDOR_ID_ROHM 0x10DB #define PCI_DEVICE_ID_ML7213_I2C 0x802D |
efbe0f27c i2c-eg20t: Suppor... |
179 |
#define PCI_DEVICE_ID_ML7223_I2C 0x8010 |
c3f4661f5 i2c-eg20t: Suppor... |
180 |
#define PCI_DEVICE_ID_ML7831_I2C 0x8817 |
173442f27 i2c-eg20t: suppor... |
181 |
|
392debf11 i2c: remove DEFIN... |
182 |
static const struct pci_device_id pch_pcidev_id[] = { |
173442f27 i2c-eg20t: suppor... |
183 184 |
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C), 1, }, { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, }, |
efbe0f27c i2c-eg20t: Suppor... |
185 |
{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), 1, }, |
c3f4661f5 i2c-eg20t: Suppor... |
186 |
{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7831_I2C), 1, }, |
e9bc8fa5d i2c-eg20t: add dr... |
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
{0,} }; static irqreturn_t pch_i2c_handler(int irq, void *pData); static inline void pch_setbit(void __iomem *addr, u32 offset, u32 bitmask) { u32 val; val = ioread32(addr + offset); val |= bitmask; iowrite32(val, addr + offset); } static inline void pch_clrbit(void __iomem *addr, u32 offset, u32 bitmask) { u32 val; val = ioread32(addr + offset); val &= (~bitmask); iowrite32(val, addr + offset); } /** * pch_i2c_init() - hardware initialization of I2C module * @adap: Pointer to struct i2c_algo_pch_data. */ static void pch_i2c_init(struct i2c_algo_pch_data *adap) { void __iomem *p = adap->pch_base_address; u32 pch_i2cbc; u32 pch_i2ctmr; u32 reg_value; /* reset I2C controller */ iowrite32(0x01, p + PCH_I2CSRST); msleep(20); iowrite32(0x0, p + PCH_I2CSRST); /* Initialize I2C registers */ iowrite32(0x21, p + PCH_I2CNF); |
173442f27 i2c-eg20t: suppor... |
226 |
pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_I2CCTL_I2CMEN); |
e9bc8fa5d i2c-eg20t: add dr... |
227 228 229 230 231 232 233 234 235 236 237 238 239 |
if (pch_i2c_speed != 400) pch_i2c_speed = 100; reg_value = PCH_I2CCTL_I2CMEN; if (pch_i2c_speed == FAST_MODE_CLK) { reg_value |= FAST_MODE_EN; pch_dbg(adap, "Fast mode enabled "); } if (pch_clk > PCH_MAX_CLK) pch_clk = 62500; |
ff35e8b18 i2c-eg20t: modifi... |
240 |
pch_i2cbc = (pch_clk + (pch_i2c_speed * 4)) / (pch_i2c_speed * 8); |
e9bc8fa5d i2c-eg20t: add dr... |
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
/* Set transfer speed in I2CBC */ iowrite32(pch_i2cbc, p + PCH_I2CBC); pch_i2ctmr = (pch_clk) / 8; iowrite32(pch_i2ctmr, p + PCH_I2CTMR); reg_value |= NORMAL_INTR_ENBL; /* Enable interrupts in normal mode */ iowrite32(reg_value, p + PCH_I2CCTL); pch_dbg(adap, "I2CCTL=%x pch_i2cbc=%x pch_i2ctmr=%x Enable interrupts ", ioread32(p + PCH_I2CCTL), pch_i2cbc, pch_i2ctmr); init_waitqueue_head(&pch_event); } |
e9bc8fa5d i2c-eg20t: add dr... |
257 258 259 |
/** * pch_i2c_wait_for_bus_idle() - check the status of bus. * @adap: Pointer to struct i2c_algo_pch_data. |
0836c8090 i2c-eg20t: Rework... |
260 |
* @timeout: waiting time counter (ms). |
e9bc8fa5d i2c-eg20t: add dr... |
261 262 |
*/ static s32 pch_i2c_wait_for_bus_idle(struct i2c_algo_pch_data *adap, |
173442f27 i2c-eg20t: suppor... |
263 |
s32 timeout) |
e9bc8fa5d i2c-eg20t: add dr... |
264 265 |
{ void __iomem *p = adap->pch_base_address; |
0836c8090 i2c-eg20t: Rework... |
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 |
int schedule = 0; unsigned long end = jiffies + msecs_to_jiffies(timeout); while (ioread32(p + PCH_I2CSR) & I2CMBB_BIT) { if (time_after(jiffies, end)) { pch_dbg(adap, "I2CSR = %x ", ioread32(p + PCH_I2CSR)); pch_err(adap, "%s: Timeout Error.return%d ", __func__, -ETIME); pch_i2c_init(adap); return -ETIME; } if (!schedule) /* Retry after some usecs */ udelay(5); else /* Wait a bit more without consuming CPU */ usleep_range(20, 1000); schedule = 1; } |
e9bc8fa5d i2c-eg20t: add dr... |
290 |
|
0836c8090 i2c-eg20t: Rework... |
291 |
return 0; |
e9bc8fa5d i2c-eg20t: add dr... |
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
} /** * pch_i2c_start() - Generate I2C start condition in normal mode. * @adap: Pointer to struct i2c_algo_pch_data. * * Generate I2C start condition in normal mode by setting I2CCTL.I2CMSTA to 1. */ static void pch_i2c_start(struct i2c_algo_pch_data *adap) { void __iomem *p = adap->pch_base_address; pch_dbg(adap, "I2CCTL = %x ", ioread32(p + PCH_I2CCTL)); pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_START); } /** |
e9bc8fa5d i2c-eg20t: add dr... |
309 310 311 312 313 314 315 316 317 318 319 |
* pch_i2c_stop() - generate stop condition in normal mode. * @adap: Pointer to struct i2c_algo_pch_data. */ static void pch_i2c_stop(struct i2c_algo_pch_data *adap) { void __iomem *p = adap->pch_base_address; pch_dbg(adap, "I2CCTL = %x ", ioread32(p + PCH_I2CCTL)); /* clear the start bit */ pch_clrbit(adap->pch_base_address, PCH_I2CCTL, PCH_START); } |
5cc056327 i2c-eg20t: add he... |
320 321 |
static int pch_i2c_wait_for_check_xfer(struct i2c_algo_pch_data *adap) { |
199bca2a7 i2c-eg20t: Merge ... |
322 |
long ret; |
5e47eec00 i2c: i2c-eg20t: d... |
323 |
void __iomem *p = adap->pch_base_address; |
199bca2a7 i2c-eg20t: Merge ... |
324 325 326 327 328 329 330 331 332 333 334 335 336 |
ret = wait_event_timeout(pch_event, (adap->pch_event_flag != 0), msecs_to_jiffies(1000)); if (!ret) { pch_err(adap, "%s:wait-event timeout ", __func__); adap->pch_event_flag = 0; pch_i2c_stop(adap); pch_i2c_init(adap); return -ETIMEDOUT; } if (adap->pch_event_flag & I2C_ERROR_MASK) { |
5cc056327 i2c-eg20t: add he... |
337 338 |
pch_err(adap, "Lost Arbitration "); |
199bca2a7 i2c-eg20t: Merge ... |
339 |
adap->pch_event_flag = 0; |
5cc056327 i2c-eg20t: add he... |
340 341 342 343 |
pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMAL_BIT); pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMIF_BIT); pch_i2c_init(adap); return -EAGAIN; |
199bca2a7 i2c-eg20t: Merge ... |
344 345 346 |
} adap->pch_event_flag = 0; |
5e47eec00 i2c: i2c-eg20t: d... |
347 348 349 350 |
if (ioread32(p + PCH_I2CSR) & PCH_GETACK) { pch_dbg(adap, "Receive NACK for slave address setting "); return -ENXIO; |
5cc056327 i2c-eg20t: add he... |
351 352 353 354 |
} return 0; } |
e9bc8fa5d i2c-eg20t: add dr... |
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 |
/** * pch_i2c_repstart() - generate repeated start condition in normal mode * @adap: Pointer to struct i2c_algo_pch_data. */ static void pch_i2c_repstart(struct i2c_algo_pch_data *adap) { void __iomem *p = adap->pch_base_address; pch_dbg(adap, "I2CCTL = %x ", ioread32(p + PCH_I2CCTL)); pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_REPSTART); } /** * pch_i2c_writebytes() - write data to I2C bus in normal mode * @i2c_adap: Pointer to the struct i2c_adapter. * @last: specifies whether last message or not. * In the case of compound mode it will be 1 for last message, * otherwise 0. * @first: specifies whether first message or not. * 1 for first message otherwise 0. */ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, u32 last, u32 first) { struct i2c_algo_pch_data *adap = i2c_adap->algo_data; u8 *buf; u32 length; u32 addr; u32 addr_2_msb; u32 addr_8_lsb; s32 wrcount; |
12bd31465 i2c-eg20t: Separa... |
386 |
s32 rtn; |
e9bc8fa5d i2c-eg20t: add dr... |
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 |
void __iomem *p = adap->pch_base_address; length = msgs->len; buf = msgs->buf; addr = msgs->addr; /* enable master tx */ pch_setbit(adap->pch_base_address, PCH_I2CCTL, I2C_TX_MODE); pch_dbg(adap, "I2CCTL = %x msgs->len = %d ", ioread32(p + PCH_I2CCTL), length); if (first) { if (pch_i2c_wait_for_bus_idle(adap, BUS_IDLE_TIMEOUT) == -ETIME) return -ETIME; } if (msgs->flags & I2C_M_TEN) { |
c249ac207 i2c-eg20t: Fix 10... |
406 |
addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7) & 0x06; |
e9bc8fa5d i2c-eg20t: add dr... |
407 408 409 |
iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR); if (first) pch_i2c_start(adap); |
12bd31465 i2c-eg20t: Separa... |
410 |
|
5cc056327 i2c-eg20t: add he... |
411 412 413 414 415 416 |
rtn = pch_i2c_wait_for_check_xfer(adap); if (rtn) return rtn; addr_8_lsb = (addr & I2C_ADDR_MSK); iowrite32(addr_8_lsb, p + PCH_I2CDR); |
e9bc8fa5d i2c-eg20t: add dr... |
417 418 419 420 421 422 |
} else { /* set 7 bit slave address and R/W bit as 0 */ iowrite32(addr << 1, p + PCH_I2CDR); if (first) pch_i2c_start(adap); } |
5cc056327 i2c-eg20t: add he... |
423 424 425 |
rtn = pch_i2c_wait_for_check_xfer(adap); if (rtn) return rtn; |
e9bc8fa5d i2c-eg20t: add dr... |
426 |
|
12bd31465 i2c-eg20t: Separa... |
427 428 429 430 431 |
for (wrcount = 0; wrcount < length; ++wrcount) { /* write buffer value to I2C data register */ iowrite32(buf[wrcount], p + PCH_I2CDR); pch_dbg(adap, "writing %x to Data register ", buf[wrcount]); |
e9bc8fa5d i2c-eg20t: add dr... |
432 |
|
5cc056327 i2c-eg20t: add he... |
433 434 435 436 437 438 |
rtn = pch_i2c_wait_for_check_xfer(adap); if (rtn) return rtn; pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMCF_BIT); pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMIF_BIT); |
12bd31465 i2c-eg20t: Separa... |
439 |
} |
e9bc8fa5d i2c-eg20t: add dr... |
440 |
|
12bd31465 i2c-eg20t: Separa... |
441 442 |
/* check if this is the last message */ if (last) |
e9bc8fa5d i2c-eg20t: add dr... |
443 |
pch_i2c_stop(adap); |
12bd31465 i2c-eg20t: Separa... |
444 445 |
else pch_i2c_repstart(adap); |
e9bc8fa5d i2c-eg20t: add dr... |
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 |
pch_dbg(adap, "return=%d ", wrcount); return wrcount; } /** * pch_i2c_sendack() - send ACK * @adap: Pointer to struct i2c_algo_pch_data. */ static void pch_i2c_sendack(struct i2c_algo_pch_data *adap) { void __iomem *p = adap->pch_base_address; pch_dbg(adap, "I2CCTL = %x ", ioread32(p + PCH_I2CCTL)); pch_clrbit(adap->pch_base_address, PCH_I2CCTL, PCH_ACK); } /** * pch_i2c_sendnack() - send NACK * @adap: Pointer to struct i2c_algo_pch_data. */ static void pch_i2c_sendnack(struct i2c_algo_pch_data *adap) { void __iomem *p = adap->pch_base_address; pch_dbg(adap, "I2CCTL = %x ", ioread32(p + PCH_I2CCTL)); pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_ACK); } /** |
c249ac207 i2c-eg20t: Fix 10... |
478 479 480 481 482 483 484 485 486 487 488 489 490 491 |
* pch_i2c_restart() - Generate I2C restart condition in normal mode. * @adap: Pointer to struct i2c_algo_pch_data. * * Generate I2C restart condition in normal mode by setting I2CCTL.I2CRSTA. */ static void pch_i2c_restart(struct i2c_algo_pch_data *adap) { void __iomem *p = adap->pch_base_address; pch_dbg(adap, "I2CCTL = %x ", ioread32(p + PCH_I2CCTL)); pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_RESTART); } /** |
e9bc8fa5d i2c-eg20t: add dr... |
492 493 494 495 496 497 |
* pch_i2c_readbytes() - read data from I2C bus in normal mode. * @i2c_adap: Pointer to the struct i2c_adapter. * @msgs: Pointer to i2c_msg structure. * @last: specifies whether last message or not. * @first: specifies whether first message or not. */ |
173442f27 i2c-eg20t: suppor... |
498 499 |
static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, u32 last, u32 first) |
e9bc8fa5d i2c-eg20t: add dr... |
500 501 502 503 504 505 506 507 |
{ struct i2c_algo_pch_data *adap = i2c_adap->algo_data; u8 *buf; u32 count; u32 length; u32 addr; u32 addr_2_msb; |
c249ac207 i2c-eg20t: Fix 10... |
508 |
u32 addr_8_lsb; |
e9bc8fa5d i2c-eg20t: add dr... |
509 |
void __iomem *p = adap->pch_base_address; |
12bd31465 i2c-eg20t: Separa... |
510 |
s32 rtn; |
e9bc8fa5d i2c-eg20t: add dr... |
511 512 513 514 515 516 517 518 519 520 521 522 523 524 |
length = msgs->len; buf = msgs->buf; addr = msgs->addr; /* enable master reception */ pch_clrbit(adap->pch_base_address, PCH_I2CCTL, I2C_TX_MODE); if (first) { if (pch_i2c_wait_for_bus_idle(adap, BUS_IDLE_TIMEOUT) == -ETIME) return -ETIME; } if (msgs->flags & I2C_M_TEN) { |
c249ac207 i2c-eg20t: Fix 10... |
525 |
addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7); |
e9bc8fa5d i2c-eg20t: add dr... |
526 |
iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR); |
c249ac207 i2c-eg20t: Fix 10... |
527 528 |
if (first) pch_i2c_start(adap); |
e9bc8fa5d i2c-eg20t: add dr... |
529 |
|
5cc056327 i2c-eg20t: add he... |
530 531 532 533 534 535 |
rtn = pch_i2c_wait_for_check_xfer(adap); if (rtn) return rtn; addr_8_lsb = (addr & I2C_ADDR_MSK); iowrite32(addr_8_lsb, p + PCH_I2CDR); |
c249ac207 i2c-eg20t: Fix 10... |
536 |
pch_i2c_restart(adap); |
5cc056327 i2c-eg20t: add he... |
537 538 539 540 541 542 543 |
rtn = pch_i2c_wait_for_check_xfer(adap); if (rtn) return rtn; addr_2_msb |= I2C_RD; iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR); |
e9bc8fa5d i2c-eg20t: add dr... |
544 545 546 547 548 549 550 551 552 |
} else { /* 7 address bits + R/W bit */ addr = (((addr) << 1) | (I2C_RD)); iowrite32(addr, p + PCH_I2CDR); } /* check if it is the first message */ if (first) pch_i2c_start(adap); |
5cc056327 i2c-eg20t: add he... |
553 554 555 |
rtn = pch_i2c_wait_for_check_xfer(adap); if (rtn) return rtn; |
e9bc8fa5d i2c-eg20t: add dr... |
556 |
|
12bd31465 i2c-eg20t: Separa... |
557 558 559 |
if (length == 0) { pch_i2c_stop(adap); ioread32(p + PCH_I2CDR); /* Dummy read needs */ |
e9bc8fa5d i2c-eg20t: add dr... |
560 |
|
12bd31465 i2c-eg20t: Separa... |
561 562 563 564 565 |
count = length; } else { int read_index; int loop; pch_i2c_sendack(adap); |
e9bc8fa5d i2c-eg20t: add dr... |
566 |
|
12bd31465 i2c-eg20t: Separa... |
567 568 569 |
/* Dummy read */ for (loop = 1, read_index = 0; loop < length; loop++) { buf[read_index] = ioread32(p + PCH_I2CDR); |
e9bc8fa5d i2c-eg20t: add dr... |
570 |
|
12bd31465 i2c-eg20t: Separa... |
571 572 |
if (loop != 1) read_index++; |
e9bc8fa5d i2c-eg20t: add dr... |
573 |
|
5cc056327 i2c-eg20t: add he... |
574 575 576 |
rtn = pch_i2c_wait_for_check_xfer(adap); if (rtn) return rtn; |
12bd31465 i2c-eg20t: Separa... |
577 |
} /* end for */ |
e9bc8fa5d i2c-eg20t: add dr... |
578 |
|
12bd31465 i2c-eg20t: Separa... |
579 |
pch_i2c_sendnack(adap); |
e9bc8fa5d i2c-eg20t: add dr... |
580 |
|
12bd31465 i2c-eg20t: Separa... |
581 |
buf[read_index] = ioread32(p + PCH_I2CDR); /* Read final - 1 */ |
e9bc8fa5d i2c-eg20t: add dr... |
582 |
|
12bd31465 i2c-eg20t: Separa... |
583 584 |
if (length != 1) read_index++; |
e9bc8fa5d i2c-eg20t: add dr... |
585 |
|
5cc056327 i2c-eg20t: add he... |
586 587 588 |
rtn = pch_i2c_wait_for_check_xfer(adap); if (rtn) return rtn; |
12bd31465 i2c-eg20t: Separa... |
589 590 591 592 593 594 595 596 |
if (last) pch_i2c_stop(adap); else pch_i2c_repstart(adap); buf[read_index++] = ioread32(p + PCH_I2CDR); /* Read Final */ count = read_index; |
e9bc8fa5d i2c-eg20t: add dr... |
597 598 599 600 601 602 |
} return count; } /** |
173442f27 i2c-eg20t: suppor... |
603 |
* pch_i2c_cb() - Interrupt handler Call back function |
e9bc8fa5d i2c-eg20t: add dr... |
604 605 |
* @adap: Pointer to struct i2c_algo_pch_data. */ |
173442f27 i2c-eg20t: suppor... |
606 |
static void pch_i2c_cb(struct i2c_algo_pch_data *adap) |
e9bc8fa5d i2c-eg20t: add dr... |
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 |
{ u32 sts; void __iomem *p = adap->pch_base_address; sts = ioread32(p + PCH_I2CSR); sts &= (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT); if (sts & I2CMAL_BIT) adap->pch_event_flag |= I2CMAL_EVENT; if (sts & I2CMCF_BIT) adap->pch_event_flag |= I2CMCF_EVENT; /* clear the applicable bits */ pch_clrbit(adap->pch_base_address, PCH_I2CSR, sts); pch_dbg(adap, "PCH_I2CSR = %x ", ioread32(p + PCH_I2CSR)); wake_up(&pch_event); } /** * pch_i2c_handler() - interrupt handler for the PCH I2C controller * @irq: irq number. * @pData: cookie passed back to the handler function. */ static irqreturn_t pch_i2c_handler(int irq, void *pData) { |
173442f27 i2c-eg20t: suppor... |
635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 |
u32 reg_val; int flag; int i; struct adapter_info *adap_info = pData; void __iomem *p; u32 mode; for (i = 0, flag = 0; i < adap_info->ch_num; i++) { p = adap_info->pch_data[i].pch_base_address; mode = ioread32(p + PCH_I2CMOD); mode &= BUFFER_MODE | EEPROM_SR_MODE; if (mode != NORMAL_MODE) { pch_err(adap_info->pch_data, "I2C-%d mode(%d) is not supported ", mode, i); continue; } reg_val = ioread32(p + PCH_I2CSR); if (reg_val & (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT)) { pch_i2c_cb(&adap_info->pch_data[i]); flag = 1; } |
e9bc8fa5d i2c-eg20t: add dr... |
657 |
} |
173442f27 i2c-eg20t: suppor... |
658 |
return flag ? IRQ_HANDLED : IRQ_NONE; |
e9bc8fa5d i2c-eg20t: add dr... |
659 660 661 662 663 664 665 666 667 |
} /** * pch_i2c_xfer() - Reading adnd writing data through I2C bus * @i2c_adap: Pointer to the struct i2c_adapter. * @msgs: Pointer to i2c_msg structure. * @num: number of messages. */ static s32 pch_i2c_xfer(struct i2c_adapter *i2c_adap, |
173442f27 i2c-eg20t: suppor... |
668 |
struct i2c_msg *msgs, s32 num) |
e9bc8fa5d i2c-eg20t: add dr... |
669 670 671 672 |
{ struct i2c_msg *pmsg; u32 i = 0; u32 status; |
e9bc8fa5d i2c-eg20t: add dr... |
673 674 675 676 677 678 |
s32 ret; struct i2c_algo_pch_data *adap = i2c_adap->algo_data; ret = mutex_lock_interruptible(&pch_mutex); if (ret) |
772ae99c5 i2c: eg20t: pass ... |
679 |
return ret; |
e9bc8fa5d i2c-eg20t: add dr... |
680 681 682 683 684 685 686 687 688 689 690 |
if (adap->p_adapter_info->pch_i2c_suspended) { mutex_unlock(&pch_mutex); return -EBUSY; } pch_dbg(adap, "adap->p_adapter_info->pch_i2c_suspended is %d ", adap->p_adapter_info->pch_i2c_suspended); /* transfer not completed */ adap->pch_i2c_xfer_in_progress = true; |
07e729ce8 i2c-eg20t : Fix t... |
691 |
for (i = 0; i < num && ret >= 0; i++) { |
7a9c42ccc i2c-eg20t : Suppo... |
692 693 694 695 696 697 |
pmsg = &msgs[i]; pmsg->flags |= adap->pch_buff_mode_en; status = pmsg->flags; pch_dbg(adap, "After invoking I2C_MODE_SEL :flag= 0x%x ", status); |
7a9c42ccc i2c-eg20t : Suppo... |
698 699 700 701 702 703 704 705 |
if ((status & (I2C_M_RD)) != false) { ret = pch_i2c_readbytes(i2c_adap, pmsg, (i + 1 == num), (i == 0)); } else { ret = pch_i2c_writebytes(i2c_adap, pmsg, (i + 1 == num), (i == 0)); } |
e9bc8fa5d i2c-eg20t: add dr... |
706 707 708 709 710 |
} adap->pch_i2c_xfer_in_progress = false; /* transfer completed */ mutex_unlock(&pch_mutex); |
07e729ce8 i2c-eg20t : Fix t... |
711 |
return (ret < 0) ? ret : num; |
e9bc8fa5d i2c-eg20t: add dr... |
712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 |
} /** * pch_i2c_func() - return the functionality of the I2C driver * @adap: Pointer to struct i2c_algo_pch_data. */ static u32 pch_i2c_func(struct i2c_adapter *adap) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR; } static struct i2c_algorithm pch_algorithm = { .master_xfer = pch_i2c_xfer, .functionality = pch_i2c_func }; /** * pch_i2c_disbl_int() - Disable PCH I2C interrupts * @adap: Pointer to struct i2c_algo_pch_data. */ static void pch_i2c_disbl_int(struct i2c_algo_pch_data *adap) { void __iomem *p = adap->pch_base_address; pch_clrbit(adap->pch_base_address, PCH_I2CCTL, NORMAL_INTR_ENBL); iowrite32(EEPROM_RST_INTR_DISBL, p + PCH_I2CESRMSK); iowrite32(BUFFER_MODE_INTR_DISBL, p + PCH_I2CBUFMSK); } |
0b255e927 i2c: remove __dev... |
742 |
static int pch_i2c_probe(struct pci_dev *pdev, |
173442f27 i2c-eg20t: suppor... |
743 |
const struct pci_device_id *id) |
e9bc8fa5d i2c-eg20t: add dr... |
744 745 |
{ void __iomem *base_addr; |
173442f27 i2c-eg20t: suppor... |
746 747 |
int ret; int i, j; |
e9bc8fa5d i2c-eg20t: add dr... |
748 |
struct adapter_info *adap_info; |
173442f27 i2c-eg20t: suppor... |
749 |
struct i2c_adapter *pch_adap; |
e9bc8fa5d i2c-eg20t: add dr... |
750 751 752 753 754 |
pch_pci_dbg(pdev, "Entered. "); adap_info = kzalloc((sizeof(struct adapter_info)), GFP_KERNEL); |
46797a2ad i2c: remove unnec... |
755 |
if (adap_info == NULL) |
e9bc8fa5d i2c-eg20t: add dr... |
756 |
return -ENOMEM; |
e9bc8fa5d i2c-eg20t: add dr... |
757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 |
ret = pci_enable_device(pdev); if (ret) { pch_pci_err(pdev, "pci_enable_device FAILED "); goto err_pci_enable; } ret = pci_request_regions(pdev, KBUILD_MODNAME); if (ret) { pch_pci_err(pdev, "pci_request_regions FAILED "); goto err_pci_req; } base_addr = pci_iomap(pdev, 1, 0); if (base_addr == NULL) { pch_pci_err(pdev, "pci_iomap FAILED "); ret = -ENOMEM; goto err_pci_iomap; } |
173442f27 i2c-eg20t: suppor... |
780 781 |
/* Set the number of I2C channel instance */ adap_info->ch_num = id->driver_data; |
e9bc8fa5d i2c-eg20t: add dr... |
782 |
|
0d5fb5ea7 i2c-eg20t: correc... |
783 784 785 786 787 788 789 |
ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED, KBUILD_MODNAME, adap_info); if (ret) { pch_pci_err(pdev, "request_irq FAILED "); goto err_request_irq; } |
173442f27 i2c-eg20t: suppor... |
790 791 792 |
for (i = 0; i < adap_info->ch_num; i++) { pch_adap = &adap_info->pch_data[i].pch_adapter; adap_info->pch_i2c_suspended = false; |
e9bc8fa5d i2c-eg20t: add dr... |
793 |
|
173442f27 i2c-eg20t: suppor... |
794 |
adap_info->pch_data[i].p_adapter_info = adap_info; |
e9bc8fa5d i2c-eg20t: add dr... |
795 |
|
173442f27 i2c-eg20t: suppor... |
796 797 |
pch_adap->owner = THIS_MODULE; pch_adap->class = I2C_CLASS_HWMON; |
6188a3768 i2c: eg20t: don't... |
798 |
strlcpy(pch_adap->name, KBUILD_MODNAME, sizeof(pch_adap->name)); |
173442f27 i2c-eg20t: suppor... |
799 800 |
pch_adap->algo = &pch_algorithm; pch_adap->algo_data = &adap_info->pch_data[i]; |
e9bc8fa5d i2c-eg20t: add dr... |
801 |
|
173442f27 i2c-eg20t: suppor... |
802 803 |
/* base_addr + offset; */ adap_info->pch_data[i].pch_base_address = base_addr + 0x100 * i; |
e9bc8fa5d i2c-eg20t: add dr... |
804 |
|
173442f27 i2c-eg20t: suppor... |
805 |
pch_adap->dev.parent = &pdev->dev; |
e9bc8fa5d i2c-eg20t: add dr... |
806 |
|
0d5fb5ea7 i2c-eg20t: correc... |
807 |
pch_i2c_init(&adap_info->pch_data[i]); |
07e8a51ff i2c-eg20t: use i2... |
808 809 810 |
pch_adap->nr = i; ret = i2c_add_numbered_adapter(pch_adap); |
173442f27 i2c-eg20t: suppor... |
811 812 813 |
if (ret) { pch_pci_err(pdev, "i2c_add_adapter[ch:%d] FAILED ", i); |
0d5fb5ea7 i2c-eg20t: correc... |
814 |
goto err_add_adapter; |
173442f27 i2c-eg20t: suppor... |
815 |
} |
e9bc8fa5d i2c-eg20t: add dr... |
816 817 818 819 820 821 |
} pci_set_drvdata(pdev, adap_info); pch_pci_dbg(pdev, "returns %d. ", ret); return 0; |
0d5fb5ea7 i2c-eg20t: correc... |
822 |
err_add_adapter: |
173442f27 i2c-eg20t: suppor... |
823 824 |
for (j = 0; j < i; j++) i2c_del_adapter(&adap_info->pch_data[j].pch_adapter); |
0d5fb5ea7 i2c-eg20t: correc... |
825 826 |
free_irq(pdev->irq, adap_info); err_request_irq: |
e9bc8fa5d i2c-eg20t: add dr... |
827 828 829 830 831 832 833 834 835 |
pci_iounmap(pdev, base_addr); err_pci_iomap: pci_release_regions(pdev); err_pci_req: pci_disable_device(pdev); err_pci_enable: kfree(adap_info); return ret; } |
0b255e927 i2c: remove __dev... |
836 |
static void pch_i2c_remove(struct pci_dev *pdev) |
e9bc8fa5d i2c-eg20t: add dr... |
837 |
{ |
173442f27 i2c-eg20t: suppor... |
838 |
int i; |
e9bc8fa5d i2c-eg20t: add dr... |
839 |
struct adapter_info *adap_info = pci_get_drvdata(pdev); |
173442f27 i2c-eg20t: suppor... |
840 |
free_irq(pdev->irq, adap_info); |
e9bc8fa5d i2c-eg20t: add dr... |
841 |
|
173442f27 i2c-eg20t: suppor... |
842 843 844 |
for (i = 0; i < adap_info->ch_num; i++) { pch_i2c_disbl_int(&adap_info->pch_data[i]); i2c_del_adapter(&adap_info->pch_data[i].pch_adapter); |
e9bc8fa5d i2c-eg20t: add dr... |
845 |
} |
173442f27 i2c-eg20t: suppor... |
846 847 848 849 |
if (adap_info->pch_data[0].pch_base_address) pci_iounmap(pdev, adap_info->pch_data[0].pch_base_address); for (i = 0; i < adap_info->ch_num; i++) |
75fb1f25d i2c: eg20t: use N... |
850 |
adap_info->pch_data[i].pch_base_address = NULL; |
173442f27 i2c-eg20t: suppor... |
851 |
|
e9bc8fa5d i2c-eg20t: add dr... |
852 853 854 855 856 857 858 859 860 861 |
pci_release_regions(pdev); pci_disable_device(pdev); kfree(adap_info); } #ifdef CONFIG_PM static int pch_i2c_suspend(struct pci_dev *pdev, pm_message_t state) { int ret; |
173442f27 i2c-eg20t: suppor... |
862 |
int i; |
e9bc8fa5d i2c-eg20t: add dr... |
863 |
struct adapter_info *adap_info = pci_get_drvdata(pdev); |
173442f27 i2c-eg20t: suppor... |
864 |
void __iomem *p = adap_info->pch_data[0].pch_base_address; |
e9bc8fa5d i2c-eg20t: add dr... |
865 866 |
adap_info->pch_i2c_suspended = true; |
173442f27 i2c-eg20t: suppor... |
867 868 869 870 871 |
for (i = 0; i < adap_info->ch_num; i++) { while ((adap_info->pch_data[i].pch_i2c_xfer_in_progress)) { /* Wait until all channel transfers are completed */ msleep(20); } |
e9bc8fa5d i2c-eg20t: add dr... |
872 |
} |
173442f27 i2c-eg20t: suppor... |
873 |
|
e9bc8fa5d i2c-eg20t: add dr... |
874 |
/* Disable the i2c interrupts */ |
173442f27 i2c-eg20t: suppor... |
875 876 |
for (i = 0; i < adap_info->ch_num; i++) pch_i2c_disbl_int(&adap_info->pch_data[i]); |
e9bc8fa5d i2c-eg20t: add dr... |
877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 |
pch_pci_dbg(pdev, "I2CSR = %x I2CBUFSTA = %x I2CESRSTA = %x " "invoked function pch_i2c_disbl_int successfully ", ioread32(p + PCH_I2CSR), ioread32(p + PCH_I2CBUFSTA), ioread32(p + PCH_I2CESRSTA)); ret = pci_save_state(pdev); if (ret) { pch_pci_err(pdev, "pci_save_state "); return ret; } pci_enable_wake(pdev, PCI_D3hot, 0); pci_disable_device(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; } static int pch_i2c_resume(struct pci_dev *pdev) { |
173442f27 i2c-eg20t: suppor... |
901 |
int i; |
e9bc8fa5d i2c-eg20t: add dr... |
902 903 904 905 906 907 908 909 910 911 912 913 |
struct adapter_info *adap_info = pci_get_drvdata(pdev); pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); if (pci_enable_device(pdev) < 0) { pch_pci_err(pdev, "pch_i2c_resume:pci_enable_device FAILED "); return -EIO; } pci_enable_wake(pdev, PCI_D3hot, 0); |
173442f27 i2c-eg20t: suppor... |
914 915 |
for (i = 0; i < adap_info->ch_num; i++) pch_i2c_init(&adap_info->pch_data[i]); |
e9bc8fa5d i2c-eg20t: add dr... |
916 917 918 919 920 921 922 923 924 925 926 927 928 929 |
adap_info->pch_i2c_suspended = false; return 0; } #else #define pch_i2c_suspend NULL #define pch_i2c_resume NULL #endif static struct pci_driver pch_pcidriver = { .name = KBUILD_MODNAME, .id_table = pch_pcidev_id, .probe = pch_i2c_probe, |
0b255e927 i2c: remove __dev... |
930 |
.remove = pch_i2c_remove, |
e9bc8fa5d i2c-eg20t: add dr... |
931 932 933 |
.suspend = pch_i2c_suspend, .resume = pch_i2c_resume }; |
56f217889 i2c/busses: Use m... |
934 |
module_pci_driver(pch_pcidriver); |
e9bc8fa5d i2c-eg20t: add dr... |
935 |
|
8956dc102 i2c-eg20t: Change... |
936 |
MODULE_DESCRIPTION("Intel EG20T PCH/LAPIS Semico ML7213/ML7223/ML7831 IOH I2C"); |
e9bc8fa5d i2c-eg20t: add dr... |
937 |
MODULE_LICENSE("GPL"); |
096407136 i2c-eg20t: Modify... |
938 |
MODULE_AUTHOR("Tomoya MORINAGA. <tomoya.rohm@gmail.com>"); |
e9bc8fa5d i2c-eg20t: add dr... |
939 940 |
module_param(pch_i2c_speed, int, (S_IRUSR | S_IWUSR)); module_param(pch_clk, int, (S_IRUSR | S_IWUSR)); |