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 26static DEFINE_MUTEX(update_lock); 27 28/* 29 * C2 port operations 30 */ 31 32static 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 51static 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 67static int duramar2150_c2port_c2d_get(struct c2port_device *dev) 68{ 69 return inb(DATA_PORT) & C2D; 70} 71 72static 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 88static 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 104static 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 115static struct c2port_device *duramar2150_c2port_dev; 116 117/* 118 * Module stuff 119 */ 120 121static 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 (!duramar2150_c2port_dev) { 133 ret = -ENODEV; 134 goto free_region; 135 } 136 137 return 0; 138 139free_region: 140 release_region(0x325, 2); 141 return ret; 142} 143 144static 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 154module_init(duramar2150_c2port_init); 155module_exit(duramar2150_c2port_exit); 156 157MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>"); 158MODULE_DESCRIPTION("Silicon Labs C2 port Linux support for Duramar 2150"); 159MODULE_LICENSE("GPL"); 160