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