Lynx framebuffers multidomain implementation.
[linux/elbrus.git] / drivers / mcst / i2c_spd / i2c_spd.c
blobc9bf5b8698a01197ea7572ced88841c71ffb3bb3
1 #include <linux/module.h>
2 #include <linux/errno.h>
3 #include <linux/signal.h>
4 #include <linux/sched.h>
5 #include <linux/timer.h>
6 #include <linux/interrupt.h>
7 #include <linux/string.h>
8 #include <linux/fcntl.h>
9 #include <linux/ptrace.h>
10 //#include <linux/cyclades.h>
11 #include <linux/mm.h>
12 #include <linux/ioport.h>
13 #include <linux/init.h>
14 #include <linux/delay.h>
15 #include <linux/spinlock.h>
16 #include <linux/bitops.h>
17 #include <linux/proc_fs.h>
19 #include <asm/system.h>
20 #include <asm/io.h>
21 #include <asm/irq.h>
22 #include <asm/uaccess.h>
24 #include <linux/types.h>
25 #include <linux/kernel.h>
26 #include <linux/pci.h>
28 #define DEV_NAME "i2c_spd"
30 #define I2C_CTRL 0x14
31 #define I2C_STATUS 0x18
32 #define I2C_MODE 0x1c
34 struct i2c_dev {
35 int bus;
36 int _addr;
39 struct i2c_spd_info_t {
41 struct pci_dev *pcidev;
42 void __iomem *dev;
43 struct i2c_dev adrdev[256];
44 void __iomem *base_io;
45 struct proc_dir_entry *proc_dev;
46 int count;
47 spinlock_t spd_lock;
50 static int count = 0;
52 static int i2c_spd_probe(struct pci_dev *pcidev,
53 const struct pci_device_id *pciid);
54 static void i2c_spd_remove(struct pci_dev *pci_dev);
55 inline int i2c_read_reg(struct pci_dev *dev, char *base, unsigned char reg,
56 int bus, int adr);
57 inline int i2c_write_reg(struct pci_dev *dev, char *base, unsigned char reg,
58 int bus, int adr);
60 #define SPD_SZ 128
61 static int proc_read_i2c_spd(char *page, char **start,
62 off_t off, int count, int *eof, void *data)
64 int len = 0;
65 struct i2c_spd_info_t *device = (struct i2c_spd_info_t *)data;
66 struct pci_dev *dev = device->pcidev;
67 int i, j;
68 unsigned char dt;
69 int bus, adr;
71 spin_lock(&device->spd_lock);
72 for (i = 0; i < device->count; i++) {
73 bus = device->adrdev[i].bus;
74 adr = device->adrdev[i]._addr;
75 len += sprintf(&page[len], "Module %d", i);
77 for (j = 0; j < SPD_SZ; j++) {
78 if(!(j % 16))
79 len += sprintf(&page[len], "\n\t");
80 if (i2c_read_reg(dev, &dt, j, bus, adr) <= 0) { // read status reg
81 len = sprintf(page, "Error read spd unit\n");
82 goto l_1;
84 len += sprintf(&page[len], "%02x ", dt);
86 len += sprintf(&page[len], "\n\n");
88 l_1:
89 spin_unlock(&device->spd_lock);
90 return len;
93 int i2c_base_write(struct pci_dev *dev, char *base, int sz, int bus, int adr,
94 int reg)
96 struct i2c_spd_info_t *device = pci_get_drvdata(dev);
97 // sz < 63
98 volatile u32 i2c_ctrl =
99 0x1 | (sz << 1) | (adr << 15) | (bus << 24) | (0 << 26) | (1 << 28)
100 | (reg << 7) | (0 << 22) | (1 << 23);
101 // write | size | 7bit addr | 0 -phase data | bus number | start byte on | start
102 volatile u32 i2c_mode = 0;
103 int k = 0;
104 int i;
105 int ret;
107 for (i = 1000000; i; i--) {
108 if (readl(device->dev + I2C_STATUS) & 0x1) {
109 udelay(1);
110 continue;
112 break;
115 if (!i)
116 return 0;
118 for (k = 0; k < sz; k++) {
119 writeb(*(base + k), device->base_io + k);
122 writel(i2c_mode, device->dev + I2C_MODE);
123 writel(0x1e, device->dev + I2C_STATUS);
124 writel(i2c_ctrl, device->dev + I2C_CTRL);
126 // data transfer
128 for (i = 1000000; i; i--) {
129 ret = readl(device->dev + I2C_STATUS);
130 if (ret & 0x1) {
131 udelay(1);
132 continue;
134 if (ret & 0x2 && (!(ret & 0x1c))) {
135 return sz;
137 if (ret & 0x1c) {
138 break;
142 if (!i) {
143 writel((1 << 27), device->dev + I2C_CTRL); //kill task
144 writel(0x1e, device->dev + I2C_STATUS); //clean error bits
147 return -1;
150 int i2c_base_read(struct pci_dev *dev, char *base, int sz, int bus, int adr,
151 int reg)
154 struct i2c_spd_info_t *device = pci_get_drvdata(dev);
155 // sz < 63 //0x1 | (sz << 1) | (adr << 15) | (bus << 24) | (0 << 26) | (1 << 28) | (reg << 7) | (0 << 22) | (1 << 23);
156 volatile u32 i2c_ctrl =
157 0x0 | (sz << 1) | (adr << 15) | (bus << 24) | (0 << 26) | (1 << 28)
158 | (reg << 7) | (1 << 23) | (0 << 22);
159 volatile u32 i2c_mode = 0;
161 int i;
162 int ret;
164 // start transfer data
166 for (i = 1000000; i; i--) {
167 if (readl(device->dev + I2C_STATUS) & 0x1) {
168 udelay(1);
169 continue;
172 break;
174 if (!i)
175 return -1;
177 writel(i2c_mode, device->dev + I2C_MODE);
178 writel(0x1e, device->dev + I2C_STATUS);
180 writel(i2c_ctrl, device->dev + I2C_CTRL);
182 // check transfer
184 for (i = 1000000; i; i--) {
185 ret = readl(device->dev + I2C_STATUS);
186 if (ret & 0x1) {
187 udelay(1);
188 continue;
191 if (ret & 0x2 && (!(ret & 0x1c))) {
192 int j = 0;
194 for (j = 0; j < sz; j++) {
195 char b = readb(device->base_io + j);
196 *(base + j) = b;
198 return sz;
201 if (ret & 0x1c)
202 break;
205 if (!i) {
206 writel((i2c_ctrl = (1 << 27)), device->dev + I2C_CTRL);
207 writel(0x1e, device->dev + I2C_STATUS); //clean error bits
210 return -1;
214 inline int i2c_read_reg(struct pci_dev *dev, char *base, unsigned char reg,
215 int bus, int adr)
217 int ret = i2c_base_write(dev, &reg, 1, bus, adr, 00);
219 if (ret == -1)
220 return ret;
222 return i2c_base_read(dev, base, 1, bus, adr, 00);
225 inline int i2c_write_reg(struct pci_dev *dev, char *base, unsigned char reg,
226 int bus, int adr)
228 char ctm[2];
229 ctm[0] = reg;
230 ctm[1] = *base;
231 return i2c_base_write(dev, &ctm[0], 2, bus, adr, 00);
234 static int i2c_find_spd_dev(struct i2c_spd_info_t *device)
236 char adr = 0x50;
237 struct pci_dev *pcidev = device->pcidev;
238 int j, f, k = 0;
239 char ctm[64];
241 for (j = 0; j < 1; j++) {
242 for (f = 0; f < 8; f++) {
243 if (i2c_read_reg(pcidev, &ctm[0], 0, j, adr + f) > 0) {
244 printk("spd chip found at %d:%x\n",j, adr + f);
245 device->adrdev[k].bus = j;
246 device->adrdev[k]._addr = adr + f;
247 k++;
251 return k;
255 static int i2c_spd_probe(struct pci_dev *pcidev,
256 const struct pci_device_id *pciid)
258 struct i2c_spd_info_t *device;
259 static char fflag = 0;
261 device =
262 (struct i2c_spd_info_t *)kmalloc(sizeof(struct i2c_spd_info_t),
263 GFP_KERNEL);
264 if (device == NULL) {
265 printk(KERN_ALERT "I2C - Error while trying alloc memory.\n");
266 return -ENOMEM;
268 memset(device, 0, sizeof(struct i2c_spd_info_t));
270 memset(device->adrdev, -1, sizeof(struct i2c_dev) * 256);
272 device->pcidev = pcidev;
273 spin_lock_init(&device->spd_lock);
276 device->dev = pci_iomap(device->pcidev, 0, 0);
277 device->base_io = pci_iomap(device->pcidev, 1, 0);
279 pci_set_drvdata(pcidev, device);
281 //check i2c
282 device->count = i2c_find_spd_dev(device);
284 if (device->count == 0)
285 goto release_device;
287 printk("%d spd chips was found\n", device->count);
289 device->proc_dev = create_proc_entry("i2c_spd", 0444, NULL);
290 if (device->proc_dev == NULL) {
291 goto release_device;
293 strcpy((char *)device->proc_dev->name, "i2c_spd");
294 device->proc_dev->data = device;
295 device->proc_dev->read_proc = proc_read_i2c_spd;
296 device->proc_dev->write_proc = NULL;
297 fflag++;
298 count = fflag;
300 return 0;
302 release_device:
303 pci_set_drvdata(pcidev, NULL);
304 kfree(device);
305 return -1;
309 static int __init i2c_spd_init_module(void)
311 int ret = 0;
312 struct pci_dev *dev = NULL;
314 do {
315 dev = pci_get_device(0x8086, 0x0002, dev);
316 if (dev) {
317 if (i2c_spd_probe(dev, NULL) == 0)
318 ret++;
320 } while (dev != NULL);
322 if (ret == 0) {
323 printk ("i2c_spd: Unable to locate any i2c_spd"
324 " device with valid IDs\n");
325 return -ENODEV;
328 return 0;
331 static void i2c_spd_remove(struct pci_dev *pci_dev1)
333 struct i2c_spd_info_t *device; // = pci_get_drvdata(pci_dev);
334 struct pci_dev *pcidev = 0; // = device->pcidev;
336 do {
337 pcidev = pci_get_device(0x8086, 0x0002, pcidev);
338 if (pcidev) {
339 device = pci_get_drvdata(pcidev);
340 pci_set_drvdata(pcidev, NULL);
341 remove_proc_entry("i2c_spd", device->proc_dev);
342 pci_iounmap(pcidev, device->dev);
343 pci_iounmap(pcidev, device->base_io);
344 kfree(device);
346 } while (pcidev != NULL);
349 static void i2c_spd_exit_module(void)
351 i2c_spd_remove(NULL);
354 module_init(i2c_spd_init_module);
355 module_exit(i2c_spd_exit_module);
357 MODULE_DESCRIPTION("I2C Driver for dumping spd");
358 MODULE_LICENSE("GPL");