mirror of
				https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
				synced 2025-10-31 11:03:14 +00:00 
			
		
		
		
	 65131cd52b
			
		
	
	
		65131cd52b
		
	
	
	
	
		
			
			Signed-off-by: Rodolfo Giometti <giometti@linux.it> Cc: Greg KH <greg@kroah.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
		
			
				
	
	
		
			159 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			159 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  *  Silicon Labs C2 port Linux support for Eurotech Duramar 2150
 | |
|  *
 | |
|  *  Copyright (c) 2008 Rodolfo Giometti <giometti@linux.it>
 | |
|  *  Copyright (c) 2008 Eurotech S.p.A. <info@eurotech.it>
 | |
|  *
 | |
|  * This program is free software; you can redistribute it and/or modify it
 | |
|  * under the terms of the GNU General Public License version 2 as published by
 | |
|  * the Free Software Foundation
 | |
|  */
 | |
| 
 | |
| #include <linux/errno.h>
 | |
| #include <linux/init.h>
 | |
| #include <linux/kernel.h>
 | |
| #include <linux/module.h>
 | |
| #include <linux/delay.h>
 | |
| #include <linux/io.h>
 | |
| #include <linux/c2port.h>
 | |
| 
 | |
| #define DATA_PORT	0x325
 | |
| #define DIR_PORT	0x326
 | |
| #define    C2D		   (1 << 0)
 | |
| #define    C2CK		   (1 << 1)
 | |
| 
 | |
| static DEFINE_MUTEX(update_lock);
 | |
| 
 | |
| /*
 | |
|  * C2 port operations
 | |
|  */
 | |
| 
 | |
| static void duramar2150_c2port_access(struct c2port_device *dev, int status)
 | |
| {
 | |
| 	u8 v;
 | |
| 
 | |
| 	mutex_lock(&update_lock);
 | |
| 
 | |
| 	v = inb(DIR_PORT);
 | |
| 
 | |
| 	/* 0 = input, 1 = output */
 | |
| 	if (status)
 | |
| 		outb(v | (C2D | C2CK), DIR_PORT);
 | |
| 	else
 | |
| 		/* When access is "off" is important that both lines are set
 | |
| 		 * as inputs or hi-impedence */
 | |
| 		outb(v & ~(C2D | C2CK), DIR_PORT);
 | |
| 
 | |
| 	mutex_unlock(&update_lock);
 | |
| }
 | |
| 
 | |
| static void duramar2150_c2port_c2d_dir(struct c2port_device *dev, int dir)
 | |
| {
 | |
| 	u8 v;
 | |
| 
 | |
| 	mutex_lock(&update_lock);
 | |
| 
 | |
| 	v = inb(DIR_PORT);
 | |
| 
 | |
| 	if (dir)
 | |
| 		outb(v & ~C2D, DIR_PORT);
 | |
| 	else
 | |
| 		outb(v | C2D, DIR_PORT);
 | |
| 
 | |
| 	mutex_unlock(&update_lock);
 | |
| }
 | |
| 
 | |
| static int duramar2150_c2port_c2d_get(struct c2port_device *dev)
 | |
| {
 | |
| 	return inb(DATA_PORT) & C2D;
 | |
| }
 | |
| 
 | |
| static void duramar2150_c2port_c2d_set(struct c2port_device *dev, int status)
 | |
| {
 | |
| 	u8 v;
 | |
| 
 | |
| 	mutex_lock(&update_lock);
 | |
| 
 | |
| 	v = inb(DATA_PORT);
 | |
| 
 | |
| 	if (status)
 | |
| 		outb(v | C2D, DATA_PORT);
 | |
| 	else
 | |
| 		outb(v & ~C2D, DATA_PORT);
 | |
| 
 | |
| 	mutex_unlock(&update_lock);
 | |
| }
 | |
| 
 | |
| static void duramar2150_c2port_c2ck_set(struct c2port_device *dev, int status)
 | |
| {
 | |
| 	u8 v;
 | |
| 
 | |
| 	mutex_lock(&update_lock);
 | |
| 
 | |
| 	v = inb(DATA_PORT);
 | |
| 
 | |
| 	if (status)
 | |
| 		outb(v | C2CK, DATA_PORT);
 | |
| 	else
 | |
| 		outb(v & ~C2CK, DATA_PORT);
 | |
| 
 | |
| 	mutex_unlock(&update_lock);
 | |
| }
 | |
| 
 | |
| static struct c2port_ops duramar2150_c2port_ops = {
 | |
| 	.block_size	= 512,	/* bytes */
 | |
| 	.blocks_num	= 30,	/* total flash size: 15360 bytes */
 | |
| 
 | |
| 	.access		= duramar2150_c2port_access,
 | |
| 	.c2d_dir	= duramar2150_c2port_c2d_dir,
 | |
| 	.c2d_get	= duramar2150_c2port_c2d_get,
 | |
| 	.c2d_set	= duramar2150_c2port_c2d_set,
 | |
| 	.c2ck_set	= duramar2150_c2port_c2ck_set,
 | |
| };
 | |
| 
 | |
| static struct c2port_device *duramar2150_c2port_dev;
 | |
| 
 | |
| /*
 | |
|  * Module stuff
 | |
|  */
 | |
| 
 | |
| static int __init duramar2150_c2port_init(void)
 | |
| {
 | |
| 	struct resource *res;
 | |
| 	int ret = 0;
 | |
| 
 | |
| 	res = request_region(0x325, 2, "c2port");
 | |
| 	if (!res)
 | |
| 		return -EBUSY;
 | |
| 
 | |
| 	duramar2150_c2port_dev = c2port_device_register("uc",
 | |
| 					&duramar2150_c2port_ops, NULL);
 | |
| 	if (!duramar2150_c2port_dev) {
 | |
| 		ret = -ENODEV;
 | |
| 		goto free_region;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| 
 | |
| free_region:
 | |
| 	release_region(0x325, 2);
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| static void __exit duramar2150_c2port_exit(void)
 | |
| {
 | |
| 	/* Setup the GPIOs as input by default (access = 0) */
 | |
| 	duramar2150_c2port_access(duramar2150_c2port_dev, 0);
 | |
| 
 | |
| 	c2port_device_unregister(duramar2150_c2port_dev);
 | |
| 
 | |
| 	release_region(0x325, 2);
 | |
| }
 | |
| 
 | |
| module_init(duramar2150_c2port_init);
 | |
| module_exit(duramar2150_c2port_exit);
 | |
| 
 | |
| MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
 | |
| MODULE_DESCRIPTION("Silicon Labs C2 port Linux support for Duramar 2150");
 | |
| MODULE_LICENSE("GPL");
 |