diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-nforce2.c')
-rw-r--r-- | drivers/i2c/busses/i2c-nforce2.c | 44 |
1 files changed, 43 insertions, 1 deletions
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 3cd0d63e7b50..c48140f782d0 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c | |||
@@ -61,6 +61,7 @@ struct nforce2_smbus { | |||
61 | struct i2c_adapter adapter; | 61 | struct i2c_adapter adapter; |
62 | int base; | 62 | int base; |
63 | int size; | 63 | int size; |
64 | int blockops; | ||
64 | }; | 65 | }; |
65 | 66 | ||
66 | 67 | ||
@@ -80,6 +81,8 @@ struct nforce2_smbus { | |||
80 | #define NVIDIA_SMB_ADDR (smbus->base + 0x02) /* address */ | 81 | #define NVIDIA_SMB_ADDR (smbus->base + 0x02) /* address */ |
81 | #define NVIDIA_SMB_CMD (smbus->base + 0x03) /* command */ | 82 | #define NVIDIA_SMB_CMD (smbus->base + 0x03) /* command */ |
82 | #define NVIDIA_SMB_DATA (smbus->base + 0x04) /* 32 data registers */ | 83 | #define NVIDIA_SMB_DATA (smbus->base + 0x04) /* 32 data registers */ |
84 | #define NVIDIA_SMB_BCNT (smbus->base + 0x24) /* number of data | ||
85 | bytes */ | ||
83 | 86 | ||
84 | #define NVIDIA_SMB_STS_DONE 0x80 | 87 | #define NVIDIA_SMB_STS_DONE 0x80 |
85 | #define NVIDIA_SMB_STS_ALRM 0x40 | 88 | #define NVIDIA_SMB_STS_ALRM 0x40 |
@@ -92,6 +95,7 @@ struct nforce2_smbus { | |||
92 | #define NVIDIA_SMB_PRTCL_BYTE 0x04 | 95 | #define NVIDIA_SMB_PRTCL_BYTE 0x04 |
93 | #define NVIDIA_SMB_PRTCL_BYTE_DATA 0x06 | 96 | #define NVIDIA_SMB_PRTCL_BYTE_DATA 0x06 |
94 | #define NVIDIA_SMB_PRTCL_WORD_DATA 0x08 | 97 | #define NVIDIA_SMB_PRTCL_WORD_DATA 0x08 |
98 | #define NVIDIA_SMB_PRTCL_BLOCK_DATA 0x0a | ||
95 | #define NVIDIA_SMB_PRTCL_PEC 0x80 | 99 | #define NVIDIA_SMB_PRTCL_PEC 0x80 |
96 | 100 | ||
97 | static struct pci_driver nforce2_driver; | 101 | static struct pci_driver nforce2_driver; |
@@ -103,6 +107,8 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, | |||
103 | { | 107 | { |
104 | struct nforce2_smbus *smbus = adap->algo_data; | 108 | struct nforce2_smbus *smbus = adap->algo_data; |
105 | unsigned char protocol, pec, temp; | 109 | unsigned char protocol, pec, temp; |
110 | u8 len; | ||
111 | int i; | ||
106 | 112 | ||
107 | protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ : | 113 | protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ : |
108 | NVIDIA_SMB_PRTCL_WRITE; | 114 | NVIDIA_SMB_PRTCL_WRITE; |
@@ -137,6 +143,25 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, | |||
137 | protocol |= NVIDIA_SMB_PRTCL_WORD_DATA | pec; | 143 | protocol |= NVIDIA_SMB_PRTCL_WORD_DATA | pec; |
138 | break; | 144 | break; |
139 | 145 | ||
146 | case I2C_SMBUS_BLOCK_DATA: | ||
147 | outb_p(command, NVIDIA_SMB_CMD); | ||
148 | if (read_write == I2C_SMBUS_WRITE) { | ||
149 | len = data->block[0]; | ||
150 | if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX)) { | ||
151 | dev_err(&adap->dev, | ||
152 | "Transaction failed " | ||
153 | "(requested block size: %d)\n", | ||
154 | len); | ||
155 | return -1; | ||
156 | } | ||
157 | outb_p(len, NVIDIA_SMB_BCNT); | ||
158 | for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++) | ||
159 | outb_p(data->block[i + 1], | ||
160 | NVIDIA_SMB_DATA+i); | ||
161 | } | ||
162 | protocol |= NVIDIA_SMB_PRTCL_BLOCK_DATA | pec; | ||
163 | break; | ||
164 | |||
140 | default: | 165 | default: |
141 | dev_err(&adap->dev, "Unsupported transaction %d\n", size); | 166 | dev_err(&adap->dev, "Unsupported transaction %d\n", size); |
142 | return -1; | 167 | return -1; |
@@ -174,6 +199,14 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, | |||
174 | case I2C_SMBUS_WORD_DATA: | 199 | case I2C_SMBUS_WORD_DATA: |
175 | data->word = inb_p(NVIDIA_SMB_DATA) | (inb_p(NVIDIA_SMB_DATA+1) << 8); | 200 | data->word = inb_p(NVIDIA_SMB_DATA) | (inb_p(NVIDIA_SMB_DATA+1) << 8); |
176 | break; | 201 | break; |
202 | |||
203 | case I2C_SMBUS_BLOCK_DATA: | ||
204 | len = inb_p(NVIDIA_SMB_BCNT); | ||
205 | len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX); | ||
206 | for (i = 0; i < len; i++) | ||
207 | data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i); | ||
208 | data->block[0] = len; | ||
209 | break; | ||
177 | } | 210 | } |
178 | 211 | ||
179 | return 0; | 212 | return 0; |
@@ -184,7 +217,9 @@ static u32 nforce2_func(struct i2c_adapter *adapter) | |||
184 | { | 217 | { |
185 | /* other functionality might be possible, but is not tested */ | 218 | /* other functionality might be possible, but is not tested */ |
186 | return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | | 219 | return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | |
187 | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA; | 220 | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | |
221 | (((struct nforce2_smbus*)adapter->algo_data)->blockops ? | ||
222 | I2C_FUNC_SMBUS_BLOCK_DATA : 0); | ||
188 | } | 223 | } |
189 | 224 | ||
190 | static struct i2c_algorithm smbus_algorithm = { | 225 | static struct i2c_algorithm smbus_algorithm = { |
@@ -268,6 +303,13 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_ | |||
268 | return -ENOMEM; | 303 | return -ENOMEM; |
269 | pci_set_drvdata(dev, smbuses); | 304 | pci_set_drvdata(dev, smbuses); |
270 | 305 | ||
306 | switch(dev->device) { | ||
307 | case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS: | ||
308 | case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS: | ||
309 | smbuses[0].blockops = 1; | ||
310 | smbuses[1].blockops = 1; | ||
311 | } | ||
312 | |||
271 | /* SMBus adapter 1 */ | 313 | /* SMBus adapter 1 */ |
272 | res1 = nforce2_probe_smb(dev, 4, NFORCE_PCI_SMB1, &smbuses[0], "SMB1"); | 314 | res1 = nforce2_probe_smb(dev, 4, NFORCE_PCI_SMB1, &smbuses[0], "SMB1"); |
273 | if (res1 < 0) { | 315 | if (res1 < 0) { |