⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 stargate_ssp.c

📁 tinyos-2.x.rar
💻 C
字号:
/*

 * sg_ssp.c -- Stargate SSP Driver for mote programming

 *

 * Portions Copyright (c) 2002-2003 Intel Corporation

 * All rights reserved.

 *

 * This file is distributed under the terms in the attached INTEL-LICENSE     

 * file. If you do not find these files, copies can be found by writing to

 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 

 * 94704.  Attention:  Intel License Inquiry.



 * Portions Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet

 * Copyright (C) 2001 O'Reilly & Associates

 *

 * The source code in this file can be freely used, adapted,

 * and redistributed in source or binary form, so long as an

 * acknowledgment appears in derived source files.  The citation

 * should list that the code comes from the book "Linux Device

 * Drivers" by Alessandro Rubini and Jonathan Corbet, published

 * by O'Reilly & Associates.   No warranty is attached;

 * we cannot take responsibility for errors or fitness for use.

 *

 * $Id: stargate_ssp.c,v 1.4 2006/12/12 18:23:01 vlahan Exp $

 */



#ifndef __KERNEL__

#  define __KERNEL__

#endif

#ifndef MODULE

#  define MODULE

#endif



#include <linux/config.h>



#ifdef CONFIG_MODVERSIONS

#define MODVERSIONS

#include <linux/modversions.h>

#endif



#include <linux/kernel.h> /* printk() */

#include <linux/module.h>

#include <linux/sched.h>



#include <linux/fs.h>     /* everything... */

#include <linux/errno.h>  /* error codes */

#include <linux/delay.h>  /* udelay */

#include <linux/slab.h>

#include <linux/mm.h>

#include <linux/ioport.h>

#include <linux/interrupt.h>

#include <linux/tqueue.h>

#include <linux/poll.h>

#include <linux/init.h>



#include <asm/io.h>

#include <asm/system.h>

#include <asm/hardware.h>

#include <asm/irq.h>



#define SG_SSP_PHYSBASE (__PREG(SSCR0))

#define SG_SSP_SIZE	(5*4) /* 5 Registers, 4 Bytes each */



#define SG_GPIOCNTL_PHYSBASE (__PREG(GPLR0))

#define SG_GPIOCNTL_SIZE (27*4) /* 27 Registers, 4 Bytes each */



#define SSPS_TNF		(1 << 2)

#define SSPS_RNE		(1 << 3)

#define SSPS_BSY		(1 << 4)

#define SSPS_TFS		(1 << 5)

#define SSPS_RFS		(1 << 6)

#define SSPS_ROR		(1 << 7)



#define SSPC_SSE		(1 << 7)

/*

 * all of the parameters have no "sg_ssp_" prefix, to save typing when

 * specifying them at load time

 */

static int major = 0; /* dynamic by default */

MODULE_PARM(major, "i");



/* Since sg_ssp_base is vremapped in case use_mem==1, remember the phys addr. */

unsigned long sg_ssp_vbase;



MODULE_AUTHOR ("Phil Buonadonna");

MODULE_DESCRIPTION ("Stargate SSP Driver v 0.91");

/*

 * The devices with low minor numbers write/read burst of data to/from

 * specific I/O ports (by default the parallel ones).

 * 

 * The device with 128 as minor number returns ascii strings telling

 * when interrupts have been received. Writing to the device toggles

 * 00/FF on the parallel data lines. If there is a loopback wire, this

 * generates interrupts.  

 */



int sg_ssp_open (struct inode *inode, struct file *filp)

{

  MOD_INC_USE_COUNT;





  GPCR(22) = GPIO_bit(22); // MUX -> Programming mode

  

  SSCR0 = ((10 << 8) | SSPC_SSE | 7);  /* SRC=3, SSE, DSS = 8-bit data */

  

  /* Put attached mote into reset */

  GPCR(77) = GPIO_bit(77); // RSTN -> 0

  

  return 0;

}





int sg_ssp_release (struct inode *inode, struct file *filp)

{

  SSCR0 = 0;



  GPSR(22) = GPIO_bit(22); // MUX -> Serial Comm mode



  /* Clear the reset */

  GPSR(77) = GPIO_bit(77); // RSTN -> 1



  MOD_DEC_USE_COUNT;

  return 0;

}





ssize_t sg_ssp_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)

{

  int retval = count, lcnt = count;

  unsigned char *kbuf=kmalloc(count, GFP_KERNEL), *ptr;

  unsigned int value;



  if (!kbuf) {

    return -ENOMEM;

  }



  ptr = kbuf;



  while (lcnt > 0) {

    while (!(SSSR & SSPS_RNE)) {

      cpu_relax();

    }

    value = SSDR;

    *(ptr++) = value;

    //printk(KERN_INFO "sg_ssp: read 0x%lx from ssp\n",value);

    lcnt--;

  }



  if ( (retval > 0) && copy_to_user(buf, kbuf, retval))

    retval = -EFAULT;

  kfree(kbuf);



  return retval;

}



ssize_t sg_ssp_write(struct file *filp, const char *buf, size_t count,

		     loff_t *f_pos)

