1 /* 2 * Silicon Labs C2 port Linux support for Eurotech Duramar 2150 3 * 4 * Copyright (c) 2008 Rodolfo Giometti <giometti@linux.it> 5 * Copyright (c) 2008 Eurotech S.p.A. <info@eurotech.it> 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 as published by 9 * the Free Software Foundation 10 */ 11 12 #include <linux/errno.h> 13 #include <linux/init.h> 14 #include <linux/kernel.h> 15 #include <linux/module.h> 16 #include <linux/delay.h> 17 #include <linux/io.h> 18 #include <linux/c2port.h> 19 20 #define DATA_PORT 0x325 21 #define DIR_PORT 0x326 22 #define C2D (1 << 0) 23 #define C2CK (1 << 1) 24 25 static DEFINE_MUTEX(update_lock); 26 27 /* 28 * C2 port operations 29 */ 30 31 static void duramar2150_c2port_access(struct c2port_device *dev, int status) 32 { 33 u8 v; 34 35 mutex_lock(&update_lock); 36 37 v = inb(DIR_PORT); 38 39 /* 0 = input, 1 = output */ 40 if (status) 41 outb(v | (C2D | C2CK), DIR_PORT); 42 else 43 /* When access is "off" is important that both lines are set 44 * as inputs or hi-impedence */ 45 outb(v & ~(C2D | C2CK), DIR_PORT); 46 47 mutex_unlock(&update_lock); 48 } 49 50 static void duramar2150_c2port_c2d_dir(struct c2port_device *dev, int dir) 51 { 52 u8 v; 53 54 mutex_lock(&update_lock); 55 56 v = inb(DIR_PORT); 57 58 if (dir) 59 outb(v & ~C2D, DIR_PORT); 60 else 61 outb(v | C2D, DIR_PORT); 62 63 mutex_unlock(&update_lock); 64 } 65 66 static int duramar2150_c2port_c2d_get(struct c2port_device *dev) 67 { 68 return inb(DATA_PORT) & C2D; 69 } 70 71 static void duramar2150_c2port_c2d_set(struct c2port_device *dev, int status) 72 { 73 u8 v; 74 75 mutex_lock(&update_lock); 76 77 v = inb(DATA_PORT); 78 79 if (status) 80 outb(v | C2D, DATA_PORT); 81 else 82 outb(v & ~C2D, DATA_PORT); 83 84 mutex_unlock(&update_lock); 85 } 86 87 static void duramar2150_c2port_c2ck_set(struct c2port_device *dev, int status) 88 { 89 u8 v; 90 91 mutex_lock(&update_lock); 92 93 v = inb(DATA_PORT); 94 95 if (status) 96 outb(v | C2CK, DATA_PORT); 97 else 98 outb(v & ~C2CK, DATA_PORT); 99 100 mutex_unlock(&update_lock); 101 } 102 103 static struct c2port_ops duramar2150_c2port_ops = { 104 .block_size = 512, /* bytes */ 105 .blocks_num = 30, /* total flash size: 15360 bytes */ 106 107 .access = duramar2150_c2port_access, 108 .c2d_dir = duramar2150_c2port_c2d_dir, 109 .c2d_get = duramar2150_c2port_c2d_get, 110 .c2d_set = duramar2150_c2port_c2d_set, 111 .c2ck_set = duramar2150_c2port_c2ck_set, 112 }; 113 114 static struct c2port_device *duramar2150_c2port_dev; 115 116 /* 117 * Module stuff 118 */ 119 120 static int __init duramar2150_c2port_init(void) 121 { 122 struct resource *res; 123 int ret = 0; 124 125 res = request_region(0x325, 2, "c2port"); 126 if (!res) 127 return -EBUSY; 128 129 duramar2150_c2port_dev = c2port_device_register("uc", 130 &duramar2150_c2port_ops, NULL); 131 if (!duramar2150_c2port_dev) { 132 ret = -ENODEV; 133 goto free_region; 134 } 135 136 return 0; 137 138 free_region: 139 release_region(0x325, 2); 140 return ret; 141 } 142 143 static void __exit duramar2150_c2port_exit(void) 144 { 145 /* Setup the GPIOs as input by default (access = 0) */ 146 duramar2150_c2port_access(duramar2150_c2port_dev, 0); 147 148 c2port_device_unregister(duramar2150_c2port_dev); 149 150 release_region(0x325, 2); 151 } 152 153 module_init(duramar2150_c2port_init); 154 module_exit(duramar2150_c2port_exit); 155 156 MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>"); 157 MODULE_DESCRIPTION("Silicon Labs C2 port Linux support for Duramar 2150"); 158 MODULE_LICENSE("GPL"); 159