175041120SAndy Shevchenko // SPDX-License-Identifier: GPL-2.0-only 2cfad6425SSerge Semin /* 3cfad6425SSerge Semin * Copyright (C) 2016 T-Platforms. All Rights Reserved. 4cfad6425SSerge Semin * 5cfad6425SSerge Semin * IDT PCIe-switch NTB Linux driver 6cfad6425SSerge Semin * 7cfad6425SSerge Semin * Contact Information: 8cfad6425SSerge Semin * Serge Semin <fancer.lancer@gmail.com>, <Sergey.Semin@t-platforms.ru> 9cfad6425SSerge Semin */ 10cfad6425SSerge Semin /* 11cfad6425SSerge Semin * NOTE of the IDT 89HPESx SMBus-slave interface driver 12cfad6425SSerge Semin * This driver primarily is developed to have an access to EEPROM device of 13cfad6425SSerge Semin * IDT PCIe-switches. IDT provides a simple SMBus interface to perform IO- 14cfad6425SSerge Semin * operations from/to EEPROM, which is located at private (so called Master) 15cfad6425SSerge Semin * SMBus of switches. Using that interface this the driver creates a simple 16cfad6425SSerge Semin * binary sysfs-file in the device directory: 17cfad6425SSerge Semin * /sys/bus/i2c/devices/<bus>-<devaddr>/eeprom 18cfad6425SSerge Semin * In case if read-only flag is specified in the dts-node of device desription, 19cfad6425SSerge Semin * User-space applications won't be able to write to the EEPROM sysfs-node. 20cfad6425SSerge Semin * Additionally IDT 89HPESx SMBus interface has an ability to write/read 21cfad6425SSerge Semin * data of device CSRs. This driver exposes debugf-file to perform simple IO 22cfad6425SSerge Semin * operations using that ability for just basic debug purpose. Particularly 23cfad6425SSerge Semin * next file is created in the specific debugfs-directory: 24cfad6425SSerge Semin * /sys/kernel/debug/idt_csr/ 25cfad6425SSerge Semin * Format of the debugfs-node is: 26cfad6425SSerge Semin * $ cat /sys/kernel/debug/idt_csr/<bus>-<devaddr>/<devname>; 27cfad6425SSerge Semin * <CSR address>:<CSR value> 28cfad6425SSerge Semin * So reading the content of the file gives current CSR address and it value. 29cfad6425SSerge Semin * If User-space application wishes to change current CSR address, 30cfad6425SSerge Semin * it can just write a proper value to the sysfs-file: 31cfad6425SSerge Semin * $ echo "<CSR address>" > /sys/kernel/debug/idt_csr/<bus>-<devaddr>/<devname> 32cfad6425SSerge Semin * If it wants to change the CSR value as well, the format of the write 33cfad6425SSerge Semin * operation is: 34cfad6425SSerge Semin * $ echo "<CSR address>:<CSR value>" > \ 35cfad6425SSerge Semin * /sys/kernel/debug/idt_csr/<bus>-<devaddr>/<devname>; 36cfad6425SSerge Semin * CSR address and value can be any of hexadecimal, decimal or octal format. 37cfad6425SSerge Semin */ 38cfad6425SSerge Semin 39cfad6425SSerge Semin #include <linux/kernel.h> 40cfad6425SSerge Semin #include <linux/init.h> 41cfad6425SSerge Semin #include <linux/module.h> 42cfad6425SSerge Semin #include <linux/types.h> 43cfad6425SSerge Semin #include <linux/sizes.h> 44cfad6425SSerge Semin #include <linux/slab.h> 45cfad6425SSerge Semin #include <linux/mutex.h> 46cfad6425SSerge Semin #include <linux/sysfs.h> 47cfad6425SSerge Semin #include <linux/debugfs.h> 48cfad6425SSerge Semin #include <linux/mod_devicetable.h> 49db15d73eSHuy Duong #include <linux/property.h> 50cfad6425SSerge Semin #include <linux/i2c.h> 51cfad6425SSerge Semin #include <linux/pci_ids.h> 52cfad6425SSerge Semin #include <linux/delay.h> 53cfad6425SSerge Semin 54cfad6425SSerge Semin #define IDT_NAME "89hpesx" 55cfad6425SSerge Semin #define IDT_89HPESX_DESC "IDT 89HPESx SMBus-slave interface driver" 56cfad6425SSerge Semin #define IDT_89HPESX_VER "1.0" 57cfad6425SSerge Semin 58cfad6425SSerge Semin MODULE_DESCRIPTION(IDT_89HPESX_DESC); 59cfad6425SSerge Semin MODULE_VERSION(IDT_89HPESX_VER); 60cfad6425SSerge Semin MODULE_LICENSE("GPL v2"); 61cfad6425SSerge Semin MODULE_AUTHOR("T-platforms"); 62cfad6425SSerge Semin 63cfad6425SSerge Semin /* 64cfad6425SSerge Semin * csr_dbgdir - CSR read/write operations Debugfs directory 65cfad6425SSerge Semin */ 66cfad6425SSerge Semin static struct dentry *csr_dbgdir; 67cfad6425SSerge Semin 68cfad6425SSerge Semin /* 69cfad6425SSerge Semin * struct idt_89hpesx_dev - IDT 89HPESx device data structure 70cfad6425SSerge Semin * @eesize: Size of EEPROM in bytes (calculated from "idt,eecompatible") 71cfad6425SSerge Semin * @eero: EEPROM Read-only flag 72cfad6425SSerge Semin * @eeaddr: EEPROM custom address 73cfad6425SSerge Semin * 74cfad6425SSerge Semin * @inieecmd: Initial cmd value for EEPROM read/write operations 75cfad6425SSerge Semin * @inicsrcmd: Initial cmd value for CSR read/write operations 76cfad6425SSerge Semin * @iniccode: Initialial command code value for IO-operations 77cfad6425SSerge Semin * 78cfad6425SSerge Semin * @csr: CSR address to perform read operation 79cfad6425SSerge Semin * 80cfad6425SSerge Semin * @smb_write: SMBus write method 81cfad6425SSerge Semin * @smb_read: SMBus read method 82cfad6425SSerge Semin * @smb_mtx: SMBus mutex 83cfad6425SSerge Semin * 84cfad6425SSerge Semin * @client: i2c client used to perform IO operations 85cfad6425SSerge Semin * 86cfad6425SSerge Semin * @ee_file: EEPROM read/write sysfs-file 87cfad6425SSerge Semin */ 88cfad6425SSerge Semin struct idt_smb_seq; 89cfad6425SSerge Semin struct idt_89hpesx_dev { 90cfad6425SSerge Semin u32 eesize; 91cfad6425SSerge Semin bool eero; 92cfad6425SSerge Semin u8 eeaddr; 93cfad6425SSerge Semin 94cfad6425SSerge Semin u8 inieecmd; 95cfad6425SSerge Semin u8 inicsrcmd; 96cfad6425SSerge Semin u8 iniccode; 97cfad6425SSerge Semin 98cfad6425SSerge Semin u16 csr; 99cfad6425SSerge Semin 100cfad6425SSerge Semin int (*smb_write)(struct idt_89hpesx_dev *, const struct idt_smb_seq *); 101cfad6425SSerge Semin int (*smb_read)(struct idt_89hpesx_dev *, struct idt_smb_seq *); 102cfad6425SSerge Semin struct mutex smb_mtx; 103cfad6425SSerge Semin 104cfad6425SSerge Semin struct i2c_client *client; 105cfad6425SSerge Semin 106cfad6425SSerge Semin struct bin_attribute *ee_file; 107cfad6425SSerge Semin struct dentry *csr_dir; 108cfad6425SSerge Semin }; 109cfad6425SSerge Semin 110cfad6425SSerge Semin /* 111cfad6425SSerge Semin * struct idt_smb_seq - sequence of data to be read/written from/to IDT 89HPESx 112cfad6425SSerge Semin * @ccode: SMBus command code 113cfad6425SSerge Semin * @bytecnt: Byte count of operation 114cfad6425SSerge Semin * @data: Data to by written 115cfad6425SSerge Semin */ 116cfad6425SSerge Semin struct idt_smb_seq { 117cfad6425SSerge Semin u8 ccode; 118cfad6425SSerge Semin u8 bytecnt; 119cfad6425SSerge Semin u8 *data; 120cfad6425SSerge Semin }; 121cfad6425SSerge Semin 122cfad6425SSerge Semin /* 123cfad6425SSerge Semin * struct idt_eeprom_seq - sequence of data to be read/written from/to EEPROM 124cfad6425SSerge Semin * @cmd: Transaction CMD 125cfad6425SSerge Semin * @eeaddr: EEPROM custom address 126cfad6425SSerge Semin * @memaddr: Internal memory address of EEPROM 127cfad6425SSerge Semin * @data: Data to be written at the memory address 128cfad6425SSerge Semin */ 129cfad6425SSerge Semin struct idt_eeprom_seq { 130cfad6425SSerge Semin u8 cmd; 131cfad6425SSerge Semin u8 eeaddr; 132cfad6425SSerge Semin u16 memaddr; 133cfad6425SSerge Semin u8 data; 134cfad6425SSerge Semin } __packed; 135cfad6425SSerge Semin 136cfad6425SSerge Semin /* 137cfad6425SSerge Semin * struct idt_csr_seq - sequence of data to be read/written from/to CSR 138cfad6425SSerge Semin * @cmd: Transaction CMD 139cfad6425SSerge Semin * @csraddr: Internal IDT device CSR address 140cfad6425SSerge Semin * @data: Data to be read/written from/to the CSR address 141cfad6425SSerge Semin */ 142cfad6425SSerge Semin struct idt_csr_seq { 143cfad6425SSerge Semin u8 cmd; 144cfad6425SSerge Semin u16 csraddr; 145cfad6425SSerge Semin u32 data; 146cfad6425SSerge Semin } __packed; 147cfad6425SSerge Semin 148cfad6425SSerge Semin /* 149cfad6425SSerge Semin * SMBus command code macros 150cfad6425SSerge Semin * @CCODE_END: Indicates the end of transaction 151cfad6425SSerge Semin * @CCODE_START: Indicates the start of transaction 152cfad6425SSerge Semin * @CCODE_CSR: CSR read/write transaction 153cfad6425SSerge Semin * @CCODE_EEPROM: EEPROM read/write transaction 154cfad6425SSerge Semin * @CCODE_BYTE: Supplied data has BYTE length 155cfad6425SSerge Semin * @CCODE_WORD: Supplied data has WORD length 156cfad6425SSerge Semin * @CCODE_BLOCK: Supplied data has variable length passed in bytecnt 157cfad6425SSerge Semin * byte right following CCODE byte 158cfad6425SSerge Semin */ 159cfad6425SSerge Semin #define CCODE_END ((u8)0x01) 160cfad6425SSerge Semin #define CCODE_START ((u8)0x02) 161cfad6425SSerge Semin #define CCODE_CSR ((u8)0x00) 162cfad6425SSerge Semin #define CCODE_EEPROM ((u8)0x04) 163cfad6425SSerge Semin #define CCODE_BYTE ((u8)0x00) 164cfad6425SSerge Semin #define CCODE_WORD ((u8)0x20) 165cfad6425SSerge Semin #define CCODE_BLOCK ((u8)0x40) 166cfad6425SSerge Semin #define CCODE_PEC ((u8)0x80) 167cfad6425SSerge Semin 168cfad6425SSerge Semin /* 169cfad6425SSerge Semin * EEPROM command macros 170cfad6425SSerge Semin * @EEPROM_OP_WRITE: EEPROM write operation 171cfad6425SSerge Semin * @EEPROM_OP_READ: EEPROM read operation 172cfad6425SSerge Semin * @EEPROM_USA: Use specified address of EEPROM 173cfad6425SSerge Semin * @EEPROM_NAERR: EEPROM device is not ready to respond 174cfad6425SSerge Semin * @EEPROM_LAERR: EEPROM arbitration loss error 175cfad6425SSerge Semin * @EEPROM_MSS: EEPROM misplace start & stop bits error 176cfad6425SSerge Semin * @EEPROM_WR_CNT: Bytes count to perform write operation 177cfad6425SSerge Semin * @EEPROM_WRRD_CNT: Bytes count to write before reading 178cfad6425SSerge Semin * @EEPROM_RD_CNT: Bytes count to perform read operation 179cfad6425SSerge Semin * @EEPROM_DEF_SIZE: Fall back size of EEPROM 180cfad6425SSerge Semin * @EEPROM_DEF_ADDR: Defatul EEPROM address 181cfad6425SSerge Semin * @EEPROM_TOUT: Timeout before retry read operation if eeprom is busy 182cfad6425SSerge Semin */ 183cfad6425SSerge Semin #define EEPROM_OP_WRITE ((u8)0x00) 184cfad6425SSerge Semin #define EEPROM_OP_READ ((u8)0x01) 185cfad6425SSerge Semin #define EEPROM_USA ((u8)0x02) 186cfad6425SSerge Semin #define EEPROM_NAERR ((u8)0x08) 187cfad6425SSerge Semin #define EEPROM_LAERR ((u8)0x10) 188cfad6425SSerge Semin #define EEPROM_MSS ((u8)0x20) 189cfad6425SSerge Semin #define EEPROM_WR_CNT ((u8)5) 190cfad6425SSerge Semin #define EEPROM_WRRD_CNT ((u8)4) 191cfad6425SSerge Semin #define EEPROM_RD_CNT ((u8)5) 192cfad6425SSerge Semin #define EEPROM_DEF_SIZE ((u16)4096) 193cfad6425SSerge Semin #define EEPROM_DEF_ADDR ((u8)0x50) 194cfad6425SSerge Semin #define EEPROM_TOUT (100) 195cfad6425SSerge Semin 196cfad6425SSerge Semin /* 197cfad6425SSerge Semin * CSR command macros 198cfad6425SSerge Semin * @CSR_DWE: Enable all four bytes of the operation 199cfad6425SSerge Semin * @CSR_OP_WRITE: CSR write operation 200cfad6425SSerge Semin * @CSR_OP_READ: CSR read operation 201cfad6425SSerge Semin * @CSR_RERR: Read operation error 202cfad6425SSerge Semin * @CSR_WERR: Write operation error 203cfad6425SSerge Semin * @CSR_WR_CNT: Bytes count to perform write operation 204cfad6425SSerge Semin * @CSR_WRRD_CNT: Bytes count to write before reading 205cfad6425SSerge Semin * @CSR_RD_CNT: Bytes count to perform read operation 206cfad6425SSerge Semin * @CSR_MAX: Maximum CSR address 207cfad6425SSerge Semin * @CSR_DEF: Default CSR address 208cfad6425SSerge Semin * @CSR_REAL_ADDR: CSR real unshifted address 209cfad6425SSerge Semin */ 210cfad6425SSerge Semin #define CSR_DWE ((u8)0x0F) 211cfad6425SSerge Semin #define CSR_OP_WRITE ((u8)0x00) 212cfad6425SSerge Semin #define CSR_OP_READ ((u8)0x10) 213cfad6425SSerge Semin #define CSR_RERR ((u8)0x40) 214cfad6425SSerge Semin #define CSR_WERR ((u8)0x80) 215cfad6425SSerge Semin #define CSR_WR_CNT ((u8)7) 216cfad6425SSerge Semin #define CSR_WRRD_CNT ((u8)3) 217cfad6425SSerge Semin #define CSR_RD_CNT ((u8)7) 218cfad6425SSerge Semin #define CSR_MAX ((u32)0x3FFFF) 219cfad6425SSerge Semin #define CSR_DEF ((u16)0x0000) 220cfad6425SSerge Semin #define CSR_REAL_ADDR(val) ((unsigned int)val << 2) 221cfad6425SSerge Semin 222cfad6425SSerge Semin /* 223cfad6425SSerge Semin * IDT 89HPESx basic register 224cfad6425SSerge Semin * @IDT_VIDDID_CSR: PCIe VID and DID of IDT 89HPESx 225cfad6425SSerge Semin * @IDT_VID_MASK: Mask of VID 226cfad6425SSerge Semin */ 227cfad6425SSerge Semin #define IDT_VIDDID_CSR ((u32)0x0000) 228cfad6425SSerge Semin #define IDT_VID_MASK ((u32)0xFFFF) 229cfad6425SSerge Semin 230cfad6425SSerge Semin /* 231cfad6425SSerge Semin * IDT 89HPESx can send NACK when new command is sent before previous one 232cfad6425SSerge Semin * fininshed execution. In this case driver retries operation 233cfad6425SSerge Semin * certain times. 234cfad6425SSerge Semin * @RETRY_CNT: Number of retries before giving up and fail 235cfad6425SSerge Semin * @idt_smb_safe: Generate a retry loop on corresponding SMBus method 236cfad6425SSerge Semin */ 237cfad6425SSerge Semin #define RETRY_CNT (128) 238cfad6425SSerge Semin #define idt_smb_safe(ops, args...) ({ \ 239cfad6425SSerge Semin int __retry = RETRY_CNT; \ 240cfad6425SSerge Semin s32 __sts; \ 241cfad6425SSerge Semin do { \ 242cfad6425SSerge Semin __sts = i2c_smbus_ ## ops ## _data(args); \ 243cfad6425SSerge Semin } while (__retry-- && __sts < 0); \ 244cfad6425SSerge Semin __sts; \ 245cfad6425SSerge Semin }) 246cfad6425SSerge Semin 247cfad6425SSerge Semin /*=========================================================================== 248cfad6425SSerge Semin * i2c bus level IO-operations 249cfad6425SSerge Semin *=========================================================================== 250cfad6425SSerge Semin */ 251cfad6425SSerge Semin 252cfad6425SSerge Semin /* 253cfad6425SSerge Semin * idt_smb_write_byte() - SMBus write method when I2C_SMBUS_BYTE_DATA operation 254cfad6425SSerge Semin * is only available 255cfad6425SSerge Semin * @pdev: Pointer to the driver data 256cfad6425SSerge Semin * @seq: Sequence of data to be written 257cfad6425SSerge Semin */ 258cfad6425SSerge Semin static int idt_smb_write_byte(struct idt_89hpesx_dev *pdev, 259cfad6425SSerge Semin const struct idt_smb_seq *seq) 260cfad6425SSerge Semin { 261cfad6425SSerge Semin s32 sts; 262cfad6425SSerge Semin u8 ccode; 263cfad6425SSerge Semin int idx; 264cfad6425SSerge Semin 265cfad6425SSerge Semin /* Loop over the supplied data sending byte one-by-one */ 266cfad6425SSerge Semin for (idx = 0; idx < seq->bytecnt; idx++) { 267cfad6425SSerge Semin /* Collect the command code byte */ 268cfad6425SSerge Semin ccode = seq->ccode | CCODE_BYTE; 269cfad6425SSerge Semin if (idx == 0) 270cfad6425SSerge Semin ccode |= CCODE_START; 271cfad6425SSerge Semin if (idx == seq->bytecnt - 1) 272cfad6425SSerge Semin ccode |= CCODE_END; 273cfad6425SSerge Semin 274cfad6425SSerge Semin /* Send data to the device */ 275cfad6425SSerge Semin sts = idt_smb_safe(write_byte, pdev->client, ccode, 276cfad6425SSerge Semin seq->data[idx]); 277cfad6425SSerge Semin if (sts != 0) 278cfad6425SSerge Semin return (int)sts; 279cfad6425SSerge Semin } 280cfad6425SSerge Semin 281cfad6425SSerge Semin return 0; 282cfad6425SSerge Semin } 283cfad6425SSerge Semin 284cfad6425SSerge Semin /* 285cfad6425SSerge Semin * idt_smb_read_byte() - SMBus read method when I2C_SMBUS_BYTE_DATA operation 286cfad6425SSerge Semin * is only available 287cfad6425SSerge Semin * @pdev: Pointer to the driver data 288cfad6425SSerge Semin * @seq: Buffer to read data to 289cfad6425SSerge Semin */ 290cfad6425SSerge Semin static int idt_smb_read_byte(struct idt_89hpesx_dev *pdev, 291cfad6425SSerge Semin struct idt_smb_seq *seq) 292cfad6425SSerge Semin { 293cfad6425SSerge Semin s32 sts; 294cfad6425SSerge Semin u8 ccode; 295cfad6425SSerge Semin int idx; 296cfad6425SSerge Semin 297cfad6425SSerge Semin /* Loop over the supplied buffer receiving byte one-by-one */ 298cfad6425SSerge Semin for (idx = 0; idx < seq->bytecnt; idx++) { 299cfad6425SSerge Semin /* Collect the command code byte */ 300cfad6425SSerge Semin ccode = seq->ccode | CCODE_BYTE; 301cfad6425SSerge Semin if (idx == 0) 302cfad6425SSerge Semin ccode |= CCODE_START; 303cfad6425SSerge Semin if (idx == seq->bytecnt - 1) 304cfad6425SSerge Semin ccode |= CCODE_END; 305cfad6425SSerge Semin 306cfad6425SSerge Semin /* Read data from the device */ 307cfad6425SSerge Semin sts = idt_smb_safe(read_byte, pdev->client, ccode); 308cfad6425SSerge Semin if (sts < 0) 309cfad6425SSerge Semin return (int)sts; 310cfad6425SSerge Semin 311cfad6425SSerge Semin seq->data[idx] = (u8)sts; 312cfad6425SSerge Semin } 313cfad6425SSerge Semin 314cfad6425SSerge Semin return 0; 315cfad6425SSerge Semin } 316cfad6425SSerge Semin 317cfad6425SSerge Semin /* 318cfad6425SSerge Semin * idt_smb_write_word() - SMBus write method when I2C_SMBUS_BYTE_DATA and 319cfad6425SSerge Semin * I2C_FUNC_SMBUS_WORD_DATA operations are available 320cfad6425SSerge Semin * @pdev: Pointer to the driver data 321cfad6425SSerge Semin * @seq: Sequence of data to be written 322cfad6425SSerge Semin */ 323cfad6425SSerge Semin static int idt_smb_write_word(struct idt_89hpesx_dev *pdev, 324cfad6425SSerge Semin const struct idt_smb_seq *seq) 325cfad6425SSerge Semin { 326cfad6425SSerge Semin s32 sts; 327cfad6425SSerge Semin u8 ccode; 328cfad6425SSerge Semin int idx, evencnt; 329cfad6425SSerge Semin 330cfad6425SSerge Semin /* Calculate the even count of data to send */ 331cfad6425SSerge Semin evencnt = seq->bytecnt - (seq->bytecnt % 2); 332cfad6425SSerge Semin 333cfad6425SSerge Semin /* Loop over the supplied data sending two bytes at a time */ 334cfad6425SSerge Semin for (idx = 0; idx < evencnt; idx += 2) { 335cfad6425SSerge Semin /* Collect the command code byte */ 336cfad6425SSerge Semin ccode = seq->ccode | CCODE_WORD; 337cfad6425SSerge Semin if (idx == 0) 338cfad6425SSerge Semin ccode |= CCODE_START; 339cfad6425SSerge Semin if (idx == evencnt - 2) 340cfad6425SSerge Semin ccode |= CCODE_END; 341cfad6425SSerge Semin 342cfad6425SSerge Semin /* Send word data to the device */ 343cfad6425SSerge Semin sts = idt_smb_safe(write_word, pdev->client, ccode, 344cfad6425SSerge Semin *(u16 *)&seq->data[idx]); 345cfad6425SSerge Semin if (sts != 0) 346cfad6425SSerge Semin return (int)sts; 347cfad6425SSerge Semin } 348cfad6425SSerge Semin 349cfad6425SSerge Semin /* If there is odd number of bytes then send just one last byte */ 350cfad6425SSerge Semin if (seq->bytecnt != evencnt) { 351cfad6425SSerge Semin /* Collect the command code byte */ 352cfad6425SSerge Semin ccode = seq->ccode | CCODE_BYTE | CCODE_END; 353cfad6425SSerge Semin if (idx == 0) 354cfad6425SSerge Semin ccode |= CCODE_START; 355cfad6425SSerge Semin 356cfad6425SSerge Semin /* Send byte data to the device */ 357cfad6425SSerge Semin sts = idt_smb_safe(write_byte, pdev->client, ccode, 358cfad6425SSerge Semin seq->data[idx]); 359cfad6425SSerge Semin if (sts != 0) 360cfad6425SSerge Semin return (int)sts; 361cfad6425SSerge Semin } 362cfad6425SSerge Semin 363cfad6425SSerge Semin return 0; 364cfad6425SSerge Semin } 365cfad6425SSerge Semin 366cfad6425SSerge Semin /* 367cfad6425SSerge Semin * idt_smb_read_word() - SMBus read method when I2C_SMBUS_BYTE_DATA and 368cfad6425SSerge Semin * I2C_FUNC_SMBUS_WORD_DATA operations are available 369cfad6425SSerge Semin * @pdev: Pointer to the driver data 370cfad6425SSerge Semin * @seq: Buffer to read data to 371cfad6425SSerge Semin */ 372cfad6425SSerge Semin static int idt_smb_read_word(struct idt_89hpesx_dev *pdev, 373cfad6425SSerge Semin struct idt_smb_seq *seq) 374cfad6425SSerge Semin { 375cfad6425SSerge Semin s32 sts; 376cfad6425SSerge Semin u8 ccode; 377cfad6425SSerge Semin int idx, evencnt; 378cfad6425SSerge Semin 379cfad6425SSerge Semin /* Calculate the even count of data to send */ 380cfad6425SSerge Semin evencnt = seq->bytecnt - (seq->bytecnt % 2); 381cfad6425SSerge Semin 382cfad6425SSerge Semin /* Loop over the supplied data reading two bytes at a time */ 383cfad6425SSerge Semin for (idx = 0; idx < evencnt; idx += 2) { 384cfad6425SSerge Semin /* Collect the command code byte */ 385cfad6425SSerge Semin ccode = seq->ccode | CCODE_WORD; 386cfad6425SSerge Semin if (idx == 0) 387cfad6425SSerge Semin ccode |= CCODE_START; 388cfad6425SSerge Semin if (idx == evencnt - 2) 389cfad6425SSerge Semin ccode |= CCODE_END; 390cfad6425SSerge Semin 391cfad6425SSerge Semin /* Read word data from the device */ 392cfad6425SSerge Semin sts = idt_smb_safe(read_word, pdev->client, ccode); 393cfad6425SSerge Semin if (sts < 0) 394cfad6425SSerge Semin return (int)sts; 395cfad6425SSerge Semin 396cfad6425SSerge Semin *(u16 *)&seq->data[idx] = (u16)sts; 397cfad6425SSerge Semin } 398cfad6425SSerge Semin 399cfad6425SSerge Semin /* If there is odd number of bytes then receive just one last byte */ 400cfad6425SSerge Semin if (seq->bytecnt != evencnt) { 401cfad6425SSerge Semin /* Collect the command code byte */ 402cfad6425SSerge Semin ccode = seq->ccode | CCODE_BYTE | CCODE_END; 403cfad6425SSerge Semin if (idx == 0) 404cfad6425SSerge Semin ccode |= CCODE_START; 405cfad6425SSerge Semin 406cfad6425SSerge Semin /* Read last data byte from the device */ 407cfad6425SSerge Semin sts = idt_smb_safe(read_byte, pdev->client, ccode); 408cfad6425SSerge Semin if (sts < 0) 409cfad6425SSerge Semin return (int)sts; 410cfad6425SSerge Semin 411cfad6425SSerge Semin seq->data[idx] = (u8)sts; 412cfad6425SSerge Semin } 413cfad6425SSerge Semin 414cfad6425SSerge Semin return 0; 415cfad6425SSerge Semin } 416cfad6425SSerge Semin 417cfad6425SSerge Semin /* 418cfad6425SSerge Semin * idt_smb_write_block() - SMBus write method when I2C_SMBUS_BLOCK_DATA 419cfad6425SSerge Semin * operation is available 420cfad6425SSerge Semin * @pdev: Pointer to the driver data 421cfad6425SSerge Semin * @seq: Sequence of data to be written 422cfad6425SSerge Semin */ 423cfad6425SSerge Semin static int idt_smb_write_block(struct idt_89hpesx_dev *pdev, 424cfad6425SSerge Semin const struct idt_smb_seq *seq) 425cfad6425SSerge Semin { 426cfad6425SSerge Semin u8 ccode; 427cfad6425SSerge Semin 428cfad6425SSerge Semin /* Return error if too much data passed to send */ 429cfad6425SSerge Semin if (seq->bytecnt > I2C_SMBUS_BLOCK_MAX) 430cfad6425SSerge Semin return -EINVAL; 431cfad6425SSerge Semin 432cfad6425SSerge Semin /* Collect the command code byte */ 433cfad6425SSerge Semin ccode = seq->ccode | CCODE_BLOCK | CCODE_START | CCODE_END; 434cfad6425SSerge Semin 435cfad6425SSerge Semin /* Send block of data to the device */ 436cfad6425SSerge Semin return idt_smb_safe(write_block, pdev->client, ccode, seq->bytecnt, 437cfad6425SSerge Semin seq->data); 438cfad6425SSerge Semin } 439cfad6425SSerge Semin 440cfad6425SSerge Semin /* 441cfad6425SSerge Semin * idt_smb_read_block() - SMBus read method when I2C_SMBUS_BLOCK_DATA 442cfad6425SSerge Semin * operation is available 443cfad6425SSerge Semin * @pdev: Pointer to the driver data 444cfad6425SSerge Semin * @seq: Buffer to read data to 445cfad6425SSerge Semin */ 446cfad6425SSerge Semin static int idt_smb_read_block(struct idt_89hpesx_dev *pdev, 447cfad6425SSerge Semin struct idt_smb_seq *seq) 448cfad6425SSerge Semin { 449cfad6425SSerge Semin s32 sts; 450cfad6425SSerge Semin u8 ccode; 451cfad6425SSerge Semin 452cfad6425SSerge Semin /* Return error if too much data passed to send */ 453cfad6425SSerge Semin if (seq->bytecnt > I2C_SMBUS_BLOCK_MAX) 454cfad6425SSerge Semin return -EINVAL; 455cfad6425SSerge Semin 456cfad6425SSerge Semin /* Collect the command code byte */ 457cfad6425SSerge Semin ccode = seq->ccode | CCODE_BLOCK | CCODE_START | CCODE_END; 458cfad6425SSerge Semin 459cfad6425SSerge Semin /* Read block of data from the device */ 460cfad6425SSerge Semin sts = idt_smb_safe(read_block, pdev->client, ccode, seq->data); 461cfad6425SSerge Semin if (sts != seq->bytecnt) 462cfad6425SSerge Semin return (sts < 0 ? sts : -ENODATA); 463cfad6425SSerge Semin 464cfad6425SSerge Semin return 0; 465cfad6425SSerge Semin } 466cfad6425SSerge Semin 467cfad6425SSerge Semin /* 468cfad6425SSerge Semin * idt_smb_write_i2c_block() - SMBus write method when I2C_SMBUS_I2C_BLOCK_DATA 469cfad6425SSerge Semin * operation is available 470cfad6425SSerge Semin * @pdev: Pointer to the driver data 471cfad6425SSerge Semin * @seq: Sequence of data to be written 472cfad6425SSerge Semin * 473cfad6425SSerge Semin * NOTE It's usual SMBus write block operation, except the actual data length is 474cfad6425SSerge Semin * sent as first byte of data 475cfad6425SSerge Semin */ 476cfad6425SSerge Semin static int idt_smb_write_i2c_block(struct idt_89hpesx_dev *pdev, 477cfad6425SSerge Semin const struct idt_smb_seq *seq) 478cfad6425SSerge Semin { 479cfad6425SSerge Semin u8 ccode, buf[I2C_SMBUS_BLOCK_MAX + 1]; 480cfad6425SSerge Semin 481cfad6425SSerge Semin /* Return error if too much data passed to send */ 482cfad6425SSerge Semin if (seq->bytecnt > I2C_SMBUS_BLOCK_MAX) 483cfad6425SSerge Semin return -EINVAL; 484cfad6425SSerge Semin 485cfad6425SSerge Semin /* Collect the data to send. Length byte must be added prior the data */ 486cfad6425SSerge Semin buf[0] = seq->bytecnt; 487cfad6425SSerge Semin memcpy(&buf[1], seq->data, seq->bytecnt); 488cfad6425SSerge Semin 489cfad6425SSerge Semin /* Collect the command code byte */ 490cfad6425SSerge Semin ccode = seq->ccode | CCODE_BLOCK | CCODE_START | CCODE_END; 491cfad6425SSerge Semin 492cfad6425SSerge Semin /* Send length and block of data to the device */ 493cfad6425SSerge Semin return idt_smb_safe(write_i2c_block, pdev->client, ccode, 494cfad6425SSerge Semin seq->bytecnt + 1, buf); 495cfad6425SSerge Semin } 496cfad6425SSerge Semin 497cfad6425SSerge Semin /* 498cfad6425SSerge Semin * idt_smb_read_i2c_block() - SMBus read method when I2C_SMBUS_I2C_BLOCK_DATA 499cfad6425SSerge Semin * operation is available 500cfad6425SSerge Semin * @pdev: Pointer to the driver data 501cfad6425SSerge Semin * @seq: Buffer to read data to 502cfad6425SSerge Semin * 503cfad6425SSerge Semin * NOTE It's usual SMBus read block operation, except the actual data length is 504cfad6425SSerge Semin * retrieved as first byte of data 505cfad6425SSerge Semin */ 506cfad6425SSerge Semin static int idt_smb_read_i2c_block(struct idt_89hpesx_dev *pdev, 507cfad6425SSerge Semin struct idt_smb_seq *seq) 508cfad6425SSerge Semin { 509cfad6425SSerge Semin u8 ccode, buf[I2C_SMBUS_BLOCK_MAX + 1]; 510cfad6425SSerge Semin s32 sts; 511cfad6425SSerge Semin 512cfad6425SSerge Semin /* Return error if too much data passed to send */ 513cfad6425SSerge Semin if (seq->bytecnt > I2C_SMBUS_BLOCK_MAX) 514cfad6425SSerge Semin return -EINVAL; 515cfad6425SSerge Semin 516cfad6425SSerge Semin /* Collect the command code byte */ 517cfad6425SSerge Semin ccode = seq->ccode | CCODE_BLOCK | CCODE_START | CCODE_END; 518cfad6425SSerge Semin 519cfad6425SSerge Semin /* Read length and block of data from the device */ 520cfad6425SSerge Semin sts = idt_smb_safe(read_i2c_block, pdev->client, ccode, 521cfad6425SSerge Semin seq->bytecnt + 1, buf); 522cfad6425SSerge Semin if (sts != seq->bytecnt + 1) 523cfad6425SSerge Semin return (sts < 0 ? sts : -ENODATA); 524cfad6425SSerge Semin if (buf[0] != seq->bytecnt) 525cfad6425SSerge Semin return -ENODATA; 526cfad6425SSerge Semin 527cfad6425SSerge Semin /* Copy retrieved data to the output data buffer */ 528cfad6425SSerge Semin memcpy(seq->data, &buf[1], seq->bytecnt); 529cfad6425SSerge Semin 530cfad6425SSerge Semin return 0; 531cfad6425SSerge Semin } 532cfad6425SSerge Semin 533cfad6425SSerge Semin /*=========================================================================== 534cfad6425SSerge Semin * EEPROM IO-operations 535cfad6425SSerge Semin *=========================================================================== 536cfad6425SSerge Semin */ 537cfad6425SSerge Semin 538cfad6425SSerge Semin /* 539cfad6425SSerge Semin * idt_eeprom_read_byte() - read just one byte from EEPROM 540cfad6425SSerge Semin * @pdev: Pointer to the driver data 541cfad6425SSerge Semin * @memaddr: Start EEPROM memory address 542cfad6425SSerge Semin * @data: Data to be written to EEPROM 543cfad6425SSerge Semin */ 544cfad6425SSerge Semin static int idt_eeprom_read_byte(struct idt_89hpesx_dev *pdev, u16 memaddr, 545cfad6425SSerge Semin u8 *data) 546cfad6425SSerge Semin { 547cfad6425SSerge Semin struct device *dev = &pdev->client->dev; 548cfad6425SSerge Semin struct idt_eeprom_seq eeseq; 549cfad6425SSerge Semin struct idt_smb_seq smbseq; 550cfad6425SSerge Semin int ret, retry; 551cfad6425SSerge Semin 552cfad6425SSerge Semin /* Initialize SMBus sequence fields */ 553cfad6425SSerge Semin smbseq.ccode = pdev->iniccode | CCODE_EEPROM; 554cfad6425SSerge Semin smbseq.data = (u8 *)&eeseq; 555cfad6425SSerge Semin 556cfad6425SSerge Semin /* 557cfad6425SSerge Semin * Sometimes EEPROM may respond with NACK if it's busy with previous 558cfad6425SSerge Semin * operation, so we need to perform a few attempts of read cycle 559cfad6425SSerge Semin */ 560cfad6425SSerge Semin retry = RETRY_CNT; 561cfad6425SSerge Semin do { 562cfad6425SSerge Semin /* Send EEPROM memory address to read data from */ 563cfad6425SSerge Semin smbseq.bytecnt = EEPROM_WRRD_CNT; 564cfad6425SSerge Semin eeseq.cmd = pdev->inieecmd | EEPROM_OP_READ; 565cfad6425SSerge Semin eeseq.eeaddr = pdev->eeaddr; 566cfad6425SSerge Semin eeseq.memaddr = cpu_to_le16(memaddr); 567cfad6425SSerge Semin ret = pdev->smb_write(pdev, &smbseq); 568cfad6425SSerge Semin if (ret != 0) { 569*ffff4913SJustin Stitt dev_err(dev, "Failed to init eeprom addr 0x%02x", 570cfad6425SSerge Semin memaddr); 571cfad6425SSerge Semin break; 572cfad6425SSerge Semin } 573cfad6425SSerge Semin 574cfad6425SSerge Semin /* Perform read operation */ 575cfad6425SSerge Semin smbseq.bytecnt = EEPROM_RD_CNT; 576cfad6425SSerge Semin ret = pdev->smb_read(pdev, &smbseq); 577cfad6425SSerge Semin if (ret != 0) { 578*ffff4913SJustin Stitt dev_err(dev, "Failed to read eeprom data 0x%02x", 579cfad6425SSerge Semin memaddr); 580cfad6425SSerge Semin break; 581cfad6425SSerge Semin } 582cfad6425SSerge Semin 583cfad6425SSerge Semin /* Restart read operation if the device is busy */ 584cfad6425SSerge Semin if (retry && (eeseq.cmd & EEPROM_NAERR)) { 585cfad6425SSerge Semin dev_dbg(dev, "EEPROM busy, retry reading after %d ms", 586cfad6425SSerge Semin EEPROM_TOUT); 587cfad6425SSerge Semin msleep(EEPROM_TOUT); 588cfad6425SSerge Semin continue; 589cfad6425SSerge Semin } 590cfad6425SSerge Semin 591cfad6425SSerge Semin /* Check whether IDT successfully read data from EEPROM */ 592cfad6425SSerge Semin if (eeseq.cmd & (EEPROM_NAERR | EEPROM_LAERR | EEPROM_MSS)) { 593cfad6425SSerge Semin dev_err(dev, 594cfad6425SSerge Semin "Communication with eeprom failed, cmd 0x%hhx", 595cfad6425SSerge Semin eeseq.cmd); 596cfad6425SSerge Semin ret = -EREMOTEIO; 597cfad6425SSerge Semin break; 598cfad6425SSerge Semin } 599cfad6425SSerge Semin 600cfad6425SSerge Semin /* Save retrieved data and exit the loop */ 601cfad6425SSerge Semin *data = eeseq.data; 602cfad6425SSerge Semin break; 603cfad6425SSerge Semin } while (retry--); 604cfad6425SSerge Semin 605cfad6425SSerge Semin /* Return the status of operation */ 606cfad6425SSerge Semin return ret; 607cfad6425SSerge Semin } 608cfad6425SSerge Semin 609cfad6425SSerge Semin /* 610cfad6425SSerge Semin * idt_eeprom_write() - EEPROM write operation 611cfad6425SSerge Semin * @pdev: Pointer to the driver data 612cfad6425SSerge Semin * @memaddr: Start EEPROM memory address 613cfad6425SSerge Semin * @len: Length of data to be written 614cfad6425SSerge Semin * @data: Data to be written to EEPROM 615cfad6425SSerge Semin */ 616cfad6425SSerge Semin static int idt_eeprom_write(struct idt_89hpesx_dev *pdev, u16 memaddr, u16 len, 617cfad6425SSerge Semin const u8 *data) 618cfad6425SSerge Semin { 619cfad6425SSerge Semin struct device *dev = &pdev->client->dev; 620cfad6425SSerge Semin struct idt_eeprom_seq eeseq; 621cfad6425SSerge Semin struct idt_smb_seq smbseq; 622cfad6425SSerge Semin int ret; 623cfad6425SSerge Semin u16 idx; 624cfad6425SSerge Semin 625cfad6425SSerge Semin /* Initialize SMBus sequence fields */ 626cfad6425SSerge Semin smbseq.ccode = pdev->iniccode | CCODE_EEPROM; 627cfad6425SSerge Semin smbseq.data = (u8 *)&eeseq; 628cfad6425SSerge Semin 629cfad6425SSerge Semin /* Send data byte-by-byte, checking if it is successfully written */ 630cfad6425SSerge Semin for (idx = 0; idx < len; idx++, memaddr++) { 631cfad6425SSerge Semin /* Lock IDT SMBus device */ 632cfad6425SSerge Semin mutex_lock(&pdev->smb_mtx); 633cfad6425SSerge Semin 634cfad6425SSerge Semin /* Perform write operation */ 635cfad6425SSerge Semin smbseq.bytecnt = EEPROM_WR_CNT; 636cfad6425SSerge Semin eeseq.cmd = pdev->inieecmd | EEPROM_OP_WRITE; 637cfad6425SSerge Semin eeseq.eeaddr = pdev->eeaddr; 638cfad6425SSerge Semin eeseq.memaddr = cpu_to_le16(memaddr); 639cfad6425SSerge Semin eeseq.data = data[idx]; 640cfad6425SSerge Semin ret = pdev->smb_write(pdev, &smbseq); 641cfad6425SSerge Semin if (ret != 0) { 642cfad6425SSerge Semin dev_err(dev, 643cfad6425SSerge Semin "Failed to write 0x%04hx:0x%02hhx to eeprom", 644cfad6425SSerge Semin memaddr, data[idx]); 645cfad6425SSerge Semin goto err_mutex_unlock; 646cfad6425SSerge Semin } 647cfad6425SSerge Semin 648cfad6425SSerge Semin /* 649cfad6425SSerge Semin * Check whether the data is successfully written by reading 650cfad6425SSerge Semin * from the same EEPROM memory address. 651cfad6425SSerge Semin */ 652cfad6425SSerge Semin eeseq.data = ~data[idx]; 653cfad6425SSerge Semin ret = idt_eeprom_read_byte(pdev, memaddr, &eeseq.data); 654cfad6425SSerge Semin if (ret != 0) 655cfad6425SSerge Semin goto err_mutex_unlock; 656cfad6425SSerge Semin 657cfad6425SSerge Semin /* Check whether the read byte is the same as written one */ 658cfad6425SSerge Semin if (eeseq.data != data[idx]) { 659cfad6425SSerge Semin dev_err(dev, "Values don't match 0x%02hhx != 0x%02hhx", 660cfad6425SSerge Semin eeseq.data, data[idx]); 661cfad6425SSerge Semin ret = -EREMOTEIO; 662cfad6425SSerge Semin goto err_mutex_unlock; 663cfad6425SSerge Semin } 664cfad6425SSerge Semin 665cfad6425SSerge Semin /* Unlock IDT SMBus device */ 666cfad6425SSerge Semin err_mutex_unlock: 667cfad6425SSerge Semin mutex_unlock(&pdev->smb_mtx); 668cfad6425SSerge Semin if (ret != 0) 669cfad6425SSerge Semin return ret; 670cfad6425SSerge Semin } 671cfad6425SSerge Semin 672cfad6425SSerge Semin return 0; 673cfad6425SSerge Semin } 674cfad6425SSerge Semin 675cfad6425SSerge Semin /* 676cfad6425SSerge Semin * idt_eeprom_read() - EEPROM read operation 677cfad6425SSerge Semin * @pdev: Pointer to the driver data 678cfad6425SSerge Semin * @memaddr: Start EEPROM memory address 679cfad6425SSerge Semin * @len: Length of data to read 680cfad6425SSerge Semin * @buf: Buffer to read data to 681cfad6425SSerge Semin */ 682cfad6425SSerge Semin static int idt_eeprom_read(struct idt_89hpesx_dev *pdev, u16 memaddr, u16 len, 683cfad6425SSerge Semin u8 *buf) 684cfad6425SSerge Semin { 685cfad6425SSerge Semin int ret; 686cfad6425SSerge Semin u16 idx; 687cfad6425SSerge Semin 688cfad6425SSerge Semin /* Read data byte-by-byte, retrying if it wasn't successful */ 689cfad6425SSerge Semin for (idx = 0; idx < len; idx++, memaddr++) { 690cfad6425SSerge Semin /* Lock IDT SMBus device */ 691cfad6425SSerge Semin mutex_lock(&pdev->smb_mtx); 692cfad6425SSerge Semin 693cfad6425SSerge Semin /* Just read the byte to the buffer */ 694cfad6425SSerge Semin ret = idt_eeprom_read_byte(pdev, memaddr, &buf[idx]); 695cfad6425SSerge Semin 696cfad6425SSerge Semin /* Unlock IDT SMBus device */ 697cfad6425SSerge Semin mutex_unlock(&pdev->smb_mtx); 698cfad6425SSerge Semin 699cfad6425SSerge Semin /* Return error if read operation failed */ 700cfad6425SSerge Semin if (ret != 0) 701cfad6425SSerge Semin return ret; 702cfad6425SSerge Semin } 703cfad6425SSerge Semin 704cfad6425SSerge Semin return 0; 705cfad6425SSerge Semin } 706cfad6425SSerge Semin 707cfad6425SSerge Semin /*=========================================================================== 708cfad6425SSerge Semin * CSR IO-operations 709cfad6425SSerge Semin *=========================================================================== 710cfad6425SSerge Semin */ 711cfad6425SSerge Semin 712cfad6425SSerge Semin /* 713cfad6425SSerge Semin * idt_csr_write() - CSR write operation 714cfad6425SSerge Semin * @pdev: Pointer to the driver data 715cfad6425SSerge Semin * @csraddr: CSR address (with no two LS bits) 716cfad6425SSerge Semin * @data: Data to be written to CSR 717cfad6425SSerge Semin */ 718cfad6425SSerge Semin static int idt_csr_write(struct idt_89hpesx_dev *pdev, u16 csraddr, 719cfad6425SSerge Semin const u32 data) 720cfad6425SSerge Semin { 721cfad6425SSerge Semin struct device *dev = &pdev->client->dev; 722cfad6425SSerge Semin struct idt_csr_seq csrseq; 723cfad6425SSerge Semin struct idt_smb_seq smbseq; 724cfad6425SSerge Semin int ret; 725cfad6425SSerge Semin 726cfad6425SSerge Semin /* Initialize SMBus sequence fields */ 727cfad6425SSerge Semin smbseq.ccode = pdev->iniccode | CCODE_CSR; 728cfad6425SSerge Semin smbseq.data = (u8 *)&csrseq; 729cfad6425SSerge Semin 730cfad6425SSerge Semin /* Lock IDT SMBus device */ 731cfad6425SSerge Semin mutex_lock(&pdev->smb_mtx); 732cfad6425SSerge Semin 733cfad6425SSerge Semin /* Perform write operation */ 734cfad6425SSerge Semin smbseq.bytecnt = CSR_WR_CNT; 735cfad6425SSerge Semin csrseq.cmd = pdev->inicsrcmd | CSR_OP_WRITE; 736cfad6425SSerge Semin csrseq.csraddr = cpu_to_le16(csraddr); 737cfad6425SSerge Semin csrseq.data = cpu_to_le32(data); 738cfad6425SSerge Semin ret = pdev->smb_write(pdev, &smbseq); 739cfad6425SSerge Semin if (ret != 0) { 740cfad6425SSerge Semin dev_err(dev, "Failed to write 0x%04x: 0x%04x to csr", 741cfad6425SSerge Semin CSR_REAL_ADDR(csraddr), data); 742cfad6425SSerge Semin goto err_mutex_unlock; 743cfad6425SSerge Semin } 744cfad6425SSerge Semin 745cfad6425SSerge Semin /* Send CSR address to read data from */ 746cfad6425SSerge Semin smbseq.bytecnt = CSR_WRRD_CNT; 747cfad6425SSerge Semin csrseq.cmd = pdev->inicsrcmd | CSR_OP_READ; 748cfad6425SSerge Semin ret = pdev->smb_write(pdev, &smbseq); 749cfad6425SSerge Semin if (ret != 0) { 750cfad6425SSerge Semin dev_err(dev, "Failed to init csr address 0x%04x", 751cfad6425SSerge Semin CSR_REAL_ADDR(csraddr)); 752cfad6425SSerge Semin goto err_mutex_unlock; 753cfad6425SSerge Semin } 754cfad6425SSerge Semin 755cfad6425SSerge Semin /* Perform read operation */ 756cfad6425SSerge Semin smbseq.bytecnt = CSR_RD_CNT; 757cfad6425SSerge Semin ret = pdev->smb_read(pdev, &smbseq); 758cfad6425SSerge Semin if (ret != 0) { 759cfad6425SSerge Semin dev_err(dev, "Failed to read csr 0x%04x", 760cfad6425SSerge Semin CSR_REAL_ADDR(csraddr)); 761cfad6425SSerge Semin goto err_mutex_unlock; 762cfad6425SSerge Semin } 763cfad6425SSerge Semin 764cfad6425SSerge Semin /* Check whether IDT successfully retrieved CSR data */ 765cfad6425SSerge Semin if (csrseq.cmd & (CSR_RERR | CSR_WERR)) { 766cfad6425SSerge Semin dev_err(dev, "IDT failed to perform CSR r/w"); 767cfad6425SSerge Semin ret = -EREMOTEIO; 768cfad6425SSerge Semin goto err_mutex_unlock; 769cfad6425SSerge Semin } 770cfad6425SSerge Semin 771cfad6425SSerge Semin /* Unlock IDT SMBus device */ 772cfad6425SSerge Semin err_mutex_unlock: 773cfad6425SSerge Semin mutex_unlock(&pdev->smb_mtx); 774cfad6425SSerge Semin 775cfad6425SSerge Semin return ret; 776cfad6425SSerge Semin } 777cfad6425SSerge Semin 778cfad6425SSerge Semin /* 779cfad6425SSerge Semin * idt_csr_read() - CSR read operation 780cfad6425SSerge Semin * @pdev: Pointer to the driver data 781cfad6425SSerge Semin * @csraddr: CSR address (with no two LS bits) 782cfad6425SSerge Semin * @data: Data to be written to CSR 783cfad6425SSerge Semin */ 784cfad6425SSerge Semin static int idt_csr_read(struct idt_89hpesx_dev *pdev, u16 csraddr, u32 *data) 785cfad6425SSerge Semin { 786cfad6425SSerge Semin struct device *dev = &pdev->client->dev; 787cfad6425SSerge Semin struct idt_csr_seq csrseq; 788cfad6425SSerge Semin struct idt_smb_seq smbseq; 789cfad6425SSerge Semin int ret; 790cfad6425SSerge Semin 791cfad6425SSerge Semin /* Initialize SMBus sequence fields */ 792cfad6425SSerge Semin smbseq.ccode = pdev->iniccode | CCODE_CSR; 793cfad6425SSerge Semin smbseq.data = (u8 *)&csrseq; 794cfad6425SSerge Semin 795cfad6425SSerge Semin /* Lock IDT SMBus device */ 796cfad6425SSerge Semin mutex_lock(&pdev->smb_mtx); 797cfad6425SSerge Semin 798cfad6425SSerge Semin /* Send CSR register address before reading it */ 799cfad6425SSerge Semin smbseq.bytecnt = CSR_WRRD_CNT; 800cfad6425SSerge Semin csrseq.cmd = pdev->inicsrcmd | CSR_OP_READ; 801cfad6425SSerge Semin csrseq.csraddr = cpu_to_le16(csraddr); 802cfad6425SSerge Semin ret = pdev->smb_write(pdev, &smbseq); 803cfad6425SSerge Semin if (ret != 0) { 804cfad6425SSerge Semin dev_err(dev, "Failed to init csr address 0x%04x", 805cfad6425SSerge Semin CSR_REAL_ADDR(csraddr)); 806cfad6425SSerge Semin goto err_mutex_unlock; 807cfad6425SSerge Semin } 808cfad6425SSerge Semin 809cfad6425SSerge Semin /* Perform read operation */ 810cfad6425SSerge Semin smbseq.bytecnt = CSR_RD_CNT; 811cfad6425SSerge Semin ret = pdev->smb_read(pdev, &smbseq); 812cfad6425SSerge Semin if (ret != 0) { 813*ffff4913SJustin Stitt dev_err(dev, "Failed to read csr 0x%04x", 814cfad6425SSerge Semin CSR_REAL_ADDR(csraddr)); 815cfad6425SSerge Semin goto err_mutex_unlock; 816cfad6425SSerge Semin } 817cfad6425SSerge Semin 818cfad6425SSerge Semin /* Check whether IDT successfully retrieved CSR data */ 819cfad6425SSerge Semin if (csrseq.cmd & (CSR_RERR | CSR_WERR)) { 820cfad6425SSerge Semin dev_err(dev, "IDT failed to perform CSR r/w"); 821cfad6425SSerge Semin ret = -EREMOTEIO; 822cfad6425SSerge Semin goto err_mutex_unlock; 823cfad6425SSerge Semin } 824cfad6425SSerge Semin 825cfad6425SSerge Semin /* Save data retrieved from IDT */ 826cfad6425SSerge Semin *data = le32_to_cpu(csrseq.data); 827cfad6425SSerge Semin 828cfad6425SSerge Semin /* Unlock IDT SMBus device */ 829cfad6425SSerge Semin err_mutex_unlock: 830cfad6425SSerge Semin mutex_unlock(&pdev->smb_mtx); 831cfad6425SSerge Semin 832cfad6425SSerge Semin return ret; 833cfad6425SSerge Semin } 834cfad6425SSerge Semin 835cfad6425SSerge Semin /*=========================================================================== 836cfad6425SSerge Semin * Sysfs/debugfs-nodes IO-operations 837cfad6425SSerge Semin *=========================================================================== 838cfad6425SSerge Semin */ 839cfad6425SSerge Semin 840cfad6425SSerge Semin /* 841cfad6425SSerge Semin * eeprom_write() - EEPROM sysfs-node write callback 842cfad6425SSerge Semin * @filep: Pointer to the file system node 843cfad6425SSerge Semin * @kobj: Pointer to the kernel object related to the sysfs-node 844cfad6425SSerge Semin * @attr: Attributes of the file 845cfad6425SSerge Semin * @buf: Buffer to write data to 846cfad6425SSerge Semin * @off: Offset at which data should be written to 847cfad6425SSerge Semin * @count: Number of bytes to write 848cfad6425SSerge Semin */ 849cfad6425SSerge Semin static ssize_t eeprom_write(struct file *filp, struct kobject *kobj, 850cfad6425SSerge Semin struct bin_attribute *attr, 851cfad6425SSerge Semin char *buf, loff_t off, size_t count) 852cfad6425SSerge Semin { 853cfad6425SSerge Semin struct idt_89hpesx_dev *pdev; 854cfad6425SSerge Semin int ret; 855cfad6425SSerge Semin 856cfad6425SSerge Semin /* Retrieve driver data */ 857cfad6425SSerge Semin pdev = dev_get_drvdata(kobj_to_dev(kobj)); 858cfad6425SSerge Semin 859cfad6425SSerge Semin /* Perform EEPROM write operation */ 860cfad6425SSerge Semin ret = idt_eeprom_write(pdev, (u16)off, (u16)count, (u8 *)buf); 861cfad6425SSerge Semin return (ret != 0 ? ret : count); 862cfad6425SSerge Semin } 863cfad6425SSerge Semin 864cfad6425SSerge Semin /* 865cfad6425SSerge Semin * eeprom_read() - EEPROM sysfs-node read callback 866cfad6425SSerge Semin * @filep: Pointer to the file system node 867cfad6425SSerge Semin * @kobj: Pointer to the kernel object related to the sysfs-node 868cfad6425SSerge Semin * @attr: Attributes of the file 869cfad6425SSerge Semin * @buf: Buffer to write data to 870cfad6425SSerge Semin * @off: Offset at which data should be written to 871cfad6425SSerge Semin * @count: Number of bytes to write 872cfad6425SSerge Semin */ 873cfad6425SSerge Semin static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, 874cfad6425SSerge Semin struct bin_attribute *attr, 875cfad6425SSerge Semin char *buf, loff_t off, size_t count) 876cfad6425SSerge Semin { 877cfad6425SSerge Semin struct idt_89hpesx_dev *pdev; 878cfad6425SSerge Semin int ret; 879cfad6425SSerge Semin 880cfad6425SSerge Semin /* Retrieve driver data */ 881cfad6425SSerge Semin pdev = dev_get_drvdata(kobj_to_dev(kobj)); 882cfad6425SSerge Semin 883cfad6425SSerge Semin /* Perform EEPROM read operation */ 884cfad6425SSerge Semin ret = idt_eeprom_read(pdev, (u16)off, (u16)count, (u8 *)buf); 885cfad6425SSerge Semin return (ret != 0 ? ret : count); 886cfad6425SSerge Semin } 887cfad6425SSerge Semin 888cfad6425SSerge Semin /* 889cfad6425SSerge Semin * idt_dbgfs_csr_write() - CSR debugfs-node write callback 890cfad6425SSerge Semin * @filep: Pointer to the file system file descriptor 891cfad6425SSerge Semin * @buf: Buffer to read data from 892cfad6425SSerge Semin * @count: Size of the buffer 893cfad6425SSerge Semin * @offp: Offset within the file 894cfad6425SSerge Semin * 895cfad6425SSerge Semin * It accepts either "0x<reg addr>:0x<value>" for saving register address 896cfad6425SSerge Semin * and writing value to specified DWORD register or "0x<reg addr>" for 897cfad6425SSerge Semin * just saving register address in order to perform next read operation. 898cfad6425SSerge Semin * 899cfad6425SSerge Semin * WARNING No spaces are allowed. Incoming string must be strictly formated as: 900cfad6425SSerge Semin * "<reg addr>:<value>". Register address must be aligned within 4 bytes 901cfad6425SSerge Semin * (one DWORD). 902cfad6425SSerge Semin */ 903cfad6425SSerge Semin static ssize_t idt_dbgfs_csr_write(struct file *filep, const char __user *ubuf, 904cfad6425SSerge Semin size_t count, loff_t *offp) 905cfad6425SSerge Semin { 906cfad6425SSerge Semin struct idt_89hpesx_dev *pdev = filep->private_data; 907cfad6425SSerge Semin char *colon_ch, *csraddr_str, *csrval_str; 9082e08b1dbSColin Ian King int ret, csraddr_len; 909cfad6425SSerge Semin u32 csraddr, csrval; 910cfad6425SSerge Semin char *buf; 911cfad6425SSerge Semin 912cfad6425SSerge Semin /* Copy data from User-space */ 913cfad6425SSerge Semin buf = kmalloc(count + 1, GFP_KERNEL); 914cfad6425SSerge Semin if (!buf) 915cfad6425SSerge Semin return -ENOMEM; 916cfad6425SSerge Semin 917cfad6425SSerge Semin ret = simple_write_to_buffer(buf, count, offp, ubuf, count); 918cfad6425SSerge Semin if (ret < 0) 919cfad6425SSerge Semin goto free_buf; 920cfad6425SSerge Semin buf[count] = 0; 921cfad6425SSerge Semin 922cfad6425SSerge Semin /* Find position of colon in the buffer */ 923cfad6425SSerge Semin colon_ch = strnchr(buf, count, ':'); 924cfad6425SSerge Semin 925cfad6425SSerge Semin /* 926cfad6425SSerge Semin * If there is colon passed then new CSR value should be parsed as 927cfad6425SSerge Semin * well, so allocate buffer for CSR address substring. 928cfad6425SSerge Semin * If no colon is found, then string must have just one number with 929cfad6425SSerge Semin * no new CSR value 930cfad6425SSerge Semin */ 931cfad6425SSerge Semin if (colon_ch != NULL) { 932cfad6425SSerge Semin csraddr_len = colon_ch - buf; 933cfad6425SSerge Semin csraddr_str = 9346da2ec56SKees Cook kmalloc(csraddr_len + 1, GFP_KERNEL); 935acf50ec7SColin Ian King if (csraddr_str == NULL) { 936acf50ec7SColin Ian King ret = -ENOMEM; 937acf50ec7SColin Ian King goto free_buf; 938acf50ec7SColin Ian King } 939cfad6425SSerge Semin /* Copy the register address to the substring buffer */ 940cfad6425SSerge Semin strncpy(csraddr_str, buf, csraddr_len); 941cfad6425SSerge Semin csraddr_str[csraddr_len] = '\0'; 942cfad6425SSerge Semin /* Register value must follow the colon */ 943cfad6425SSerge Semin csrval_str = colon_ch + 1; 944cfad6425SSerge Semin } else /* if (str_colon == NULL) */ { 945cfad6425SSerge Semin csraddr_str = (char *)buf; /* Just to shut warning up */ 946cfad6425SSerge Semin csraddr_len = strnlen(csraddr_str, count); 947cfad6425SSerge Semin csrval_str = NULL; 948cfad6425SSerge Semin } 949cfad6425SSerge Semin 950cfad6425SSerge Semin /* Convert CSR address to u32 value */ 951cfad6425SSerge Semin ret = kstrtou32(csraddr_str, 0, &csraddr); 952cfad6425SSerge Semin if (ret != 0) 953cfad6425SSerge Semin goto free_csraddr_str; 954cfad6425SSerge Semin 955cfad6425SSerge Semin /* Check whether passed register address is valid */ 956cfad6425SSerge Semin if (csraddr > CSR_MAX || !IS_ALIGNED(csraddr, SZ_4)) { 957cfad6425SSerge Semin ret = -EINVAL; 958cfad6425SSerge Semin goto free_csraddr_str; 959cfad6425SSerge Semin } 960cfad6425SSerge Semin 961cfad6425SSerge Semin /* Shift register address to the right so to have u16 address */ 962cfad6425SSerge Semin pdev->csr = (csraddr >> 2); 963cfad6425SSerge Semin 964cfad6425SSerge Semin /* Parse new CSR value and send it to IDT, if colon has been found */ 965cfad6425SSerge Semin if (colon_ch != NULL) { 966cfad6425SSerge Semin ret = kstrtou32(csrval_str, 0, &csrval); 967cfad6425SSerge Semin if (ret != 0) 968cfad6425SSerge Semin goto free_csraddr_str; 969cfad6425SSerge Semin 970cfad6425SSerge Semin ret = idt_csr_write(pdev, pdev->csr, csrval); 971cfad6425SSerge Semin if (ret != 0) 972cfad6425SSerge Semin goto free_csraddr_str; 973cfad6425SSerge Semin } 974cfad6425SSerge Semin 975cfad6425SSerge Semin /* Free memory only if colon has been found */ 976cfad6425SSerge Semin free_csraddr_str: 977cfad6425SSerge Semin if (colon_ch != NULL) 978cfad6425SSerge Semin kfree(csraddr_str); 979cfad6425SSerge Semin 980cfad6425SSerge Semin /* Free buffer allocated for data retrieved from User-space */ 981cfad6425SSerge Semin free_buf: 982cfad6425SSerge Semin kfree(buf); 983cfad6425SSerge Semin 984cfad6425SSerge Semin return (ret != 0 ? ret : count); 985cfad6425SSerge Semin } 986cfad6425SSerge Semin 987cfad6425SSerge Semin /* 988cfad6425SSerge Semin * idt_dbgfs_csr_read() - CSR debugfs-node read callback 989cfad6425SSerge Semin * @filep: Pointer to the file system file descriptor 990cfad6425SSerge Semin * @buf: Buffer to write data to 991cfad6425SSerge Semin * @count: Size of the buffer 992cfad6425SSerge Semin * @offp: Offset within the file 993cfad6425SSerge Semin * 994cfad6425SSerge Semin * It just prints the pair "0x<reg addr>:0x<value>" to passed buffer. 995cfad6425SSerge Semin */ 996cfad6425SSerge Semin #define CSRBUF_SIZE ((size_t)32) 997cfad6425SSerge Semin static ssize_t idt_dbgfs_csr_read(struct file *filep, char __user *ubuf, 998cfad6425SSerge Semin size_t count, loff_t *offp) 999cfad6425SSerge Semin { 1000cfad6425SSerge Semin struct idt_89hpesx_dev *pdev = filep->private_data; 1001cfad6425SSerge Semin u32 csraddr, csrval; 1002cfad6425SSerge Semin char buf[CSRBUF_SIZE]; 1003cfad6425SSerge Semin int ret, size; 1004cfad6425SSerge Semin 1005cfad6425SSerge Semin /* Perform CSR read operation */ 1006cfad6425SSerge Semin ret = idt_csr_read(pdev, pdev->csr, &csrval); 1007cfad6425SSerge Semin if (ret != 0) 1008cfad6425SSerge Semin return ret; 1009cfad6425SSerge Semin 1010cfad6425SSerge Semin /* Shift register address to the left so to have real address */ 1011cfad6425SSerge Semin csraddr = ((u32)pdev->csr << 2); 1012cfad6425SSerge Semin 1013cfad6425SSerge Semin /* Print the "0x<reg addr>:0x<value>" to buffer */ 1014cfad6425SSerge Semin size = snprintf(buf, CSRBUF_SIZE, "0x%05x:0x%08x\n", 1015cfad6425SSerge Semin (unsigned int)csraddr, (unsigned int)csrval); 1016cfad6425SSerge Semin 1017cfad6425SSerge Semin /* Copy data to User-space */ 1018cfad6425SSerge Semin return simple_read_from_buffer(ubuf, count, offp, buf, size); 1019cfad6425SSerge Semin } 1020cfad6425SSerge Semin 1021cfad6425SSerge Semin /* 1022cfad6425SSerge Semin * eeprom_attribute - EEPROM sysfs-node attributes 1023cfad6425SSerge Semin * 1024cfad6425SSerge Semin * NOTE Size will be changed in compliance with OF node. EEPROM attribute will 1025cfad6425SSerge Semin * be read-only as well if the corresponding flag is specified in OF node. 1026cfad6425SSerge Semin */ 1027cfad6425SSerge Semin static BIN_ATTR_RW(eeprom, EEPROM_DEF_SIZE); 1028cfad6425SSerge Semin 1029cfad6425SSerge Semin /* 1030cfad6425SSerge Semin * csr_dbgfs_ops - CSR debugfs-node read/write operations 1031cfad6425SSerge Semin */ 1032cfad6425SSerge Semin static const struct file_operations csr_dbgfs_ops = { 1033cfad6425SSerge Semin .owner = THIS_MODULE, 1034cfad6425SSerge Semin .open = simple_open, 1035cfad6425SSerge Semin .write = idt_dbgfs_csr_write, 1036cfad6425SSerge Semin .read = idt_dbgfs_csr_read 1037cfad6425SSerge Semin }; 1038cfad6425SSerge Semin 1039cfad6425SSerge Semin /*=========================================================================== 1040cfad6425SSerge Semin * Driver init/deinit methods 1041cfad6425SSerge Semin *=========================================================================== 1042cfad6425SSerge Semin */ 1043cfad6425SSerge Semin 1044cfad6425SSerge Semin /* 1045cfad6425SSerge Semin * idt_set_defval() - disable EEPROM access by default 1046cfad6425SSerge Semin * @pdev: Pointer to the driver data 1047cfad6425SSerge Semin */ 1048cfad6425SSerge Semin static void idt_set_defval(struct idt_89hpesx_dev *pdev) 1049cfad6425SSerge Semin { 1050cfad6425SSerge Semin /* If OF info is missing then use next values */ 1051cfad6425SSerge Semin pdev->eesize = 0; 1052cfad6425SSerge Semin pdev->eero = true; 1053cfad6425SSerge Semin pdev->inieecmd = 0; 1054cfad6425SSerge Semin pdev->eeaddr = 0; 1055cfad6425SSerge Semin } 1056cfad6425SSerge Semin 1057cfad6425SSerge Semin static const struct i2c_device_id ee_ids[]; 1058db15d73eSHuy Duong 1059cfad6425SSerge Semin /* 1060cfad6425SSerge Semin * idt_ee_match_id() - check whether the node belongs to compatible EEPROMs 1061cfad6425SSerge Semin */ 1062db15d73eSHuy Duong static const struct i2c_device_id *idt_ee_match_id(struct fwnode_handle *fwnode) 1063cfad6425SSerge Semin { 1064cfad6425SSerge Semin const struct i2c_device_id *id = ee_ids; 1065db15d73eSHuy Duong const char *compatible, *p; 1066cfad6425SSerge Semin char devname[I2C_NAME_SIZE]; 1067db15d73eSHuy Duong int ret; 1068cfad6425SSerge Semin 1069db15d73eSHuy Duong ret = fwnode_property_read_string(fwnode, "compatible", &compatible); 1070db15d73eSHuy Duong if (ret) 1071cfad6425SSerge Semin return NULL; 1072cfad6425SSerge Semin 1073db15d73eSHuy Duong p = strchr(compatible, ','); 1074db15d73eSHuy Duong strlcpy(devname, p ? p + 1 : compatible, sizeof(devname)); 1075cfad6425SSerge Semin /* Search through the device name */ 1076cfad6425SSerge Semin while (id->name[0]) { 1077cfad6425SSerge Semin if (strcmp(devname, id->name) == 0) 1078cfad6425SSerge Semin return id; 1079cfad6425SSerge Semin id++; 1080cfad6425SSerge Semin } 1081cfad6425SSerge Semin return NULL; 1082cfad6425SSerge Semin } 1083cfad6425SSerge Semin 1084cfad6425SSerge Semin /* 1085db15d73eSHuy Duong * idt_get_fw_data() - get IDT i2c-device parameters from device tree 1086cfad6425SSerge Semin * @pdev: Pointer to the driver data 1087cfad6425SSerge Semin */ 1088db15d73eSHuy Duong static void idt_get_fw_data(struct idt_89hpesx_dev *pdev) 1089cfad6425SSerge Semin { 1090cfad6425SSerge Semin struct device *dev = &pdev->client->dev; 1091db15d73eSHuy Duong struct fwnode_handle *fwnode; 1092cfad6425SSerge Semin const struct i2c_device_id *ee_id = NULL; 1093db15d73eSHuy Duong u32 eeprom_addr; 1094db15d73eSHuy Duong int ret; 1095cfad6425SSerge Semin 1096db15d73eSHuy Duong device_for_each_child_node(dev, fwnode) { 1097db15d73eSHuy Duong ee_id = idt_ee_match_id(fwnode); 1098e0db3deeSAndy Shevchenko if (ee_id) 1099cfad6425SSerge Semin break; 1100e0db3deeSAndy Shevchenko 1101e0db3deeSAndy Shevchenko dev_warn(dev, "Skip unsupported EEPROM device %pfw\n", fwnode); 1102cfad6425SSerge Semin } 1103cfad6425SSerge Semin 1104db15d73eSHuy Duong /* If there is no fwnode EEPROM device, then set zero size */ 1105cfad6425SSerge Semin if (!ee_id) { 1106db15d73eSHuy Duong dev_warn(dev, "No fwnode, EEPROM access disabled"); 1107cfad6425SSerge Semin idt_set_defval(pdev); 1108cfad6425SSerge Semin return; 1109cfad6425SSerge Semin } 1110cfad6425SSerge Semin 1111cfad6425SSerge Semin /* Retrieve EEPROM size */ 1112cfad6425SSerge Semin pdev->eesize = (u32)ee_id->driver_data; 1113cfad6425SSerge Semin 1114cfad6425SSerge Semin /* Get custom EEPROM address from 'reg' attribute */ 1115db15d73eSHuy Duong ret = fwnode_property_read_u32(fwnode, "reg", &eeprom_addr); 1116db15d73eSHuy Duong if (ret || (eeprom_addr == 0)) { 1117db15d73eSHuy Duong dev_warn(dev, "No EEPROM reg found, use default address 0x%x", 1118db15d73eSHuy Duong EEPROM_DEF_ADDR); 1119cfad6425SSerge Semin pdev->inieecmd = 0; 1120cfad6425SSerge Semin pdev->eeaddr = EEPROM_DEF_ADDR << 1; 1121cfad6425SSerge Semin } else { 1122cfad6425SSerge Semin pdev->inieecmd = EEPROM_USA; 1123db15d73eSHuy Duong pdev->eeaddr = eeprom_addr << 1; 1124cfad6425SSerge Semin } 1125cfad6425SSerge Semin 1126cfad6425SSerge Semin /* Check EEPROM 'read-only' flag */ 1127db15d73eSHuy Duong if (fwnode_property_read_bool(fwnode, "read-only")) 1128cfad6425SSerge Semin pdev->eero = true; 1129db15d73eSHuy Duong else /* if (!fwnode_property_read_bool(node, "read-only")) */ 1130cfad6425SSerge Semin pdev->eero = false; 1131cfad6425SSerge Semin 11323f6ee1c0SAndy Shevchenko fwnode_handle_put(fwnode); 1133db15d73eSHuy Duong dev_info(dev, "EEPROM of %d bytes found by 0x%x", 1134cfad6425SSerge Semin pdev->eesize, pdev->eeaddr); 1135cfad6425SSerge Semin } 1136cfad6425SSerge Semin 1137cfad6425SSerge Semin /* 1138cfad6425SSerge Semin * idt_create_pdev() - create and init data structure of the driver 1139cfad6425SSerge Semin * @client: i2c client of IDT PCIe-switch device 1140cfad6425SSerge Semin */ 1141cfad6425SSerge Semin static struct idt_89hpesx_dev *idt_create_pdev(struct i2c_client *client) 1142cfad6425SSerge Semin { 1143cfad6425SSerge Semin struct idt_89hpesx_dev *pdev; 1144cfad6425SSerge Semin 1145cfad6425SSerge Semin /* Allocate memory for driver data */ 1146cfad6425SSerge Semin pdev = devm_kmalloc(&client->dev, sizeof(struct idt_89hpesx_dev), 1147cfad6425SSerge Semin GFP_KERNEL); 1148cfad6425SSerge Semin if (pdev == NULL) 1149cfad6425SSerge Semin return ERR_PTR(-ENOMEM); 1150cfad6425SSerge Semin 1151cfad6425SSerge Semin /* Initialize basic fields of the data */ 1152cfad6425SSerge Semin pdev->client = client; 1153cfad6425SSerge Semin i2c_set_clientdata(client, pdev); 1154cfad6425SSerge Semin 1155db15d73eSHuy Duong /* Read firmware nodes information */ 1156db15d73eSHuy Duong idt_get_fw_data(pdev); 1157cfad6425SSerge Semin 1158cfad6425SSerge Semin /* Initialize basic CSR CMD field - use full DWORD-sized r/w ops */ 1159cfad6425SSerge Semin pdev->inicsrcmd = CSR_DWE; 1160cfad6425SSerge Semin pdev->csr = CSR_DEF; 1161cfad6425SSerge Semin 1162cfad6425SSerge Semin /* Enable Packet Error Checking if it's supported by adapter */ 1163cfad6425SSerge Semin if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_PEC)) { 1164cfad6425SSerge Semin pdev->iniccode = CCODE_PEC; 1165cfad6425SSerge Semin client->flags |= I2C_CLIENT_PEC; 1166cfad6425SSerge Semin } else /* PEC is unsupported */ { 1167cfad6425SSerge Semin pdev->iniccode = 0; 1168cfad6425SSerge Semin } 1169cfad6425SSerge Semin 1170cfad6425SSerge Semin return pdev; 1171cfad6425SSerge Semin } 1172cfad6425SSerge Semin 1173cfad6425SSerge Semin /* 1174cfad6425SSerge Semin * idt_free_pdev() - free data structure of the driver 1175cfad6425SSerge Semin * @pdev: Pointer to the driver data 1176cfad6425SSerge Semin */ 1177cfad6425SSerge Semin static void idt_free_pdev(struct idt_89hpesx_dev *pdev) 1178cfad6425SSerge Semin { 1179cfad6425SSerge Semin /* Clear driver data from device private field */ 1180cfad6425SSerge Semin i2c_set_clientdata(pdev->client, NULL); 1181cfad6425SSerge Semin } 1182cfad6425SSerge Semin 1183cfad6425SSerge Semin /* 1184cfad6425SSerge Semin * idt_set_smbus_ops() - set supported SMBus operations 1185cfad6425SSerge Semin * @pdev: Pointer to the driver data 1186cfad6425SSerge Semin * Return status of smbus check operations 1187cfad6425SSerge Semin */ 1188cfad6425SSerge Semin static int idt_set_smbus_ops(struct idt_89hpesx_dev *pdev) 1189cfad6425SSerge Semin { 1190cfad6425SSerge Semin struct i2c_adapter *adapter = pdev->client->adapter; 1191cfad6425SSerge Semin struct device *dev = &pdev->client->dev; 1192cfad6425SSerge Semin 1193cfad6425SSerge Semin /* Check i2c adapter read functionality */ 1194cfad6425SSerge Semin if (i2c_check_functionality(adapter, 1195cfad6425SSerge Semin I2C_FUNC_SMBUS_READ_BLOCK_DATA)) { 1196cfad6425SSerge Semin pdev->smb_read = idt_smb_read_block; 1197cfad6425SSerge Semin dev_dbg(dev, "SMBus block-read op chosen"); 1198cfad6425SSerge Semin } else if (i2c_check_functionality(adapter, 1199cfad6425SSerge Semin I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { 1200cfad6425SSerge Semin pdev->smb_read = idt_smb_read_i2c_block; 1201cfad6425SSerge Semin dev_dbg(dev, "SMBus i2c-block-read op chosen"); 1202cfad6425SSerge Semin } else if (i2c_check_functionality(adapter, 1203cfad6425SSerge Semin I2C_FUNC_SMBUS_READ_WORD_DATA) && 1204cfad6425SSerge Semin i2c_check_functionality(adapter, 1205cfad6425SSerge Semin I2C_FUNC_SMBUS_READ_BYTE_DATA)) { 1206cfad6425SSerge Semin pdev->smb_read = idt_smb_read_word; 1207cfad6425SSerge Semin dev_warn(dev, "Use slow word/byte SMBus read ops"); 1208cfad6425SSerge Semin } else if (i2c_check_functionality(adapter, 1209cfad6425SSerge Semin I2C_FUNC_SMBUS_READ_BYTE_DATA)) { 1210cfad6425SSerge Semin pdev->smb_read = idt_smb_read_byte; 1211cfad6425SSerge Semin dev_warn(dev, "Use slow byte SMBus read op"); 1212cfad6425SSerge Semin } else /* no supported smbus read operations */ { 1213cfad6425SSerge Semin dev_err(dev, "No supported SMBus read op"); 1214cfad6425SSerge Semin return -EPFNOSUPPORT; 1215cfad6425SSerge Semin } 1216cfad6425SSerge Semin 1217cfad6425SSerge Semin /* Check i2c adapter write functionality */ 1218cfad6425SSerge Semin if (i2c_check_functionality(adapter, 1219cfad6425SSerge Semin I2C_FUNC_SMBUS_WRITE_BLOCK_DATA)) { 1220cfad6425SSerge Semin pdev->smb_write = idt_smb_write_block; 1221cfad6425SSerge Semin dev_dbg(dev, "SMBus block-write op chosen"); 1222cfad6425SSerge Semin } else if (i2c_check_functionality(adapter, 1223cfad6425SSerge Semin I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) { 1224cfad6425SSerge Semin pdev->smb_write = idt_smb_write_i2c_block; 1225cfad6425SSerge Semin dev_dbg(dev, "SMBus i2c-block-write op chosen"); 1226cfad6425SSerge Semin } else if (i2c_check_functionality(adapter, 1227cfad6425SSerge Semin I2C_FUNC_SMBUS_WRITE_WORD_DATA) && 1228cfad6425SSerge Semin i2c_check_functionality(adapter, 1229cfad6425SSerge Semin I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) { 1230cfad6425SSerge Semin pdev->smb_write = idt_smb_write_word; 1231cfad6425SSerge Semin dev_warn(dev, "Use slow word/byte SMBus write op"); 1232cfad6425SSerge Semin } else if (i2c_check_functionality(adapter, 1233cfad6425SSerge Semin I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) { 1234cfad6425SSerge Semin pdev->smb_write = idt_smb_write_byte; 1235cfad6425SSerge Semin dev_warn(dev, "Use slow byte SMBus write op"); 1236cfad6425SSerge Semin } else /* no supported smbus write operations */ { 1237cfad6425SSerge Semin dev_err(dev, "No supported SMBus write op"); 1238cfad6425SSerge Semin return -EPFNOSUPPORT; 1239cfad6425SSerge Semin } 1240cfad6425SSerge Semin 1241cfad6425SSerge Semin /* Initialize IDT SMBus slave interface mutex */ 1242cfad6425SSerge Semin mutex_init(&pdev->smb_mtx); 1243cfad6425SSerge Semin 1244cfad6425SSerge Semin return 0; 1245cfad6425SSerge Semin } 1246cfad6425SSerge Semin 1247cfad6425SSerge Semin /* 1248cfad6425SSerge Semin * idt_check_dev() - check whether it's really IDT 89HPESx device 1249cfad6425SSerge Semin * @pdev: Pointer to the driver data 1250cfad6425SSerge Semin * Return status of i2c adapter check operation 1251cfad6425SSerge Semin */ 1252cfad6425SSerge Semin static int idt_check_dev(struct idt_89hpesx_dev *pdev) 1253cfad6425SSerge Semin { 1254cfad6425SSerge Semin struct device *dev = &pdev->client->dev; 1255cfad6425SSerge Semin u32 viddid; 1256cfad6425SSerge Semin int ret; 1257cfad6425SSerge Semin 1258cfad6425SSerge Semin /* Read VID and DID directly from IDT memory space */ 1259cfad6425SSerge Semin ret = idt_csr_read(pdev, IDT_VIDDID_CSR, &viddid); 1260cfad6425SSerge Semin if (ret != 0) { 1261cfad6425SSerge Semin dev_err(dev, "Failed to read VID/DID"); 1262cfad6425SSerge Semin return ret; 1263cfad6425SSerge Semin } 1264cfad6425SSerge Semin 1265cfad6425SSerge Semin /* Check whether it's IDT device */ 1266cfad6425SSerge Semin if ((viddid & IDT_VID_MASK) != PCI_VENDOR_ID_IDT) { 1267cfad6425SSerge Semin dev_err(dev, "Got unsupported VID/DID: 0x%08x", viddid); 1268cfad6425SSerge Semin return -ENODEV; 1269cfad6425SSerge Semin } 1270cfad6425SSerge Semin 1271cfad6425SSerge Semin dev_info(dev, "Found IDT 89HPES device VID:0x%04x, DID:0x%04x", 1272cfad6425SSerge Semin (viddid & IDT_VID_MASK), (viddid >> 16)); 1273cfad6425SSerge Semin 1274cfad6425SSerge Semin return 0; 1275cfad6425SSerge Semin } 1276cfad6425SSerge Semin 1277cfad6425SSerge Semin /* 1278cfad6425SSerge Semin * idt_create_sysfs_files() - create sysfs attribute files 1279cfad6425SSerge Semin * @pdev: Pointer to the driver data 1280cfad6425SSerge Semin * Return status of operation 1281cfad6425SSerge Semin */ 1282cfad6425SSerge Semin static int idt_create_sysfs_files(struct idt_89hpesx_dev *pdev) 1283cfad6425SSerge Semin { 1284cfad6425SSerge Semin struct device *dev = &pdev->client->dev; 1285cfad6425SSerge Semin int ret; 1286cfad6425SSerge Semin 1287cfad6425SSerge Semin /* Don't do anything if EEPROM isn't accessible */ 1288cfad6425SSerge Semin if (pdev->eesize == 0) { 1289cfad6425SSerge Semin dev_dbg(dev, "Skip creating sysfs-files"); 1290cfad6425SSerge Semin return 0; 1291cfad6425SSerge Semin } 1292cfad6425SSerge Semin 1293cfad6425SSerge Semin /* Allocate memory for attribute file */ 1294cfad6425SSerge Semin pdev->ee_file = devm_kmalloc(dev, sizeof(*pdev->ee_file), GFP_KERNEL); 1295cfad6425SSerge Semin if (!pdev->ee_file) 1296cfad6425SSerge Semin return -ENOMEM; 1297cfad6425SSerge Semin 1298cfad6425SSerge Semin /* Copy the declared EEPROM attr structure to change some of fields */ 1299cfad6425SSerge Semin memcpy(pdev->ee_file, &bin_attr_eeprom, sizeof(*pdev->ee_file)); 1300cfad6425SSerge Semin 1301cfad6425SSerge Semin /* In case of read-only EEPROM get rid of write ability */ 1302cfad6425SSerge Semin if (pdev->eero) { 1303cfad6425SSerge Semin pdev->ee_file->attr.mode &= ~0200; 1304cfad6425SSerge Semin pdev->ee_file->write = NULL; 1305cfad6425SSerge Semin } 1306cfad6425SSerge Semin /* Create EEPROM sysfs file */ 1307cfad6425SSerge Semin pdev->ee_file->size = pdev->eesize; 1308cfad6425SSerge Semin ret = sysfs_create_bin_file(&dev->kobj, pdev->ee_file); 1309cfad6425SSerge Semin if (ret != 0) { 1310cfad6425SSerge Semin dev_err(dev, "Failed to create EEPROM sysfs-node"); 1311cfad6425SSerge Semin return ret; 1312cfad6425SSerge Semin } 1313cfad6425SSerge Semin 1314cfad6425SSerge Semin return 0; 1315cfad6425SSerge Semin } 1316cfad6425SSerge Semin 1317cfad6425SSerge Semin /* 1318cfad6425SSerge Semin * idt_remove_sysfs_files() - remove sysfs attribute files 1319cfad6425SSerge Semin * @pdev: Pointer to the driver data 1320cfad6425SSerge Semin */ 1321cfad6425SSerge Semin static void idt_remove_sysfs_files(struct idt_89hpesx_dev *pdev) 1322cfad6425SSerge Semin { 1323cfad6425SSerge Semin struct device *dev = &pdev->client->dev; 1324cfad6425SSerge Semin 1325cfad6425SSerge Semin /* Don't do anything if EEPROM wasn't accessible */ 1326cfad6425SSerge Semin if (pdev->eesize == 0) 1327cfad6425SSerge Semin return; 1328cfad6425SSerge Semin 1329cfad6425SSerge Semin /* Remove EEPROM sysfs file */ 1330cfad6425SSerge Semin sysfs_remove_bin_file(&dev->kobj, pdev->ee_file); 1331cfad6425SSerge Semin } 1332cfad6425SSerge Semin 1333cfad6425SSerge Semin /* 1334cfad6425SSerge Semin * idt_create_dbgfs_files() - create debugfs files 1335cfad6425SSerge Semin * @pdev: Pointer to the driver data 1336cfad6425SSerge Semin */ 1337cfad6425SSerge Semin #define CSRNAME_LEN ((size_t)32) 1338cfad6425SSerge Semin static void idt_create_dbgfs_files(struct idt_89hpesx_dev *pdev) 1339cfad6425SSerge Semin { 1340cfad6425SSerge Semin struct i2c_client *cli = pdev->client; 1341cfad6425SSerge Semin char fname[CSRNAME_LEN]; 1342cfad6425SSerge Semin 1343cfad6425SSerge Semin /* Create Debugfs directory for CSR file */ 1344cfad6425SSerge Semin snprintf(fname, CSRNAME_LEN, "%d-%04hx", cli->adapter->nr, cli->addr); 1345cfad6425SSerge Semin pdev->csr_dir = debugfs_create_dir(fname, csr_dbgdir); 1346cfad6425SSerge Semin 1347cfad6425SSerge Semin /* Create Debugfs file for CSR read/write operations */ 1348f506a547SGreg Kroah-Hartman debugfs_create_file(cli->name, 0600, pdev->csr_dir, pdev, 1349f506a547SGreg Kroah-Hartman &csr_dbgfs_ops); 1350cfad6425SSerge Semin } 1351cfad6425SSerge Semin 1352cfad6425SSerge Semin /* 1353cfad6425SSerge Semin * idt_remove_dbgfs_files() - remove debugfs files 1354cfad6425SSerge Semin * @pdev: Pointer to the driver data 1355cfad6425SSerge Semin */ 1356cfad6425SSerge Semin static void idt_remove_dbgfs_files(struct idt_89hpesx_dev *pdev) 1357cfad6425SSerge Semin { 1358cfad6425SSerge Semin /* Remove CSR directory and it sysfs-node */ 1359cfad6425SSerge Semin debugfs_remove_recursive(pdev->csr_dir); 1360cfad6425SSerge Semin } 1361cfad6425SSerge Semin 1362cfad6425SSerge Semin /* 1363cfad6425SSerge Semin * idt_probe() - IDT 89HPESx driver probe() callback method 1364cfad6425SSerge Semin */ 1365cfad6425SSerge Semin static int idt_probe(struct i2c_client *client, const struct i2c_device_id *id) 1366cfad6425SSerge Semin { 1367cfad6425SSerge Semin struct idt_89hpesx_dev *pdev; 1368cfad6425SSerge Semin int ret; 1369cfad6425SSerge Semin 1370cfad6425SSerge Semin /* Create driver data */ 1371cfad6425SSerge Semin pdev = idt_create_pdev(client); 1372cfad6425SSerge Semin if (IS_ERR(pdev)) 1373cfad6425SSerge Semin return PTR_ERR(pdev); 1374cfad6425SSerge Semin 1375cfad6425SSerge Semin /* Set SMBus operations */ 1376cfad6425SSerge Semin ret = idt_set_smbus_ops(pdev); 1377cfad6425SSerge Semin if (ret != 0) 1378cfad6425SSerge Semin goto err_free_pdev; 1379cfad6425SSerge Semin 1380cfad6425SSerge Semin /* Check whether it is truly IDT 89HPESx device */ 1381cfad6425SSerge Semin ret = idt_check_dev(pdev); 1382cfad6425SSerge Semin if (ret != 0) 1383cfad6425SSerge Semin goto err_free_pdev; 1384cfad6425SSerge Semin 1385cfad6425SSerge Semin /* Create sysfs files */ 1386cfad6425SSerge Semin ret = idt_create_sysfs_files(pdev); 1387cfad6425SSerge Semin if (ret != 0) 1388cfad6425SSerge Semin goto err_free_pdev; 1389cfad6425SSerge Semin 1390cfad6425SSerge Semin /* Create debugfs files */ 1391cfad6425SSerge Semin idt_create_dbgfs_files(pdev); 1392cfad6425SSerge Semin 1393cfad6425SSerge Semin return 0; 1394cfad6425SSerge Semin 1395cfad6425SSerge Semin err_free_pdev: 1396cfad6425SSerge Semin idt_free_pdev(pdev); 1397cfad6425SSerge Semin 1398cfad6425SSerge Semin return ret; 1399cfad6425SSerge Semin } 1400cfad6425SSerge Semin 1401cfad6425SSerge Semin /* 1402cfad6425SSerge Semin * idt_remove() - IDT 89HPESx driver remove() callback method 1403cfad6425SSerge Semin */ 1404cfad6425SSerge Semin static int idt_remove(struct i2c_client *client) 1405cfad6425SSerge Semin { 1406cfad6425SSerge Semin struct idt_89hpesx_dev *pdev = i2c_get_clientdata(client); 1407cfad6425SSerge Semin 1408cfad6425SSerge Semin /* Remove debugfs files first */ 1409cfad6425SSerge Semin idt_remove_dbgfs_files(pdev); 1410cfad6425SSerge Semin 1411cfad6425SSerge Semin /* Remove sysfs files */ 1412cfad6425SSerge Semin idt_remove_sysfs_files(pdev); 1413cfad6425SSerge Semin 1414cfad6425SSerge Semin /* Discard driver data structure */ 1415cfad6425SSerge Semin idt_free_pdev(pdev); 1416cfad6425SSerge Semin 1417cfad6425SSerge Semin return 0; 1418cfad6425SSerge Semin } 1419cfad6425SSerge Semin 1420cfad6425SSerge Semin /* 1421cfad6425SSerge Semin * ee_ids - array of supported EEPROMs 1422cfad6425SSerge Semin */ 1423cfad6425SSerge Semin static const struct i2c_device_id ee_ids[] = { 1424cfad6425SSerge Semin { "24c32", 4096}, 1425cfad6425SSerge Semin { "24c64", 8192}, 1426cfad6425SSerge Semin { "24c128", 16384}, 1427cfad6425SSerge Semin { "24c256", 32768}, 1428cfad6425SSerge Semin { "24c512", 65536}, 1429cfad6425SSerge Semin {} 1430cfad6425SSerge Semin }; 1431cfad6425SSerge Semin MODULE_DEVICE_TABLE(i2c, ee_ids); 1432cfad6425SSerge Semin 1433cfad6425SSerge Semin /* 1434cfad6425SSerge Semin * idt_ids - supported IDT 89HPESx devices 1435cfad6425SSerge Semin */ 1436cfad6425SSerge Semin static const struct i2c_device_id idt_ids[] = { 1437cfad6425SSerge Semin { "89hpes8nt2", 0 }, 1438cfad6425SSerge Semin { "89hpes12nt3", 0 }, 1439cfad6425SSerge Semin 1440cfad6425SSerge Semin { "89hpes24nt6ag2", 0 }, 1441cfad6425SSerge Semin { "89hpes32nt8ag2", 0 }, 1442cfad6425SSerge Semin { "89hpes32nt8bg2", 0 }, 1443cfad6425SSerge Semin { "89hpes12nt12g2", 0 }, 1444cfad6425SSerge Semin { "89hpes16nt16g2", 0 }, 1445cfad6425SSerge Semin { "89hpes24nt24g2", 0 }, 1446cfad6425SSerge Semin { "89hpes32nt24ag2", 0 }, 1447cfad6425SSerge Semin { "89hpes32nt24bg2", 0 }, 1448cfad6425SSerge Semin 1449cfad6425SSerge Semin { "89hpes12n3", 0 }, 1450cfad6425SSerge Semin { "89hpes12n3a", 0 }, 1451cfad6425SSerge Semin { "89hpes24n3", 0 }, 1452cfad6425SSerge Semin { "89hpes24n3a", 0 }, 1453cfad6425SSerge Semin 1454cfad6425SSerge Semin { "89hpes32h8", 0 }, 1455cfad6425SSerge Semin { "89hpes32h8g2", 0 }, 1456cfad6425SSerge Semin { "89hpes48h12", 0 }, 1457cfad6425SSerge Semin { "89hpes48h12g2", 0 }, 1458cfad6425SSerge Semin { "89hpes48h12ag2", 0 }, 1459cfad6425SSerge Semin { "89hpes16h16", 0 }, 1460cfad6425SSerge Semin { "89hpes22h16", 0 }, 1461cfad6425SSerge Semin { "89hpes22h16g2", 0 }, 1462cfad6425SSerge Semin { "89hpes34h16", 0 }, 1463cfad6425SSerge Semin { "89hpes34h16g2", 0 }, 1464cfad6425SSerge Semin { "89hpes64h16", 0 }, 1465cfad6425SSerge Semin { "89hpes64h16g2", 0 }, 1466cfad6425SSerge Semin { "89hpes64h16ag2", 0 }, 1467cfad6425SSerge Semin 1468cfad6425SSerge Semin /* { "89hpes3t3", 0 }, // No SMBus-slave iface */ 1469cfad6425SSerge Semin { "89hpes12t3g2", 0 }, 1470cfad6425SSerge Semin { "89hpes24t3g2", 0 }, 1471cfad6425SSerge Semin /* { "89hpes4t4", 0 }, // No SMBus-slave iface */ 1472cfad6425SSerge Semin { "89hpes16t4", 0 }, 1473cfad6425SSerge Semin { "89hpes4t4g2", 0 }, 1474cfad6425SSerge Semin { "89hpes10t4g2", 0 }, 1475cfad6425SSerge Semin { "89hpes16t4g2", 0 }, 1476cfad6425SSerge Semin { "89hpes16t4ag2", 0 }, 1477cfad6425SSerge Semin { "89hpes5t5", 0 }, 1478cfad6425SSerge Semin { "89hpes6t5", 0 }, 1479cfad6425SSerge Semin { "89hpes8t5", 0 }, 1480cfad6425SSerge Semin { "89hpes8t5a", 0 }, 1481cfad6425SSerge Semin { "89hpes24t6", 0 }, 1482cfad6425SSerge Semin { "89hpes6t6g2", 0 }, 1483cfad6425SSerge Semin { "89hpes24t6g2", 0 }, 1484cfad6425SSerge Semin { "89hpes16t7", 0 }, 1485cfad6425SSerge Semin { "89hpes32t8", 0 }, 1486cfad6425SSerge Semin { "89hpes32t8g2", 0 }, 1487cfad6425SSerge Semin { "89hpes48t12", 0 }, 1488cfad6425SSerge Semin { "89hpes48t12g2", 0 }, 1489cfad6425SSerge Semin { /* END OF LIST */ } 1490cfad6425SSerge Semin }; 1491cfad6425SSerge Semin MODULE_DEVICE_TABLE(i2c, idt_ids); 1492cfad6425SSerge Semin 1493615cdd7cSJavier Martinez Canillas static const struct of_device_id idt_of_match[] = { 1494615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes8nt2", }, 1495615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes12nt3", }, 1496615cdd7cSJavier Martinez Canillas 1497615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes24nt6ag2", }, 1498615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes32nt8ag2", }, 1499615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes32nt8bg2", }, 1500615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes12nt12g2", }, 1501615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes16nt16g2", }, 1502615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes24nt24g2", }, 1503615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes32nt24ag2", }, 1504615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes32nt24bg2", }, 1505615cdd7cSJavier Martinez Canillas 1506615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes12n3", }, 1507615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes12n3a", }, 1508615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes24n3", }, 1509615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes24n3a", }, 1510615cdd7cSJavier Martinez Canillas 1511615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes32h8", }, 1512615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes32h8g2", }, 1513615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes48h12", }, 1514615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes48h12g2", }, 1515615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes48h12ag2", }, 1516615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes16h16", }, 1517615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes22h16", }, 1518615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes22h16g2", }, 1519615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes34h16", }, 1520615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes34h16g2", }, 1521615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes64h16", }, 1522615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes64h16g2", }, 1523615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes64h16ag2", }, 1524615cdd7cSJavier Martinez Canillas 1525615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes12t3g2", }, 1526615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes24t3g2", }, 1527615cdd7cSJavier Martinez Canillas 1528615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes16t4", }, 1529615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes4t4g2", }, 1530615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes10t4g2", }, 1531615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes16t4g2", }, 1532615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes16t4ag2", }, 1533615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes5t5", }, 1534615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes6t5", }, 1535615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes8t5", }, 1536615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes8t5a", }, 1537615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes24t6", }, 1538615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes6t6g2", }, 1539615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes24t6g2", }, 1540615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes16t7", }, 1541615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes32t8", }, 1542615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes32t8g2", }, 1543615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes48t12", }, 1544615cdd7cSJavier Martinez Canillas { .compatible = "idt,89hpes48t12g2", }, 1545615cdd7cSJavier Martinez Canillas { }, 1546615cdd7cSJavier Martinez Canillas }; 1547615cdd7cSJavier Martinez Canillas MODULE_DEVICE_TABLE(of, idt_of_match); 1548615cdd7cSJavier Martinez Canillas 1549cfad6425SSerge Semin /* 1550cfad6425SSerge Semin * idt_driver - IDT 89HPESx driver structure 1551cfad6425SSerge Semin */ 1552cfad6425SSerge Semin static struct i2c_driver idt_driver = { 1553cfad6425SSerge Semin .driver = { 1554cfad6425SSerge Semin .name = IDT_NAME, 1555615cdd7cSJavier Martinez Canillas .of_match_table = idt_of_match, 1556cfad6425SSerge Semin }, 1557cfad6425SSerge Semin .probe = idt_probe, 1558cfad6425SSerge Semin .remove = idt_remove, 1559cfad6425SSerge Semin .id_table = idt_ids, 1560cfad6425SSerge Semin }; 1561cfad6425SSerge Semin 1562cfad6425SSerge Semin /* 1563cfad6425SSerge Semin * idt_init() - IDT 89HPESx driver init() callback method 1564cfad6425SSerge Semin */ 1565cfad6425SSerge Semin static int __init idt_init(void) 1566cfad6425SSerge Semin { 1567cfad6425SSerge Semin /* Create Debugfs directory first */ 1568cfad6425SSerge Semin if (debugfs_initialized()) 1569cfad6425SSerge Semin csr_dbgdir = debugfs_create_dir("idt_csr", NULL); 1570cfad6425SSerge Semin 1571cfad6425SSerge Semin /* Add new i2c-device driver */ 1572cfad6425SSerge Semin return i2c_add_driver(&idt_driver); 1573cfad6425SSerge Semin } 1574cfad6425SSerge Semin module_init(idt_init); 1575cfad6425SSerge Semin 1576cfad6425SSerge Semin /* 1577cfad6425SSerge Semin * idt_exit() - IDT 89HPESx driver exit() callback method 1578cfad6425SSerge Semin */ 1579cfad6425SSerge Semin static void __exit idt_exit(void) 1580cfad6425SSerge Semin { 1581cfad6425SSerge Semin /* Discard debugfs directory and all files if any */ 1582cfad6425SSerge Semin debugfs_remove_recursive(csr_dbgdir); 1583cfad6425SSerge Semin 1584cfad6425SSerge Semin /* Unregister i2c-device driver */ 1585cfad6425SSerge Semin i2c_del_driver(&idt_driver); 1586cfad6425SSerge Semin } 1587cfad6425SSerge Semin module_exit(idt_exit); 1588