linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
From: Hans Schillstrom <hans.schillstrom@pwav.com>
To: srinivas.surabhi@wipro.com
Cc: linuxppc-embedded@ozlabs.org
Subject: RE: FW: LED driver
Date: Thu, 17 Mar 2005 13:53:30 +0100	[thread overview]
Message-ID: <1111064009.13233.279.camel@hawk.allgon.net> (raw)
In-Reply-To: <EF9B29C78F41FA488927FCBC7750AF0E011DA97B@hyd-mdp-msg.wipro.com>

[-- Attachment #1: Type: text/plain, Size: 3180 bytes --]

Hi,
Thats right, but the original is for 2.4.2x.
I'll attach the original status_led.c from Denx for you

/Hans

Wolfgang: Sorry about the missing copyright
 

On Thu, 2005-03-17 at 13:47, srinivas.surabhi@wipro.com wrote:
> Thanks a lot for your help. But in my sources I could not find
> immap_cpm2.h file. There is immap_8260.h file, I don't know it is
> similar to that of immap_cpum2.h.
> 
> Can you send the immap_cpum2.h file please?
> 
> I am working on kernel 2.4.20
> 
> -Thanks once again..
> SS
> 
> -----Original Message-----
> From: Hans Schillstrom [mailto:hans.schillstrom@pwav.com]
> Sent: Thursday, March 17, 2005 3:17 PM
> To: Srinivas Surabhi (WT01 - TELECOM SOLUTIONS)
> Cc: linuxppc-embedded@ozlabs.org
> Subject: Re: FW: LED driver
> 
> Hi,
> I have made a driver for our mpc8270 board
> It is based upon Denx led_driver and made for 2.6 kernel
> (See atached file)
> 
> To control the leds you have to perfom some ioctl's
> first create your devices
> mknod led0 c 151 0 ...
> 
> Example howto use it:
> 
> void led_off( int file )
> {
>   if (ioctl(file,STATUSLED_SET,0) < 0)
>     perror("led off: ");
> }
> void led_blink( int file )
> {
>   if (ioctl(file,STATUSLED_SET,1) < 0)
>     perror("led blink: ");
> }
> void led_on( int file )
> {
>   if (ioctl(file,STATUSLED_SET,2) < 0)
>     perror("led on: ");
> }
> void led_per( int file, int period )
> {
>   if (ioctl(file,STATUSLED_PERIOD,period) < 0)
>     perror("led on: ");
> }
> 
> ...
> 
> int led0 = open("/dev/led0",O_RDWR)
> ...
>   led_blink(led0);	/* turn on green LED */
> ..
> /Hans
> 
> 
> On Thu, 2005-03-17 at 06:15, srinivas.surabhi@wipro.com wrote:
> >
> > -----Original Message-----
> > From: Srinivas Surabhi (WT01 - TELECOM SOLUTIONS)
> > Sent: Thursday, March 17, 2005 7:53 AM
> > To: linuxppc-embedded@ozlabs.org
> > Subject: LED driver
> >
> > Hi,
> >
> > I am working on the MPC8270 board having connected GPIO 3 lines
> > connected to 3 LEDs. So can any one help me in finding out the best
> > solution of controlling the LEDs from MVlinux (kernel and user space)
> or
> > any pointers who has done it before.
> >
> > Thanks & Rgds
> > SS
> >
> >
> >
> >
> > Confidentiality Notice
> >
> > The information contained in this electronic message and any
> attachments to this message are intended
> > for the exclusive use of the addressee(s) and may contain confidential
> or privileged information. If
> > you are not the intended recipient, please notify the sender at Wipro
> or Mailadmin@wipro.com immediately
> > and destroy all copies of this message and any attachments.
> > _______________________________________________
> > Linuxppc-embedded mailing list
> > Linuxppc-embedded@ozlabs.org
> > https://ozlabs.org/mailman/listinfo/linuxppc-embedded
> >
> 
> 
> 
> Confidentiality Notice
> 
> The information contained in this electronic message and any attachments to this message are intended
> for the exclusive use of the addressee(s) and may contain confidential or privileged information. If
> you are not the intended recipient, please notify the sender at Wipro or Mailadmin@wipro.com immediately
> and destroy all copies of this message and any attachments.
> 

[-- Attachment #2: status_led.c --]
[-- Type: text/x-c, Size: 15945 bytes --]


/***********************************************************************
 *
 * (C) Copyright 1999, 2000, 2001
 * DENX Software Engineering
 * Wolfgang Denk, wd@denx.de
 * All rights reserved.
 *
 ***********************************************************************/

/*
 * Standard in kernel modules
 */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/spinlock.h>
#include <asm/types.h>
#include <asm/uaccess.h>
#include <asm/8xx_immap.h>
#include <asm/mpc8xx.h>

#include <asm/status_led.h>

#undef	DEBUG

#ifdef	DEBUG
# define debugk(fmt,args...)	printk(fmt ,##args)
#else
# define debugk(fmt,args...)
#endif

/*
 * Deal with CONFIG_MODVERSIONS
 */
#if CONFIG_MODVERSIONS==1
/* # define MODVERSIONS */
# include <linux/modversions.h>
#endif

/*
 * For character devices
 */
#include <linux/fs.h>		/* character device definitions	*/
#include <linux/wrapper.h>	/* wrapper for compatibility with future versions */

#if defined(CONFIG_IVMS8) || defined(CONFIG_IVML24)
static DECLARE_WAIT_QUEUE_HEAD(statusled_wait);
static char last_io_state;
static volatile char changed_io_state;
static spinlock_t statusled_lock;
static struct timer_list io_timer;
static void status_io_poll (unsigned long period);
static int  status_io_test (void);
#endif	/* CONFIG_IVMS8, CONFIG_IVML24 */

#define	LED_MAJOR	151	/* Reserverd for "Front panel LEDs" */

#define DRIVER_VERSION	"$Revision: 1.0 $"

static void statusled_blink (unsigned long minor);

/*
 * Device Declarations
 */

typedef struct {
	unsigned long		mask;
	int			state;
	int			period;
	int			flags;
	struct timer_list	timer;
} led_dev_t;

#define	SL_FLAG_OPEN	1

led_dev_t led_dev[] = {
    {	STATUS_LED_BIT,
	STATUS_LED_STATE,
	STATUS_LED_PERIOD,
	0,
	{ function: statusled_blink, data: 0UL /* minor 0 */ },
    },
#if defined(STATUS_LED_BIT1)
    {	STATUS_LED_BIT1,
	STATUS_LED_STATE1,
	STATUS_LED_PERIOD1,
	0,
	{ function: statusled_blink, data: 1UL /* minor 1 */ },
    },
#endif	/* STATUS_LED_BIT1 */
#if defined(STATUS_LED_BIT2)
    {	STATUS_LED_BIT2,
	STATUS_LED_STATE2,
	STATUS_LED_PERIOD2,
	0,
	{ function: statusled_blink, data: 2UL /* minor 2 */ },
    },
#endif	/* STATUS_LED_BIT2 */
};

#define	MAX_LED_DEV	(sizeof(led_dev)/sizeof(led_dev_t))

/*
 * On the IVM* we handle 2 additional devices with this driver:
 * MAX_LED_DEV+0 => "Interlock Switch" and "Device Reset Monitor":
 *			Both are input pins, which are polled periodically,
 *			and the user can wait with select() for a status change.
 * MAX_LED_DEV+1 => "Device Reset Enable", an output device we can set or reset.
 */
#if defined(CONFIG_IVMS8) || defined(CONFIG_IVML24)
# define MAX_IO_DEV	2
static int io_dev_flags[MAX_IO_DEV] = { 0, };	/* additional I/O devices */
#else
# define MAX_IO_DEV	0
#endif	/* CONFIG_IVMS8, CONFIG_IVML24 */


static volatile immap_t *immr = NULL;

/*
 * The name for our device, as it will appear in /proc/devices
 */
#define DEVICE_NAME "status_led"

/*
 * Prototypes
 */
static int statusled_init (void) __init;
static int statusled_open(struct inode *, struct file *);
static int statusled_release(struct inode *, struct file *);
# if defined(CONFIG_IVMS8) || defined(CONFIG_IVML24)
static ssize_t statusled_read(struct file *, char *, size_t, loff_t *);
static unsigned int statusled_poll (struct file *, poll_table *);
# endif	/* CONFIG_IVMS8, CONFIG_IVML24 */
int init_module(void);
void cleanup_module(void);

static ssize_t statusled_ioctl(struct inode *, struct file *,
			    unsigned int, unsigned long);

static struct file_operations statusled_fops = {
	owner:		THIS_MODULE,
	open:		statusled_open,
	release:	statusled_release,
	ioctl: 		statusled_ioctl,
# if defined(CONFIG_IVMS8) || defined(CONFIG_IVML24)
	read:		statusled_read,
	poll:		statusled_poll,
# endif	/* CONFIG_IVMS8, CONFIG_IVML24 */
};

static int Major;

/*
 * Initialize the driver - Register the character device
 */
static int __init statusled_init (void)
{
	int i;

	if (!immr) {		/* init CPM ptr */
		unsigned long val;

		asm( "mfspr %0,638": "=r"(val) : );
		val &= 0xFFFF0000;
		immr = (volatile immap_t *)val;
	}

	/*
	 * Register the character device
	 */
	if ((i = register_chrdev(LED_MAJOR, DEVICE_NAME, &statusled_fops)) < 0) {
		immr = NULL;
		printk("Unable to get major %d for status LED driver: rc=%d\n",
			LED_MAJOR, i);
		return (i);
	}

	Major = LED_MAJOR;

	printk (KERN_INFO
		"Status LED driver " DRIVER_VERSION " initialized\n");

	for (i=0; i<MAX_LED_DEV; ++i) {
		immr->STATUS_LED_PAR &= ~(led_dev[i].mask);
#ifdef STATUS_LED_ODR
		immr->STATUS_LED_ODR &= ~(led_dev[i].mask);
#endif
		if (led_dev[i].state == STATUS_LED_ON) {
			#if (STATUS_LED_ACTIVE == 0)	/* start with LED on */
			immr->STATUS_LED_DAT &= ~(led_dev[i].mask);
			#else
			immr->STATUS_LED_DAT |=   led_dev[i].mask ;
			#endif
		} else {
			#if (STATUS_LED_ACTIVE == 0)	/* start with LED off */
			immr->STATUS_LED_DAT |=   led_dev[i].mask ;
			#else
			immr->STATUS_LED_DAT &= ~(led_dev[i].mask);
			#endif
		}
		immr->STATUS_LED_DIR |= led_dev[i].mask;

		statusled_blink(i);
	}
#if defined(CONFIG_IVML24)
	/*
	 * Configure interlock switch port for input
	 */
	immr->im_cpm.cp_pbpar &= ~(STATUS_ILOCK_SWITCH);
	immr->im_cpm.cp_pbodr &= ~(STATUS_ILOCK_SWITCH);
	immr->im_cpm.cp_pbdir &= ~(STATUS_ILOCK_SWITCH);
	
#endif	/* CONFIG_IVML24 */

#if defined(CONFIG_IVMS8) || defined(CONFIG_IVML24)
	/*
	 * Configure device reset monitor port for input
	 */
	immr->im_ioport.iop_pcpar &= ~(STATUS_RESET_MON);
	immr->im_ioport.iop_pcso  &= ~(STATUS_RESET_MON);
	immr->im_ioport.iop_pcdir &= ~(STATUS_RESET_MON);
	/*
	 * Configure device reset enable port for output
	 * Initialize with low (0) level
	 */
	immr->im_ioport.iop_pcpar &= ~(STATUS_RESET_ENA);
	immr->im_ioport.iop_pcso  &= ~(STATUS_RESET_ENA);
	immr->im_ioport.iop_pcdat &= ~(STATUS_RESET_ENA);	/* set 0  */
	immr->im_ioport.iop_pcdir |=   STATUS_RESET_ENA ;	/* output */
	/*
	 * We use the same function (originally for the ILOCK device only)
	 * to poll both the ILOCK and RESET_MON ports
	 */
	io_timer.function = status_io_poll;
	io_timer.data     = STATUS_ILOCK_PERIOD;

	last_io_state = (char)status_io_test();
	changed_io_state = 0;

	init_timer(&io_timer);
	io_timer.expires = jiffies + io_timer.data;
	add_timer(&io_timer);
#endif	/* CONFIG_IVMS8, CONFIG_IVML24 */

	return (0);
}

/*
 * called whenever a process attempts to open the device
 */
static int statusled_open (struct inode *inode, struct file *file)
{
	int minor  = MINOR(inode->i_rdev);

	debugk ("statusled_open(%p,%p): minor %d\n", inode, file, minor);

	/*
	 * Allow for MAX_LED_DEV status LEDs
	 * On IVMS8 and IVML24: allow for additional I/O devices
	 */
	if (minor >= MAX_LED_DEV + MAX_IO_DEV)
		return (-ENXIO);

	if (!immr)
		return (-ENODEV);

	/*
	 * exclusive open only
	 */
	if (minor < MAX_LED_DEV) {
		if (led_dev[minor].flags & SL_FLAG_OPEN)
			return -EBUSY;
		led_dev[minor].flags |= SL_FLAG_OPEN;
#if defined(CONFIG_IVMS8) || defined(CONFIG_IVML24)
	} else {
		int m = minor - MAX_LED_DEV;

		if (io_dev_flags[m] & SL_FLAG_OPEN)
			return -EBUSY;
		io_dev_flags[m] |= SL_FLAG_OPEN;
#endif	/* CONFIG_IVMS8, CONFIG_IVML24 */
	}

	/*
	 * Make sure that the module isn't removed while
	 * the file is open by incrementing the usage count
	 */
	MOD_INC_USE_COUNT;

	debugk ("LED_OPEN: minor %d  dir=0x%x  par=0x%x  odr=0x%x  dat=0x%x\n",
		minor,
		immr->STATUS_LED_DIR, immr->STATUS_LED_PAR,
		immr->STATUS_LED_ODR, immr->STATUS_LED_DAT);

	return 0;
}


/*
 * Called when a process closes the device.
 * Doesn't have a return value in version 2.0.x because it can't fail,
 * but in version 2.2.x it is allowed to fail
 */
static int statusled_release (struct inode *inode, struct file *file)
{
	int minor  = MINOR(inode->i_rdev);

	debugk ("statusled_release(%p,%p)\n", inode, file);

	if (!immr)
		return (-ENODEV);

	/* We're now ready for our next caller */
	if (minor < MAX_LED_DEV) {
		led_dev[minor].flags &= ~SL_FLAG_OPEN;
#if defined(CONFIG_IVMS8) || defined(CONFIG_IVML24)
	} else {
		int m = minor - MAX_LED_DEV;

		io_dev_flags[m] &= ~SL_FLAG_OPEN;
#endif	/* CONFIG_IVMS8, CONFIG_IVML24 */
	}

	MOD_DEC_USE_COUNT;

	debugk ("LED_CLOSE: dir=0x%x  par=0x%x  odr=0x%x  dat=0x%x\n",
		immr->STATUS_LED_DIR, immr->STATUS_LED_PAR,
		immr->STATUS_LED_ODR, immr->STATUS_LED_DAT);

	return 0;
}

#if defined(CONFIG_IVMS8) || defined(CONFIG_IVML24)
/*
 * read entry point:
 * Only supported for interlock switch (return ENXIO for LED devices).
 * For the ilock switch, block until the next status change happens;
 * then return exactly one byte containing the current state
 * (0x00 switch open, 0x01 switch closed).
 */
static ssize_t statusled_read (struct file *file,
			       char *buf, size_t count, loff_t *ppos)
{
	DECLARE_WAITQUEUE(wait, current);
	int minor = MINOR(file->f_dentry->d_inode->i_rdev);
	int rc = 0;
	char c;

	if (minor != MAX_LED_DEV)
		return (-ENXIO);

	add_wait_queue(&statusled_wait, &wait);

	current->state = TASK_INTERRUPTIBLE;

	for (;;) {
		if (changed_io_state)
			break;

		if (file->f_flags & O_NONBLOCK) {
			rc = -EAGAIN;
			goto OUT;
		}

		if (signal_pending(current)) {
			rc = -ERESTARTSYS;
			goto OUT;
		}

		schedule ();
	}

	spin_lock (&statusled_lock);
	c = (char)status_io_test ();
	changed_io_state = 0;
	spin_unlock (&statusled_lock);

	/* Copy out */
	if ((rc = verify_area(VERIFY_WRITE, buf, 1)) != 0) {
		goto OUT;
	}

        rc = 1; copy_to_user((void *)buf, (void*)(&c), rc);

OUT:
        current->state = TASK_RUNNING;
        remove_wait_queue(&statusled_wait, &wait);

	return (rc);
}

static unsigned int statusled_poll (struct file *file, poll_table *wait)
{
	poll_wait(file, &statusled_wait, wait);

	if (changed_io_state)
		return POLLIN | POLLRDNORM;

	return 0;
}

#endif	/* CONFIG_IVMS8, CONFIG_IVML24 */

/*
 * ioctl entry point:
 */

static ssize_t statusled_ioctl (
	struct inode *inode,
	struct file *file,
	unsigned int cmd,
	unsigned long arg)
{
	int minor  = MINOR(inode->i_rdev);
	int n;

	if (!immr)
		return (-ENODEV);

	debugk ("IOCTL: minor=%d, cmd=%s, arg=%ld\n",
		minor,
		(cmd == STATUSLED_GET   ) ? "STATUSLED_GET"    :
		(cmd == STATUSLED_SET   ) ? "STATUSLED_SET"    :
		(cmd == STATUSLED_PERIOD) ? "STATUSLED_PERIOD" :
		"<unknown>",
		arg);

	if (minor < MAX_LED_DEV) {
		switch (cmd) {
		case STATUSLED_GET:
			switch (led_dev[minor].state) {
			case STATUS_LED_OFF:	n =  0;
						break;
			case STATUS_LED_ON:	n = -1;
						break;
			default:		n = led_dev[minor].period;
						break;
			}
			return (copy_to_user((int *)arg, &n, sizeof (int)));
		case STATUSLED_SET:
			switch (arg) {
			case STATUS_LED_OFF:
				debugk ("IOCTL: was %d, set %ld=OFF\n",
					led_dev[minor].state, arg);
				if (led_dev[minor].state == STATUS_LED_BLINKING)
					del_timer(&led_dev[minor].timer);
				led_dev[minor].state = arg;
#if (STATUS_LED_ACTIVE == 0)
				immr->STATUS_LED_DAT |=   led_dev[minor].mask ;
#else
				immr->STATUS_LED_DAT &= ~(led_dev[minor].mask);
#endif
				return (0);
			case STATUS_LED_ON:
				debugk ("IOCTL: was %d, set %ld=ON\n",
					led_dev[minor].state, arg);
				if (led_dev[minor].state == STATUS_LED_BLINKING)
					del_timer(&led_dev[minor].timer);
				led_dev[minor].state = arg;
#if (STATUS_LED_ACTIVE == 0)
				immr->STATUS_LED_DAT &= ~(led_dev[minor].mask);
#else
				immr->STATUS_LED_DAT |=   led_dev[minor].mask ;
#endif
				return (0);
			case STATUS_LED_BLINKING:
				debugk ("IOCTL: was %d, set %ld=BLINKING\n",
					led_dev[minor].state, arg);
				if (led_dev[minor].state == STATUS_LED_BLINKING)
					return (0);
				led_dev[minor].state = arg; /* must come first! */
				/* start blinking */
				statusled_blink (minor);
				return (0);
			}
			return (-EINVAL);
		case STATUSLED_PERIOD:
			led_dev[minor].period = arg;
			debugk ("IOCTL: set PERIOD=%d\n", arg);
			return (0);
		}
	}
#if defined(CONFIG_IVMS8) || defined(CONFIG_IVML24)
	else {
		int m = minor - MAX_LED_DEV;

		switch (m) {
		case 0:		/* Interlock switch and device reset monitor */
		    if (cmd == STATUS_SWITCH_GET) {
			n = status_io_test ();
			return (copy_to_user((int *)arg, &n, sizeof (int)));
		    }
		    break;
		case 1:		/* Device reset enable output */
		    if (cmd == STATUS_RESET_GET) {
			if (immr->im_ioport.iop_pcdat & STATUS_RESET_ENA) {
				n = 1;
			} else {
				n = 0;
			}
			return (copy_to_user((int *)arg, &n, sizeof (int)));
		    }
		    if (cmd == STATUS_RESET_SET) {
			if (arg == 0) {
				immr->im_ioport.iop_pcdat &= ~STATUS_RESET_ENA;
			} else {
				immr->im_ioport.iop_pcdat |=  STATUS_RESET_ENA;
			}
			return (0);
		    }
		    break;
		default:
		    break;
		}
	}
#endif
	return (-EINVAL);
}

#if defined(CONFIG_IVMS8) || defined(CONFIG_IVML24)
/*
 * Test status of interlock switch
 */
static int  status_io_test (void)
{
	int n = 0;

#if defined(CONFIG_IVMS8)
	spin_lock (&statusled_lock);
	if ((immr->im_siu_conf.sc_sipend & STATUS_ILOCK_SWITCH) != 0)
		n |= STATUS_ILOCK_BIT;
	immr->im_siu_conf.sc_sipend = STATUS_ILOCK_SWITCH;
	spin_unlock (&statusled_lock);
#elif defined(CONFIG_IVML24)
	if ((immr->im_cpm.cp_pbdat & STATUS_ILOCK_SWITCH) != 0)
		n |= STATUS_ILOCK_BIT;
#endif
	if ((immr->im_ioport.iop_pcdat & STATUS_RESET_MON) != 0)
		n |= STATUS_RESET_MON_BIT;
	return (n);
}

static void status_io_poll (unsigned long period)
{
	char c;

	spin_lock (&statusled_lock);
	c = (char)status_io_test ();
	if (c != last_io_state) {
		last_io_state = c;
		changed_io_state = 1;
	}
	spin_unlock (&statusled_lock);

	if (changed_io_state)
		wake_up_interruptible(&statusled_wait);

	init_timer(&io_timer);
	io_timer.expires = jiffies + io_timer.data;
	add_timer(&io_timer);
}
#endif	/* CONFIG_IVMS8, CONFIG_IVML24 */


/*
 * Timer controlled blink entry point.
 *
 * We delete the timer when the status is changed to non-blinking
 * or when the module is unloaded.
 */
static void statusled_blink (unsigned long minor)
{
	unsigned long flags;

	if (!immr)
		return;

        if (led_dev[minor].state != STATUS_LED_BLINKING) {
		/* don't change any more */
		return;
	}

	immr->STATUS_LED_DAT ^= led_dev[minor].mask;

	save_flags(flags);
	cli();

	init_timer(&led_dev[minor].timer);
	led_dev[minor].timer.expires = jiffies + led_dev[minor].period;
	add_timer(&led_dev[minor].timer);

	restore_flags(flags);
}


/******************************
 **** Module Declarations *****
 **************************** */

module_init (statusled_init);

#ifdef MODULE
/*
 * Cleanup - unregister the driver
 */
void statusled_cleanup (void)
{
	int minor, ret;

	/*
	 * Cleanup timer
	 */
	for (minor=0; minor<MAX_LED_DEV; ++minor) {
		if (led_dev[minor].state == STATUS_LED_BLINKING)
			del_timer(&led_dev[minor].timer);
#if (STATUS_LED_ACTIVE == 0)
		immr->STATUS_LED_DAT |=   led_dev[minor].mask ;
#else
		immr->STATUS_LED_DAT &= ~(led_dev[minor].mask);
#endif
		led_dev[minor].state = STATUS_LED_OFF;
	}
#if defined(CONFIG_IVMS8) || defined(CONFIG_IVML24)
	del_timer(&io_timer);
#endif	/* CONFIG_IVMS8, CONFIG_IVML24 */

	/*
	 * Unregister the device
	 */
	ret = unregister_chrdev (Major, DEVICE_NAME);

	/*
	 * If there's an error, report it
	 */
	if (ret < 0) {
		printk ("unregister_chrdev: error %d\n", ret);
	}
}

module_exit (statusled_cleanup);

#endif	/* MODULE */

[-- Attachment #3: status_led.h --]
[-- Type: text/x-h, Size: 9598 bytes --]

/*
 * (C) Copyright 2000, 2001
 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

/*
 * This code implements one or more status LEDs which can be switched
 * on or off or set to blink at a specified frequency.
 *
 * For instance you can use a status LED to signal the operational
 * status of a target which usually boots over the network; while
 * running in PPCBoot, the status LED is blinking. As soon as a valid
 * BOOTP reply message has been received, the LED is turned off. The
 * Linux kernel, once it is running, will start blinking the LED
 * again, with another frequency.
 *
 * For IVM* systems, this driver is also used to read and write some
 * special I/O ports:
 *
 * - The "Interlock Switch" and the "Device Reset Monitor" are input
 *   ports (one bit each), which are used to signal status changes to
 *   the applications. It is a requirement to be able to wait for
 *   such a status change using select(). Unfortunately, the hardware
 *   is different for IVMS8 and IVML24, and not all input pins used
 *   can generate interrupts. So we have to poll the ports
 *   periodically - sic!
 * - "Device Reset Enable" is an output port (1 bit) which can be set
 *   and reset from the application. OK, finally we have something
 *   really simple.
 */

#ifndef _PPC_STATUS_LED_H
#define	_PPC_STATUS_LED_H

#include <linux/config.h>
#include <asm/ioctl.h>

/* ioctl's */
#define STATUSLED_GET		_IOR('L', 1, unsigned long)
#define STATUSLED_SET		_IOW('L', 2, unsigned long)
#define STATUSLED_PERIOD	_IOW('L', 3, unsigned long)
#define	STATUS_SWITCH_GET	_IOR('L', 4, unsigned long)
#define STATUS_RESET_GET	_IOR('L', 5, unsigned long)
#define STATUS_RESET_SET	_IOW('L', 6, unsigned long)

#define	STATUS_LED_OFF		0
#define STATUS_LED_BLINKING	1
#define STATUS_LED_ON		2

#ifdef __KERNEL__

/*****  TQM8xxL  ********************************************************/
#if (defined(CONFIG_TQM8xxL) && !defined(CONFIG_ETX094))
# define STATUS_LED_PAR		im_cpm.cp_pbpar
# define STATUS_LED_DIR		im_cpm.cp_pbdir
# define STATUS_LED_ODR		im_cpm.cp_pbodr
# define STATUS_LED_DAT		im_cpm.cp_pbdat

# define STATUS_LED_BIT		0x00000001
# define STATUS_LED_PERIOD	(2 * HZ)
# define STATUS_LED_STATE	STATUS_LED_BLINKING

# define STATUS_LED_ACTIVE	1		/* LED on for bit == 1	*/

# define STATUS_LED_BOOT	0		/* LED 0 used for boot status */

/*****  ETX_094  ********************************************************/
#elif defined(CONFIG_ETX094)

# define STATUS_LED_PAR		im_ioport.iop_pdpar
# define STATUS_LED_DIR		im_ioport.iop_pddir
# undef  STATUS_LED_ODR
# define STATUS_LED_DAT		im_ioport.iop_pddat

# define STATUS_LED_BIT		0x00000001
# define STATUS_LED_PERIOD	(2 * HZ)
# define STATUS_LED_STATE	STATUS_LED_BLINKING

# define STATUS_LED_ACTIVE	0		/* LED on for bit == 0	*/

# define STATUS_LED_BOOT	0		/* LED 0 used for boot status */

/*****  IVMS8  **********************************************************/
#elif defined(CONFIG_IVMS8)

# define STATUS_LED_PAR		im_cpm.cp_pbpar
# define STATUS_LED_DIR		im_cpm.cp_pbdir
# define STATUS_LED_ODR		im_cpm.cp_pbodr
# define STATUS_LED_DAT		im_cpm.cp_pbdat

# define STATUS_LED_BIT		0x00000010	/* LED 0 is on PB.27	*/
# define STATUS_LED_PERIOD	(1 * HZ)
# define STATUS_LED_STATE	STATUS_LED_OFF
# define STATUS_LED_BIT1	0x00000020	/* LED 1 is on PB.26	*/
# define STATUS_LED_PERIOD1	(1 * HZ)
# define STATUS_LED_STATE1	STATUS_LED_OFF
/* IDE LED usable for other purposes, too */
# define STATUS_LED_BIT2	0x00000008	/* LED 2 is on PB.28	*/
# define STATUS_LED_PERIOD2	(1 * HZ)
# define STATUS_LED_STATE2	STATUS_LED_OFF

# define STATUS_LED_ACTIVE	1		/* LED on for bit == 1	*/

# define STATUS_LED_YELLOW	0
# define STATUS_LED_GREEN	1
# define STATUS_LED_BOOT	2		/* IDE LED used for boot status */

# define STATUS_ILOCK_BIT	0x01
# define STATUS_RESET_MON_BIT	0x02

# define STATUS_ILOCK_SWITCH	0x00800000	/* ILOCK switch in IRQ4	*/

# define STATUS_ILOCK_PERIOD	(HZ / 10)	/* about every 100 ms	*/

# define STATUS_RESET_MON	0x0008		/* Reset Mon. on PC.12	*/
						/* polled with ILOCK	*/
# define STATUS_RESET_ENA	0x0004		/* Reset enable  PC.13	*/

/*****  IVML24  *********************************************************/
#elif defined(CONFIG_IVML24)

# define STATUS_LED_PAR		im_cpm.cp_pbpar
# define STATUS_LED_DIR		im_cpm.cp_pbdir
# define STATUS_LED_ODR		im_cpm.cp_pbodr
# define STATUS_LED_DAT		im_cpm.cp_pbdat

# define STATUS_LED_BIT		0x00000010
# define STATUS_LED_PERIOD	(1 * HZ)
# define STATUS_LED_STATE	STATUS_LED_OFF
# define STATUS_LED_BIT1	0x00000020
# define STATUS_LED_PERIOD1	(1 * HZ)
# define STATUS_LED_STATE1	STATUS_LED_OFF
/* IDE LED usable for other purposes, too */
# define STATUS_LED_BIT2	0x00000008	/* LED 2 is on PB.28	*/
# define STATUS_LED_PERIOD2	(1 * HZ)
# define STATUS_LED_STATE2	STATUS_LED_OFF

# define STATUS_LED_ACTIVE	1		/* LED on for bit == 1	*/

# define STATUS_LED_YELLOW	0
# define STATUS_LED_GREEN	1
# define STATUS_LED_BOOT	2		/* IDE LED used for boot status */

# define STATUS_ILOCK_BIT	0x01
# define STATUS_RESET_MON_BIT	0x02

# define STATUS_ILOCK_SWITCH	0x00004000	/* ILOCK is on PB.17	*/

# define STATUS_ILOCK_PERIOD	(HZ / 10)	/* about every 100 ms	*/

# define STATUS_RESET_MON	0x0008		/* Reset Mon. on PC.12	*/
						/* polled with ILOCK	*/
# define STATUS_RESET_ENA	0x0004		/* Reset enable  PC.13	*/

/*****  PCU E  and  CCM  ************************************************/
#elif defined(CONFIG_PCU_E) || defined(CONFIG_CCM)

# define STATUS_LED_PAR		im_cpm.cp_pbpar
# define STATUS_LED_DIR		im_cpm.cp_pbdir
# undef  STATUS_LED_ODR		im_cpm.cp_pbodr
# define STATUS_LED_DAT		im_cpm.cp_pbdat

# define STATUS_LED_BIT		0x00010000	/* green LED is on PB.15 */
# define STATUS_LED_PERIOD	(2 * HZ)
# define STATUS_LED_STATE	STATUS_LED_BLINKING
# define STATUS_LED_BIT1	0x00020000	/*  red  LED is on PB.14 */
# define STATUS_LED_PERIOD1	(1 * HZ)
# define STATUS_LED_STATE1	STATUS_LED_OFF

# define STATUS_LED_ACTIVE	1		/* LED on for bit == 1	*/

# define STATUS_LED_BOOT	0		/* LED 0 used for boot status */
# define STATUS_LED_GREEN	STATUS_LED_BOOT
# define STATUS_LED_RED		1

/*****  LANTEC  *********************************************************/
#elif defined(CONFIG_LANTEC)

# define STATUS_LED_PAR		im_ioport.iop_pdpar
# define STATUS_LED_DIR		im_ioport.iop_pddir
# undef  STATUS_LED_ODR
# define STATUS_LED_DAT		im_ioport.iop_pddat

# define STATUS_LED_BIT		0x0800
# define STATUS_LED_PERIOD	(HZ / 4)
# define STATUS_LED_STATE	STATUS_LED_BLINKING

# define STATUS_LED_ACTIVE	1		/* LED on for bit == 0 */

# define STATUS_LED_BOOT	0		/* LED 0 used for boot status */

/*****  ICU862   ********************************************************/
#elif defined(CONFIG_ICU862)

# define STATUS_LED_PAR		im_ioport.iop_papar
# define STATUS_LED_DIR		im_ioport.iop_padir
# define STATUS_LED_ODR		im_ioport.iop_paodr
# define STATUS_LED_DAT		im_ioport.iop_padat

# define STATUS_LED_BIT		0x4000		/* LED 0 is on PA.1 */
# define STATUS_LED_PERIOD	(2 * HZ)
# define STATUS_LED_STATE	STATUS_LED_BLINKING
# define STATUS_LED_BIT1	0x1000		/* LED 1 is on PA.3 */
# define STATUS_LED_PERIOD1	(1 * HZ)
# define STATUS_LED_STATE1	STATUS_LED_OFF

# define STATUS_LED_ACTIVE	1		/* LED on for bit == 1	*/

# define STATUS_LED_BOOT	0		/* LED 0 used for boot status */

/*****  DAB4K    ********************************************************/
/* STATUS_LED_XXXs are defined in arch/ppc/platforms/dab4k.h            */
#elif defined(CONFIG_DAB4K)


/************************************************************************/
#elif defined(CONFIG_RCB8270)
# define STATUS_LED_PAR		im_ioport.iop_pparc
# define STATUS_LED_DIR		im_ioport.iop_pdirc
# define STATUS_LED_DAT		im_ioport.iop_pdatc
# undef STATUS_LED_ODR

# define STATUS_LED_BIT		0x20000000	/* LED 0 is on PC.2	OPERATE_LED */
# define STATUS_LED_PERIOD	(HZ)
# define STATUS_LED_STATE	STATUS_LED_BLINKING

# define STATUS_LED_BIT1	0x10000000	/* LED 1 is on PC.3	ALARM_LED   */
# define STATUS_LED_PERIOD1	(HZ)
# define STATUS_LED_STATE1	STATUS_LED_ON

# define STATUS_LED_BIT2	0x08000000	/* LED 2 is on PC.4	BOOT_LED    */
# define STATUS_LED_PERIOD2	(HZ)
# define STATUS_LED_STATE2	STATUS_LED_OFF

# define STATUS_LED_ACTIVE	0		/* LED on for bit == 1	*/
# define STATUS_LED_BOOT	2		/* LED 0 used for boot status */

#define PCMCIA_LED		0
#define STATUS_LED		1
#define FRONT_LED		2

#else
# error Status LED configuration missing
#endif

void status_led_tick (unsigned long timestamp);
void status_led_set  (int state);

#endif	/* __KERNEL__ */

#endif	/* _PPC_STATUS_LED_H */

  reply	other threads:[~2005-03-17 12:54 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-03-17 12:47 FW: LED driver srinivas.surabhi
2005-03-17 12:53 ` Hans Schillstrom [this message]
  -- strict thread matches above, loose matches on Subject: below --
2005-03-17  5:15 srinivas.surabhi
2005-03-17  9:46 ` Hans Schillstrom
2005-03-17 11:35   ` Wolfgang Denk

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1111064009.13233.279.camel@hawk.allgon.net \
    --to=hans.schillstrom@pwav.com \
    --cc=linuxppc-embedded@ozlabs.org \
    --cc=srinivas.surabhi@wipro.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).