{

  int retval = count, lcnt = count;

  unsigned char *kbuf=kmalloc((count+1), GFP_KERNEL), *ptr;

  unsigned int value;



  if (!kbuf) {

    return -ENOMEM;

  }

  if (copy_from_user(kbuf, buf, count)) {

    return -EFAULT;

  }

  ptr = kbuf;



  while (lcnt > 0) {

    while (!(SSSR & SSPS_TNF)) {

      cpu_relax();

    }

    value = *(ptr++);

    SSDR = value;

    //printk(KERN_INFO "sg_ssp: wrote 0x%lx to ssp\n",value);

    lcnt--;

  }

  kfree(kbuf);

  return retval;



}







unsigned int sg_ssp_poll(struct file *filp, poll_table *wait)

{

  return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;

}





struct file_operations sg_ssp_fops = {

  read: sg_ssp_read,

  write: sg_ssp_write,

  poll: sg_ssp_poll,

  open: sg_ssp_open,

  release: sg_ssp_release,

};





void sg_ssp_interrupt(int irq, void *dev_id, struct pt_regs *regs)

{



  unsigned int status = SSSR;



  if (status & SSPS_ROR) {

    printk(KERN_WARNING "sg_ssp: receiver overrun 0x%lx",status);

    SSSR = SSPS_ROR;

  }



}







/* Two wrappers, to use non-page-aligned ioremap() on 2.0 */



/* Remap a not (necessarily) aligned port region */

void *sg_ssp_remap(unsigned long phys_addr, unsigned long phys_size)

{

  /* The code comes mainly from arch/any/mm/ioremap.c */

  unsigned long offset, last_addr, size;



  last_addr = phys_addr + phys_size - 1;

  offset = phys_addr & ~PAGE_MASK;

    

    /* Adjust the begin and end to remap a full page */

  phys_addr &= PAGE_MASK;

  size = PAGE_ALIGN(last_addr) - phys_addr;

  return ioremap(phys_addr, size) + offset;

}



/* Unmap a region obtained with sg_ssp_remap */

void sg_ssp_unmap(void *virt_add)

{

  iounmap((void *)((unsigned long)virt_add & PAGE_MASK));

}



/* Finally, init and cleanup */



int sg_ssp_init(void)

{

  int result;

  

  /* Set up owner pointers.*/

  SET_MODULE_OWNER(&sg_ssp_fops);

  

  /* Get our needed resources. */

  result = check_mem_region(SG_SSP_PHYSBASE, SG_SSP_SIZE);

  if (result) {

    printk(KERN_INFO "sg_ssp: can't get I/O mem address 0x%lx\n",

	   SG_SSP_PHYSBASE);

    return result;

  }

  request_mem_region(SG_SSP_PHYSBASE, SG_SSP_SIZE, "SSP");

  

  result = check_mem_region(SG_GPIOCNTL_PHYSBASE, SG_GPIOCNTL_SIZE);

  if (result) {

    printk(KERN_INFO "sg_ssp: can't get GPIO I/O mem address 0x%lx\n",

	   SG_GPIOCNTL_PHYSBASE);

    return result;

  }

  request_mem_region(SG_GPIOCNTL_PHYSBASE, SG_GPIOCNTL_SIZE, "SSPGPIO");



  /* also, ioremap it */

  sg_ssp_vbase = (unsigned long)sg_ssp_remap(SG_SSP_PHYSBASE,SG_SSP_SIZE);

  /* Hmm... we should check the return value */

  

  result = register_chrdev(major, "ssp", &sg_ssp_fops);

  if (result < 0) {

    printk(KERN_INFO "sg_ssp: can't get major number\n");

    sg_ssp_unmap((void *)sg_ssp_vbase);

    release_mem_region(SG_SSP_PHYSBASE,SG_SSP_SIZE);

    return result;

  }

  if (major == 0) major = result; /* dynamic */

  

  result = request_irq(IRQ_SSP, sg_ssp_interrupt,

		       SA_INTERRUPT, "ssp", NULL);

  if (result) {

    printk(KERN_INFO "sg_ssp: can't get assigned irq %i\n",

	   IRQ_SSP);

    sg_ssp_unmap((void *)sg_ssp_vbase);

    release_mem_region(SG_SSP_PHYSBASE,SG_SSP_SIZE);

    return result;

  }



  SSSR = SSPS_ROR;

  SSCR1 = 0;



  // Enable the SSP alternate functions

  set_GPIO_mode(GPIO23_SCLK_md);

  set_GPIO_mode(GPIO25_STXD_MD); // Enable the SSP TX/RX lines

  set_GPIO_mode(GPIO26_SRXD_MD);



  set_GPIO_mode((GPIO27_SEXTCLK | GPIO_IN));    // Avoid driving the RED LED

  set_GPIO_mode((22 | GPIO_OUT));		// MUX Selector

  set_GPIO_mode((77 | GPIO_OUT));		// RSTN 



  /* Set the state of the reset pin */

  GPSR(77) = GPIO_bit(77);  // RSTN -> 1

 

  return 0;

}



void sg_ssp_cleanup(void)

{



  free_irq(IRQ_SSP,NULL);

  unregister_chrdev(major, "ssp");

  sg_ssp_unmap((void *)sg_ssp_vbase);

  release_mem_region(SG_SSP_PHYSBASE,SG_SSP_SIZE);

  release_mem_region(SG_GPIOCNTL_PHYSBASE,SG_GPIOCNTL_SIZE);

}



module_init(sg_ssp_init);

module_exit(sg_ssp_cleanup);

















⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -