165131cd5SRodolfo Giometti /* 265131cd5SRodolfo Giometti * Silicon Labs C2 port Linux support for Eurotech Duramar 2150 365131cd5SRodolfo Giometti * 465131cd5SRodolfo Giometti * Copyright (c) 2008 Rodolfo Giometti <giometti@linux.it> 565131cd5SRodolfo Giometti * Copyright (c) 2008 Eurotech S.p.A. <info@eurotech.it> 665131cd5SRodolfo Giometti * 765131cd5SRodolfo Giometti * This program is free software; you can redistribute it and/or modify it 865131cd5SRodolfo Giometti * under the terms of the GNU General Public License version 2 as published by 965131cd5SRodolfo Giometti * the Free Software Foundation 1065131cd5SRodolfo Giometti */ 1165131cd5SRodolfo Giometti 1265131cd5SRodolfo Giometti #include <linux/errno.h> 1365131cd5SRodolfo Giometti #include <linux/init.h> 1465131cd5SRodolfo Giometti #include <linux/kernel.h> 1565131cd5SRodolfo Giometti #include <linux/module.h> 1665131cd5SRodolfo Giometti #include <linux/delay.h> 1765131cd5SRodolfo Giometti #include <linux/io.h> 18ecd9d34aSPaul Gortmaker #include <linux/ioport.h> 1965131cd5SRodolfo Giometti #include <linux/c2port.h> 2065131cd5SRodolfo Giometti 2165131cd5SRodolfo Giometti #define DATA_PORT 0x325 2265131cd5SRodolfo Giometti #define DIR_PORT 0x326 2365131cd5SRodolfo Giometti #define C2D (1 << 0) 2465131cd5SRodolfo Giometti #define C2CK (1 << 1) 2565131cd5SRodolfo Giometti 2665131cd5SRodolfo Giometti static DEFINE_MUTEX(update_lock); 2765131cd5SRodolfo Giometti 2865131cd5SRodolfo Giometti /* 2965131cd5SRodolfo Giometti * C2 port operations 3065131cd5SRodolfo Giometti */ 3165131cd5SRodolfo Giometti 3265131cd5SRodolfo Giometti static void duramar2150_c2port_access(struct c2port_device *dev, int status) 3365131cd5SRodolfo Giometti { 3465131cd5SRodolfo Giometti u8 v; 3565131cd5SRodolfo Giometti 3665131cd5SRodolfo Giometti mutex_lock(&update_lock); 3765131cd5SRodolfo Giometti 3865131cd5SRodolfo Giometti v = inb(DIR_PORT); 3965131cd5SRodolfo Giometti 4065131cd5SRodolfo Giometti /* 0 = input, 1 = output */ 4165131cd5SRodolfo Giometti if (status) 4265131cd5SRodolfo Giometti outb(v | (C2D | C2CK), DIR_PORT); 4365131cd5SRodolfo Giometti else 4465131cd5SRodolfo Giometti /* When access is "off" is important that both lines are set 4525985edcSLucas De Marchi * as inputs or hi-impedance */ 4665131cd5SRodolfo Giometti outb(v & ~(C2D | C2CK), DIR_PORT); 4765131cd5SRodolfo Giometti 4865131cd5SRodolfo Giometti mutex_unlock(&update_lock); 4965131cd5SRodolfo Giometti } 5065131cd5SRodolfo Giometti 5165131cd5SRodolfo Giometti static void duramar2150_c2port_c2d_dir(struct c2port_device *dev, int dir) 5265131cd5SRodolfo Giometti { 5365131cd5SRodolfo Giometti u8 v; 5465131cd5SRodolfo Giometti 5565131cd5SRodolfo Giometti mutex_lock(&update_lock); 5665131cd5SRodolfo Giometti 5765131cd5SRodolfo Giometti v = inb(DIR_PORT); 5865131cd5SRodolfo Giometti 5965131cd5SRodolfo Giometti if (dir) 6065131cd5SRodolfo Giometti outb(v & ~C2D, DIR_PORT); 6165131cd5SRodolfo Giometti else 6265131cd5SRodolfo Giometti outb(v | C2D, DIR_PORT); 6365131cd5SRodolfo Giometti 6465131cd5SRodolfo Giometti mutex_unlock(&update_lock); 6565131cd5SRodolfo Giometti } 6665131cd5SRodolfo Giometti 6765131cd5SRodolfo Giometti static int duramar2150_c2port_c2d_get(struct c2port_device *dev) 6865131cd5SRodolfo Giometti { 6965131cd5SRodolfo Giometti return inb(DATA_PORT) & C2D; 7065131cd5SRodolfo Giometti } 7165131cd5SRodolfo Giometti 7265131cd5SRodolfo Giometti static void duramar2150_c2port_c2d_set(struct c2port_device *dev, int status) 7365131cd5SRodolfo Giometti { 7465131cd5SRodolfo Giometti u8 v; 7565131cd5SRodolfo Giometti 7665131cd5SRodolfo Giometti mutex_lock(&update_lock); 7765131cd5SRodolfo Giometti 7865131cd5SRodolfo Giometti v = inb(DATA_PORT); 7965131cd5SRodolfo Giometti 8065131cd5SRodolfo Giometti if (status) 8165131cd5SRodolfo Giometti outb(v | C2D, DATA_PORT); 8265131cd5SRodolfo Giometti else 8365131cd5SRodolfo Giometti outb(v & ~C2D, DATA_PORT); 8465131cd5SRodolfo Giometti 8565131cd5SRodolfo Giometti mutex_unlock(&update_lock); 8665131cd5SRodolfo Giometti } 8765131cd5SRodolfo Giometti 8865131cd5SRodolfo Giometti static void duramar2150_c2port_c2ck_set(struct c2port_device *dev, int status) 8965131cd5SRodolfo Giometti { 9065131cd5SRodolfo Giometti u8 v; 9165131cd5SRodolfo Giometti 9265131cd5SRodolfo Giometti mutex_lock(&update_lock); 9365131cd5SRodolfo Giometti 9465131cd5SRodolfo Giometti v = inb(DATA_PORT); 9565131cd5SRodolfo Giometti 9665131cd5SRodolfo Giometti if (status) 9765131cd5SRodolfo Giometti outb(v | C2CK, DATA_PORT); 9865131cd5SRodolfo Giometti else 9965131cd5SRodolfo Giometti outb(v & ~C2CK, DATA_PORT); 10065131cd5SRodolfo Giometti 10165131cd5SRodolfo Giometti mutex_unlock(&update_lock); 10265131cd5SRodolfo Giometti } 10365131cd5SRodolfo Giometti 10465131cd5SRodolfo Giometti static struct c2port_ops duramar2150_c2port_ops = { 10565131cd5SRodolfo Giometti .block_size = 512, /* bytes */ 10665131cd5SRodolfo Giometti .blocks_num = 30, /* total flash size: 15360 bytes */ 10765131cd5SRodolfo Giometti 10865131cd5SRodolfo Giometti .access = duramar2150_c2port_access, 10965131cd5SRodolfo Giometti .c2d_dir = duramar2150_c2port_c2d_dir, 11065131cd5SRodolfo Giometti .c2d_get = duramar2150_c2port_c2d_get, 11165131cd5SRodolfo Giometti .c2d_set = duramar2150_c2port_c2d_set, 11265131cd5SRodolfo Giometti .c2ck_set = duramar2150_c2port_c2ck_set, 11365131cd5SRodolfo Giometti }; 11465131cd5SRodolfo Giometti 11565131cd5SRodolfo Giometti static struct c2port_device *duramar2150_c2port_dev; 11665131cd5SRodolfo Giometti 11765131cd5SRodolfo Giometti /* 11865131cd5SRodolfo Giometti * Module stuff 11965131cd5SRodolfo Giometti */ 12065131cd5SRodolfo Giometti 12165131cd5SRodolfo Giometti static int __init duramar2150_c2port_init(void) 12265131cd5SRodolfo Giometti { 12365131cd5SRodolfo Giometti struct resource *res; 12465131cd5SRodolfo Giometti int ret = 0; 12565131cd5SRodolfo Giometti 12665131cd5SRodolfo Giometti res = request_region(0x325, 2, "c2port"); 12765131cd5SRodolfo Giometti if (!res) 12865131cd5SRodolfo Giometti return -EBUSY; 12965131cd5SRodolfo Giometti 13065131cd5SRodolfo Giometti duramar2150_c2port_dev = c2port_device_register("uc", 13165131cd5SRodolfo Giometti &duramar2150_c2port_ops, NULL); 1328128a31eSDan Carpenter if (IS_ERR(duramar2150_c2port_dev)) { 1338128a31eSDan Carpenter ret = PTR_ERR(duramar2150_c2port_dev); 13465131cd5SRodolfo Giometti goto free_region; 13565131cd5SRodolfo Giometti } 13665131cd5SRodolfo Giometti 13765131cd5SRodolfo Giometti return 0; 13865131cd5SRodolfo Giometti 13965131cd5SRodolfo Giometti free_region: 14065131cd5SRodolfo Giometti release_region(0x325, 2); 14165131cd5SRodolfo Giometti return ret; 14265131cd5SRodolfo Giometti } 14365131cd5SRodolfo Giometti 14465131cd5SRodolfo Giometti static void __exit duramar2150_c2port_exit(void) 14565131cd5SRodolfo Giometti { 14665131cd5SRodolfo Giometti /* Setup the GPIOs as input by default (access = 0) */ 14765131cd5SRodolfo Giometti duramar2150_c2port_access(duramar2150_c2port_dev, 0); 14865131cd5SRodolfo Giometti 14965131cd5SRodolfo Giometti c2port_device_unregister(duramar2150_c2port_dev); 15065131cd5SRodolfo Giometti 15165131cd5SRodolfo Giometti release_region(0x325, 2); 15265131cd5SRodolfo Giometti } 15365131cd5SRodolfo Giometti 15465131cd5SRodolfo Giometti module_init(duramar2150_c2port_init); 15565131cd5SRodolfo Giometti module_exit(duramar2150_c2port_exit); 15665131cd5SRodolfo Giometti 15765131cd5SRodolfo Giometti MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>"); 15865131cd5SRodolfo Giometti MODULE_DESCRIPTION("Silicon Labs C2 port Linux support for Duramar 2150"); 15965131cd5SRodolfo Giometti MODULE_LICENSE("GPL"); 160