From 902663f6ea4a2603bee0d88450aae2d653a46f5d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 26 Aug 2008 22:25:03 -0700 Subject: sparc: Delete bare sbus char bpp driver, obsoleted by parport_sunbpp Signed-off-by: David S. Miller --- drivers/sbus/char/Kconfig | 8 - drivers/sbus/char/Makefile | 1 - drivers/sbus/char/bpp.c | 1055 -------------------------------------------- drivers/sbus/sbus.c | 1 - 4 files changed, 1065 deletions(-) delete mode 100644 drivers/sbus/char/bpp.c (limited to 'drivers/sbus') diff --git a/drivers/sbus/char/Kconfig b/drivers/sbus/char/Kconfig index 400c65bfb8c..9cd54ec63ae 100644 --- a/drivers/sbus/char/Kconfig +++ b/drivers/sbus/char/Kconfig @@ -30,14 +30,6 @@ config OBP_FLASH The OpenBoot PROM on Ultra systems is flashable. If you want to be able to upgrade the OBP firmware, say Y here. -config SUN_BPP - tristate "Bidirectional parallel port support (OBSOLETE)" - depends on EXPERIMENTAL - help - Say Y here to support Sun's obsolete variant of IEEE1284 - bidirectional parallel port protocol as /dev/bppX. Can be built on - x86 machines. - config SUN_VIDEOPIX tristate "Videopix Frame Grabber (EXPERIMENTAL)" depends on EXPERIMENTAL && (BROKEN || !64BIT) diff --git a/drivers/sbus/char/Makefile b/drivers/sbus/char/Makefile index 7ab060e9a5f..d8b2d0c0ebd 100644 --- a/drivers/sbus/char/Makefile +++ b/drivers/sbus/char/Makefile @@ -17,7 +17,6 @@ obj-$(CONFIG_WATCHDOG_RIO) += riowatchdog.o obj-$(CONFIG_OBP_FLASH) += flash.o obj-$(CONFIG_SUN_OPENPROMIO) += openprom.o obj-$(CONFIG_SUN_MOSTEK_RTC) += rtc.o -obj-$(CONFIG_SUN_BPP) += bpp.o obj-$(CONFIG_SUN_VIDEOPIX) += vfc.o obj-$(CONFIG_TADPOLE_TS102_UCTRL) += uctrl.o obj-$(CONFIG_SUN_JSFLASH) += jsflash.o diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c deleted file mode 100644 index bba21e053a1..00000000000 --- a/drivers/sbus/char/bpp.c +++ /dev/null @@ -1,1055 +0,0 @@ -/* - * drivers/sbus/char/bpp.c - * - * Copyright (c) 1995 Picture Elements - * Stephen Williams (steve@icarus.com) - * Gus Baldauf (gbaldauf@ix.netcom.com) - * - * Linux/SPARC port by Peter Zaitcev. - * Integration into SPARC tree by Tom Dyas. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#if defined(__i386__) -# include -#endif - -#if defined(__sparc__) -# include -# include /* udelay() */ - -# include /* OpenProm Library */ -# include -#endif - -#include - -#define BPP_PROBE_CODE 0x55 -#define BPP_DELAY 100 - -static const unsigned BPP_MAJOR = LP_MAJOR; -static const char *bpp_dev_name = "bpp"; - -/* When switching from compatibility to a mode where I can read, try - the following mode first. */ - -/* const unsigned char DEFAULT_ECP = 0x10; */ -static const unsigned char DEFAULT_ECP = 0x30; -static const unsigned char DEFAULT_NIBBLE = 0x00; - -/* - * These are 1284 time constraints, in units of jiffies. - */ - -static const unsigned long TIME_PSetup = 1; -static const unsigned long TIME_PResponse = 6; -static const unsigned long TIME_IDLE_LIMIT = 2000; - -/* - * One instance per supported subdevice... - */ -# define BPP_NO 3 - -enum IEEE_Mode { COMPATIBILITY, NIBBLE, ECP, ECP_RLE, EPP }; - -struct inst { - unsigned present : 1; /* True if the hardware exists */ - unsigned enhanced : 1; /* True if the hardware in "enhanced" */ - unsigned opened : 1; /* True if the device is opened already */ - unsigned run_flag : 1; /* True if waiting for a repeate byte */ - - unsigned char direction; /* 0 --> out, 0x20 --> IN */ - unsigned char pp_state; /* State of host controlled pins. */ - enum IEEE_Mode mode; - - unsigned char run_length; - unsigned char repeat_byte; -}; - -static struct inst instances[BPP_NO]; - -#if defined(__i386__) - -static const unsigned short base_addrs[BPP_NO] = { 0x278, 0x378, 0x3bc }; - -/* - * These are for data access. - * Control lines accesses are hidden in set_bits() and get_bits(). - * The exception is the probe procedure, which is system-dependent. - */ -#define bpp_outb_p(data, base) outb_p((data), (base)) -#define bpp_inb(base) inb(base) -#define bpp_inb_p(base) inb_p(base) - -/* - * This method takes the pin values mask and sets the hardware pins to - * the requested value: 1 == high voltage, 0 == low voltage. This - * burries the annoying PC bit inversion and preserves the direction - * flag. - */ -static void set_pins(unsigned short pins, unsigned minor) -{ - unsigned char bits = instances[minor].direction; /* == 0x20 */ - - if (! (pins & BPP_PP_nStrobe)) bits |= 1; - if (! (pins & BPP_PP_nAutoFd)) bits |= 2; - if ( pins & BPP_PP_nInit) bits |= 4; - if (! (pins & BPP_PP_nSelectIn)) bits |= 8; - - instances[minor].pp_state = bits; - - outb_p(bits, base_addrs[minor]+2); -} - -static unsigned short get_pins(unsigned minor) -{ - unsigned short bits = 0; - - unsigned value = instances[minor].pp_state; - if (! (value & 0x01)) bits |= BPP_PP_nStrobe; - if (! (value & 0x02)) bits |= BPP_PP_nAutoFd; - if (value & 0x04) bits |= BPP_PP_nInit; - if (! (value & 0x08)) bits |= BPP_PP_nSelectIn; - - value = inb_p(base_addrs[minor]+1); - if (value & 0x08) bits |= BPP_GP_nFault; - if (value & 0x10) bits |= BPP_GP_Select; - if (value & 0x20) bits |= BPP_GP_PError; - if (value & 0x40) bits |= BPP_GP_nAck; - if (! (value & 0x80)) bits |= BPP_GP_Busy; - - return bits; -} - -#endif /* __i386__ */ - -#if defined(__sparc__) - -/* - * Register block - */ - /* DMA registers */ -#define BPP_CSR 0x00 -#define BPP_ADDR 0x04 -#define BPP_BCNT 0x08 -#define BPP_TST_CSR 0x0C - /* Parallel Port registers */ -#define BPP_HCR 0x10 -#define BPP_OCR 0x12 -#define BPP_DR 0x14 -#define BPP_TCR 0x15 -#define BPP_OR 0x16 -#define BPP_IR 0x17 -#define BPP_ICR 0x18 -#define BPP_SIZE 0x1A - -/* BPP_CSR. Bits of type RW1 are cleared with writing '1'. */ -#define P_DEV_ID_MASK 0xf0000000 /* R */ -#define P_DEV_ID_ZEBRA 0x40000000 -#define P_DEV_ID_L64854 0xa0000000 /* == NCR 89C100+89C105. Pity. */ -#define P_NA_LOADED 0x08000000 /* R NA wirtten but was not used */ -#define P_A_LOADED 0x04000000 /* R */ -#define P_DMA_ON 0x02000000 /* R DMA is not disabled */ -#define P_EN_NEXT 0x01000000 /* RW */ -#define P_TCI_DIS 0x00800000 /* RW TCI forbidden from interrupts */ -#define P_DIAG 0x00100000 /* RW Disables draining and resetting - of P-FIFO on loading of P_ADDR*/ -#define P_BURST_SIZE 0x000c0000 /* RW SBus burst size */ -#define P_BURST_8 0x00000000 -#define P_BURST_4 0x00040000 -#define P_BURST_1 0x00080000 /* "No burst" write */ -#define P_TC 0x00004000 /* RW1 Term Count, can be cleared when - P_EN_NEXT=1 */ -#define P_EN_CNT 0x00002000 /* RW */ -#define P_EN_DMA 0x00000200 /* RW */ -#define P_WRITE 0x00000100 /* R DMA dir, 1=to ram, 0=to port */ -#define P_RESET 0x00000080 /* RW */ -#define P_SLAVE_ERR 0x00000040 /* RW1 Access size error */ -#define P_INVALIDATE 0x00000020 /* W Drop P-FIFO */ -#define P_INT_EN 0x00000010 /* RW OK to P_INT_PEND||P_ERR_PEND */ -#define P_DRAINING 0x0000000c /* R P-FIFO is draining to memory */ -#define P_ERR_PEND 0x00000002 /* R */ -#define P_INT_PEND 0x00000001 /* R */ - -/* BPP_HCR. Time is in increments of SBus clock. */ -#define P_HCR_TEST 0x8000 /* Allows buried counters to be read */ -#define P_HCR_DSW 0x7f00 /* Data strobe width (in ticks) */ -#define P_HCR_DDS 0x007f /* Data setup before strobe (in ticks) */ - -/* BPP_OCR. */ -#define P_OCR_MEM_CLR 0x8000 -#define P_OCR_DATA_SRC 0x4000 /* ) */ -#define P_OCR_DS_DSEL 0x2000 /* ) Bidirectional */ -#define P_OCR_BUSY_DSEL 0x1000 /* ) selects */ -#define P_OCR_ACK_DSEL 0x0800 /* ) */ -#define P_OCR_EN_DIAG 0x0400 -#define P_OCR_BUSY_OP 0x0200 /* Busy operation */ -#define P_OCR_ACK_OP 0x0100 /* Ack operation */ -#define P_OCR_SRST 0x0080 /* Reset state machines. Not selfcleaning. */ -#define P_OCR_IDLE 0x0008 /* PP data transfer state machine is idle */ -#define P_OCR_V_ILCK 0x0002 /* Versatec faded. Zebra only. */ -#define P_OCR_EN_VER 0x0001 /* Enable Versatec (0 - enable). Zebra only. */ - -/* BPP_TCR */ -#define P_TCR_DIR 0x08 -#define P_TCR_BUSY 0x04 -#define P_TCR_ACK 0x02 -#define P_TCR_DS 0x01 /* Strobe */ - -/* BPP_OR */ -#define P_OR_V3 0x20 /* ) */ -#define P_OR_V2 0x10 /* ) on Zebra only */ -#define P_OR_V1 0x08 /* ) */ -#define P_OR_INIT 0x04 -#define P_OR_AFXN 0x02 /* Auto Feed */ -#define P_OR_SLCT_IN 0x01 - -/* BPP_IR */ -#define P_IR_PE 0x04 -#define P_IR_SLCT 0x02 -#define P_IR_ERR 0x01 - -/* BPP_ICR */ -#define P_DS_IRQ 0x8000 /* RW1 */ -#define P_ACK_IRQ 0x4000 /* RW1 */ -#define P_BUSY_IRQ 0x2000 /* RW1 */ -#define P_PE_IRQ 0x1000 /* RW1 */ -#define P_SLCT_IRQ 0x0800 /* RW1 */ -#define P_ERR_IRQ 0x0400 /* RW1 */ -#define P_DS_IRQ_EN 0x0200 /* RW Always on rising edge */ -#define P_ACK_IRQ_EN 0x0100 /* RW Always on rising edge */ -#define P_BUSY_IRP 0x0080 /* RW 1= rising edge */ -#define P_BUSY_IRQ_EN 0x0040 /* RW */ -#define P_PE_IRP 0x0020 /* RW 1= rising edge */ -#define P_PE_IRQ_EN 0x0010 /* RW */ -#define P_SLCT_IRP 0x0008 /* RW 1= rising edge */ -#define P_SLCT_IRQ_EN 0x0004 /* RW */ -#define P_ERR_IRP 0x0002 /* RW1 1= rising edge */ -#define P_ERR_IRQ_EN 0x0001 /* RW */ - -static void __iomem *base_addrs[BPP_NO]; - -#define bpp_outb_p(data, base) sbus_writeb(data, (base) + BPP_DR) -#define bpp_inb_p(base) sbus_readb((base) + BPP_DR) -#define bpp_inb(base) sbus_readb((base) + BPP_DR) - -static void set_pins(unsigned short pins, unsigned minor) -{ - void __iomem *base = base_addrs[minor]; - unsigned char bits_tcr = 0, bits_or = 0; - - if (instances[minor].direction & 0x20) bits_tcr |= P_TCR_DIR; - if ( pins & BPP_PP_nStrobe) bits_tcr |= P_TCR_DS; - - if ( pins & BPP_PP_nAutoFd) bits_or |= P_OR_AFXN; - if (! (pins & BPP_PP_nInit)) bits_or |= P_OR_INIT; - if (! (pins & BPP_PP_nSelectIn)) bits_or |= P_OR_SLCT_IN; - - sbus_writeb(bits_or, base + BPP_OR); - sbus_writeb(bits_tcr, base + BPP_TCR); -} - -/* - * i386 people read output pins from a software image. - * We may get them back from hardware. - * Again, inversion of pins must he buried here. - */ -static unsigned short get_pins(unsigned minor) -{ - void __iomem *base = base_addrs[minor]; - unsigned short bits = 0; - unsigned value_tcr = sbus_readb(base + BPP_TCR); - unsigned value_ir = sbus_readb(base + BPP_IR); - unsigned value_or = sbus_readb(base + BPP_OR); - - if (value_tcr & P_TCR_DS) bits |= BPP_PP_nStrobe; - if (value_or & P_OR_AFXN) bits |= BPP_PP_nAutoFd; - if (! (value_or & P_OR_INIT)) bits |= BPP_PP_nInit; - if (! (value_or & P_OR_SLCT_IN)) bits |= BPP_PP_nSelectIn; - - if (value_ir & P_IR_ERR) bits |= BPP_GP_nFault; - if (! (value_ir & P_IR_SLCT)) bits |= BPP_GP_Select; - if (! (value_ir & P_IR_PE)) bits |= BPP_GP_PError; - if (! (value_tcr & P_TCR_ACK)) bits |= BPP_GP_nAck; - if (value_tcr & P_TCR_BUSY) bits |= BPP_GP_Busy; - - return bits; -} - -#endif /* __sparc__ */ - -static void snooze(unsigned long snooze_time, unsigned minor) -{ - schedule_timeout_uninterruptible(snooze_time + 1); -} - -static int wait_for(unsigned short set, unsigned short clr, - unsigned long delay, unsigned minor) -{ - unsigned short pins = get_pins(minor); - - unsigned long extime = 0; - - /* - * Try a real fast scan for the first jiffy, in case the device - * responds real good. The first while loop guesses an expire - * time accounting for possible wraparound of jiffies. - */ - while (time_after_eq(jiffies, extime)) extime = jiffies + 1; - while ( (time_before(jiffies, extime)) - && (((pins & set) != set) || ((pins & clr) != 0)) ) { - pins = get_pins(minor); - } - - delay -= 1; - - /* - * If my delay expired or the pins are still not where I want - * them, then resort to using the timer and greatly reduce my - * sample rate. If the peripheral is going to be slow, this will - * give the CPU up to some more worthy process. - */ - while ( delay && (((pins & set) != set) || ((pins & clr) != 0)) ) { - - snooze(1, minor); - pins = get_pins(minor); - delay -= 1; - } - - if (delay == 0) return -1; - else return pins; -} - -/* - * Return ZERO(0) If the negotiation succeeds, an errno otherwise. An - * errno means something broke, and I do not yet know how to fix it. - */ -static int negotiate(unsigned char mode, unsigned minor) -{ - int rc; - unsigned short pins = get_pins(minor); - if (pins & BPP_PP_nSelectIn) return -EIO; - - - /* Event 0: Write the mode to the data lines */ - bpp_outb_p(mode, base_addrs[minor]); - - snooze(TIME_PSetup, minor); - - /* Event 1: Strobe the mode code into the peripheral */ - set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nInit, minor); - - /* Wait for Event 2: Peripheral responds as a 1284 device. */ - rc = wait_for(BPP_GP_PError|BPP_GP_Select|BPP_GP_nFault, - BPP_GP_nAck, - TIME_PResponse, - minor); - - if (rc == -1) return -ETIMEDOUT; - - /* Event 3: latch extensibility request */ - set_pins(BPP_PP_nSelectIn|BPP_PP_nInit, minor); - - /* ... quick nap while peripheral ponders the byte i'm sending...*/ - snooze(1, minor); - - /* Event 4: restore strobe, to ACK peripheral's response. */ - set_pins(BPP_PP_nSelectIn|BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor); - - /* Wait for Event 6: Peripheral latches response bits */ - rc = wait_for(BPP_GP_nAck, 0, TIME_PSetup+TIME_PResponse, minor); - if (rc == -1) return -EIO; - - /* A 1284 device cannot refuse nibble mode */ - if (mode == DEFAULT_NIBBLE) return 0; - - if (pins & BPP_GP_Select) return 0; - - return -EPROTONOSUPPORT; -} - -static int terminate(unsigned minor) -{ - int rc; - - /* Event 22: Request termination of 1284 mode */ - set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor); - - /* Wait for Events 23 and 24: ACK termination request. */ - rc = wait_for(BPP_GP_Busy|BPP_GP_nFault, - BPP_GP_nAck, - TIME_PSetup+TIME_PResponse, - minor); - - instances[minor].direction = 0; - instances[minor].mode = COMPATIBILITY; - - if (rc == -1) { - return -EIO; - } - - /* Event 25: Handshake by lowering nAutoFd */ - set_pins(BPP_PP_nStrobe|BPP_PP_nInit, minor); - - /* Event 26: Peripheral wiggles lines... */ - - /* Event 27: Peripheral sets nAck HIGH to ack handshake */ - rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor); - if (rc == -1) { - set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor); - return -EIO; - } - - /* Event 28: Finish phase by raising nAutoFd */ - set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor); - - return 0; -} - -static DEFINE_SPINLOCK(bpp_open_lock); - -/* - * Allow only one process to open the device at a time. - */ -static int bpp_open(struct inode *inode, struct file *f) -{ - unsigned minor = iminor(inode); - int ret; - - lock_kernel(); - spin_lock(&bpp_open_lock); - ret = 0; - if (minor >= BPP_NO) { - ret = -ENODEV; - } else { - if (! instances[minor].present) { - ret = -ENODEV; - } else { - if (instances[minor].opened) - ret = -EBUSY; - else - instances[minor].opened = 1; - } - } - spin_unlock(&bpp_open_lock); - unlock_kernel(); - - return ret; -} - -/* - * When the process closes the device, this method is called to clean - * up and reset the hardware. Always leave the device in compatibility - * mode as this is a reasonable place to clean up from messes made by - * ioctls, or other mayhem. - */ -static int bpp_release(struct inode *inode, struct file *f) -{ - unsigned minor = iminor(inode); - - spin_lock(&bpp_open_lock); - instances[minor].opened = 0; - - if (instances[minor].mode != COMPATIBILITY) - terminate(minor); - - spin_unlock(&bpp_open_lock); - - return 0; -} - -static long read_nibble(unsigned minor, char __user *c, unsigned long cnt) -{ - unsigned long remaining = cnt; - long rc; - - while (remaining > 0) { - unsigned char byte = 0; - int pins; - - /* Event 7: request nibble */ - set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe, minor); - - /* Wait for event 9: Peripher strobes first nibble */ - pins = wait_for(0, BPP_GP_nAck, TIME_IDLE_LIMIT, minor); - if (pins == -1) return -ETIMEDOUT; - - /* Event 10: I handshake nibble */ - set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nAutoFd, minor); - if (pins & BPP_GP_nFault) byte |= 0x01; - if (pins & BPP_GP_Select) byte |= 0x02; - if (pins & BPP_GP_PError) byte |= 0x04; - if (pins & BPP_GP_Busy) byte |= 0x08; - - /* Wait for event 11: Peripheral handshakes nibble */ - rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor); - - /* Event 7: request nibble */ - set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe, minor); - - /* Wait for event 9: Peripher strobes first nibble */ - pins = wait_for(0, BPP_GP_nAck, TIME_PResponse, minor); - if (rc == -1) return -ETIMEDOUT; - - /* Event 10: I handshake nibble */ - set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nAutoFd, minor); - if (pins & BPP_GP_nFault) byte |= 0x10; - if (pins & BPP_GP_Select) byte |= 0x20; - if (pins & BPP_GP_PError) byte |= 0x40; - if (pins & BPP_GP_Busy) byte |= 0x80; - - if (put_user(byte, c)) - return -EFAULT; - c += 1; - remaining -= 1; - - /* Wait for event 11: Peripheral handshakes nibble */ - rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor); - if (rc == -1) return -EIO; - } - - return cnt - remaining; -} - -static long read_ecp(unsigned minor, char __user *c, unsigned long cnt) -{ - unsigned long remaining; - long rc; - - /* Turn ECP mode from forward to reverse if needed. */ - if (! instances[minor].direction) { - unsigned short pins = get_pins(minor); - - /* Event 38: Turn the bus around */ - instances[minor].direction = 0x20; - pins &= ~BPP_PP_nAutoFd; - set_pins(pins, minor); - - /* Event 39: Set pins for reverse mode. */ - snooze(TIME_PSetup, minor); - set_pins(BPP_PP_nStrobe|BPP_PP_nSelectIn, minor); - - /* Wait for event 40: Peripheral ready to be strobed */ - rc = wait_for(0, BPP_GP_PError, TIME_PResponse, minor); - if (rc == -1) return -ETIMEDOUT; - } - - remaining = cnt; - - while (remaining > 0) { - - /* If there is a run length for a repeated byte, repeat */ - /* that byte a few times. */ - if (instances[minor].run_length && !instances[minor].run_flag) { - - char buffer[128]; - unsigned idx; - unsigned repeat = remaining < instances[minor].run_length - ? remaining - : instances[minor].run_length; - - for (idx = 0 ; idx < repeat ; idx += 1) - buffer[idx] = instances[minor].repeat_byte; - - if (copy_to_user(c, buffer, repeat)) - return -EFAULT; - remaining -= repeat; - c += repeat; - instances[minor].run_length -= repeat; - } - - if (remaining == 0) break; - - - /* Wait for Event 43: Data active on the bus. */ - rc = wait_for(0, BPP_GP_nAck, TIME_IDLE_LIMIT, minor); - if (rc == -1) break; - - if (rc & BPP_GP_Busy) { - /* OK, this is data. read it in. */ - unsigned char byte = bpp_inb(base_addrs[minor]); - if (put_user(byte, c)) - return -EFAULT; - c += 1; - remaining -= 1; - - if (instances[minor].run_flag) { - instances[minor].repeat_byte = byte; - instances[minor].run_flag = 0; - } - - } else { - unsigned char byte = bpp_inb(base_addrs[minor]); - if (byte & 0x80) { - printk("bpp%d: " - "Ignoring ECP channel %u from device.\n", - minor, byte & 0x7f); - } else { - instances[minor].run_length = byte; - instances[minor].run_flag = 1; - } - } - - /* Event 44: I got it. */ - set_pins(BPP_PP_nStrobe|BPP_PP_nAutoFd|BPP_PP_nSelectIn, minor); - - /* Wait for event 45: peripheral handshake */ - rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor); - if (rc == -1) return -ETIMEDOUT; - - /* Event 46: Finish handshake */ - set_pins(BPP_PP_nStrobe|BPP_PP_nSelectIn, minor); - - } - - - return cnt - remaining; -} - -static ssize_t bpp_read(struct file *f, char __user *c, size_t cnt, loff_t * ppos) -{ - long rc; - unsigned minor = iminor(f->f_path.dentry->d_inode); - if (minor >= BPP_NO) return -ENODEV; - if (!instances[minor].present) return -ENODEV; - - switch (instances[minor].mode) { - - default: - if (instances[minor].mode != COMPATIBILITY) - terminate(minor); - - if (instances[minor].enhanced) { - /* For now, do all reads with ECP-RLE mode */ - unsigned short pins; - - rc = negotiate(DEFAULT_ECP, minor); - if (rc < 0) break; - - instances[minor].mode = ECP_RLE; - - /* Event 30: set nAutoFd low to setup for ECP mode */ - pins = get_pins(minor); - pins &= ~BPP_PP_nAutoFd; - set_pins(pins, minor); - - /* Wait for Event 31: peripheral ready */ - rc = wait_for(BPP_GP_PError, 0, TIME_PResponse, minor); - if (rc == -1) return -ETIMEDOUT; - - rc = read_ecp(minor, c, cnt); - - } else { - rc = negotiate(DEFAULT_NIBBLE, minor); - if (rc < 0) break; - - instances[minor].mode = NIBBLE; - - rc = read_nibble(minor, c, cnt); - } - break; - - case NIBBLE: - rc = read_nibble(minor, c, cnt); - break; - - case ECP: - case ECP_RLE: - rc = read_ecp(minor, c, cnt); - break; - - } - - - return rc; -} - -/* - * Compatibility mode handshaking is a matter of writing data, - * strobing it, and waiting for the printer to stop being busy. - */ -static long write_compat(unsigned minor, const char __user *c, unsigned long cnt) -{ - long rc; - unsigned short pins = get_pins(minor); - - unsigned long remaining = cnt; - - - while (remaining > 0) { - unsigned char byte; - - if (get_user(byte, c)) - return -EFAULT; - c += 1; - - rc = wait_for(BPP_GP_nAck, BPP_GP_Busy, TIME_IDLE_LIMIT, minor); - if (rc == -1) return -ETIMEDOUT; - - bpp_outb_p(byte, base_addrs[minor]); - remaining -= 1; - /* snooze(1, minor); */ - - pins &= ~BPP_PP_nStrobe; - set_pins(pins, minor); - - rc = wait_for(BPP_GP_Busy, 0, TIME_PResponse, minor); - - pins |= BPP_PP_nStrobe; - set_pins(pins, minor); - } - - return cnt - remaining; -} - -/* - * Write data using ECP mode. Watch out that the port may be set up - * for reading. If so, turn the port around. - */ -static long write_ecp(unsigned minor, const char __user *c, unsigned long cnt) -{ - unsigned short pins = get_pins(minor); - unsigned long remaining = cnt; - - if (instances[minor].direction) { - int rc; - - /* Event 47 Request bus be turned around */ - pins |= BPP_PP_nInit; - set_pins(pins, minor); - - /* Wait for Event 49: Peripheral relinquished bus */ - rc = wait_for(BPP_GP_PError, 0, TIME_PResponse, minor); - - pins |= BPP_PP_nAutoFd; - instances[minor].direction = 0; - set_pins(pins, minor); - } - - while (remaining > 0) { - unsigned char byte; - int rc; - - if (get_user(byte, c)) - return -EFAULT; - - rc = wait_for(0, BPP_GP_Busy, TIME_PResponse, minor); - if (rc == -1) return -ETIMEDOUT; - - c += 1; - - bpp_outb_p(byte, base_addrs[minor]); - - pins &= ~BPP_PP_nStrobe; - set_pins(pins, minor); - - pins |= BPP_PP_nStrobe; - rc = wait_for(BPP_GP_Busy, 0, TIME_PResponse, minor); - if (rc == -1) return -EIO; - - set_pins(pins, minor); - } - - return cnt - remaining; -} - -/* - * Write to the peripheral. Be sensitive of the current mode. If I'm - * in a mode that can be turned around (ECP) then just do - * that. Otherwise, terminate and do my writing in compat mode. This - * is the safest course as any device can handle it. - */ -static ssize_t bpp_write(struct file *f, const char __user *c, size_t cnt, loff_t * ppos) -{ - long errno = 0; - unsigned minor = iminor(f->f_path.dentry->d_inode); - if (minor >= BPP_NO) return -ENODEV; - if (!instances[minor].present) return -ENODEV; - - switch (instances[minor].mode) { - - case ECP: - case ECP_RLE: - errno = write_ecp(minor, c, cnt); - break; - case COMPATIBILITY: - errno = write_compat(minor, c, cnt); - break; - default: - terminate(minor); - errno = write_compat(minor, c, cnt); - } - - return errno; -} - -static int bpp_ioctl(struct inode *inode, struct file *f, unsigned int cmd, - unsigned long arg) -{ - int errno = 0; - - unsigned minor = iminor(inode); - if (minor >= BPP_NO) return -ENODEV; - if (!instances[minor].present) return -ENODEV; - - - switch (cmd) { - - case BPP_PUT_PINS: - set_pins(arg, minor); - break; - - case BPP_GET_PINS: - errno = get_pins(minor); - break; - - case BPP_PUT_DATA: - bpp_outb_p(arg, base_addrs[minor]); - break; - - case BPP_GET_DATA: - errno = bpp_inb_p(base_addrs[minor]); - break; - - case BPP_SET_INPUT: - if (arg) - if (instances[minor].enhanced) { - unsigned short bits = get_pins(minor); - instances[minor].direction = 0x20; - set_pins(bits, minor); - } else { - errno = -ENOTTY; - } - else { - unsigned short bits = get_pins(minor); - instances[minor].direction = 0x00; - set_pins(bits, minor); - } - break; - - default: - errno = -EINVAL; - } - - return errno; -} - -static const struct file_operations bpp_fops = { - .owner = THIS_MODULE, - .read = bpp_read, - .write = bpp_write, - .ioctl = bpp_ioctl, - .open = bpp_open, - .release = bpp_release, -}; - -#if defined(__i386__) - -#define collectLptPorts() {} - -static void probeLptPort(unsigned idx) -{ - unsigned int testvalue; - const unsigned short lpAddr = base_addrs[idx]; - - instances[idx].present = 0; - instances[idx].enhanced = 0; - instances[idx].direction = 0; - instances[idx].mode = COMPATIBILITY; - instances[idx].run_length = 0; - instances[idx].run_flag = 0; - if (!request_region(lpAddr,3, bpp_dev_name)) return; - - /* - * First, make sure the instance exists. Do this by writing to - * the data latch and reading the value back. If the port *is* - * present, test to see if it supports extended-mode - * operation. This will be required for IEEE1284 reverse - * transfers. - */ - - outb_p(BPP_PROBE_CODE, lpAddr); - for (testvalue=0; testvalueresource[0], 0, BPP_SIZE, "bpp"); -} - -static int collectLptPorts(void) -{ - struct sbus_bus *bus; - struct sbus_dev *dev; - int count; - - count = 0; - for_all_sbusdev(dev, bus) { - if (strcmp(dev->prom_name, "SUNW,bpp") == 0) { - if (count >= BPP_NO) { - printk(KERN_NOTICE - "bpp: More than %d bpp ports," - " rest is ignored\n", BPP_NO); - return count; - } - base_addrs[count] = map_bpp(dev, count); - count++; - } - } - return count; -} - -static void probeLptPort(unsigned idx) -{ - void __iomem *rp = base_addrs[idx]; - __u32 csr; - char *brand; - - instances[idx].present = 0; - instances[idx].enhanced = 0; - instances[idx].direction = 0; - instances[idx].mode = COMPATIBILITY; - instances[idx].run_length = 0; - instances[idx].run_flag = 0; - - if (!rp) return; - - instances[idx].present = 1; - instances[idx].enhanced = 1; /* Sure */ - - csr = sbus_readl(rp + BPP_CSR); - if ((csr & P_DRAINING) != 0 && (csr & P_ERR_PEND) == 0) { - udelay(20); - csr = sbus_readl(rp + BPP_CSR); - if ((csr & P_DRAINING) != 0 && (csr & P_ERR_PEND) == 0) { - printk("bpp%d: DRAINING still active (0x%08x)\n", idx, csr); - } - } - printk("bpp%d: reset with 0x%08x ..", idx, csr); - sbus_writel((csr | P_RESET) & ~P_INT_EN, rp + BPP_CSR); - udelay(500); - sbus_writel(sbus_readl(rp + BPP_CSR) & ~P_RESET, rp + BPP_CSR); - csr = sbus_readl(rp + BPP_CSR); - printk(" done with csr=0x%08x ocr=0x%04x\n", - csr, sbus_readw(rp + BPP_OCR)); - - switch (csr & P_DEV_ID_MASK) { - case P_DEV_ID_ZEBRA: - brand = "Zebra"; - break; - case P_DEV_ID_L64854: - brand = "DMA2"; - break; - default: - brand = "Unknown"; - } - printk("bpp%d: %s at %p\n", idx, brand, rp); - - /* - * Leave the port in compat idle mode. - */ - set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, idx); - - return; -} - -static inline void freeLptPort(int idx) -{ - sbus_iounmap(base_addrs[idx], BPP_SIZE); -} - -#endif - -static int __init bpp_init(void) -{ - int rc; - unsigned idx; - - rc = collectLptPorts(); - if (rc == 0) - return -ENODEV; - - rc = register_chrdev(BPP_MAJOR, bpp_dev_name, &bpp_fops); - if (rc < 0) - return rc; - - for (idx = 0; idx < BPP_NO; idx++) { - instances[idx].opened = 0; - probeLptPort(idx); - } - - return 0; -} - -static void __exit bpp_cleanup(void) -{ - unsigned idx; - - unregister_chrdev(BPP_MAJOR, bpp_dev_name); - - for (idx = 0; idx < BPP_NO; idx++) { - if (instances[idx].present) - freeLptPort(idx); - } -} - -module_init(bpp_init); -module_exit(bpp_cleanup); - -MODULE_LICENSE("GPL"); - diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c index 9c129248466..53e5e7bf545 100644 --- a/drivers/sbus/sbus.c +++ b/drivers/sbus/sbus.c @@ -14,7 +14,6 @@ #include #include #include -#include #include static ssize_t -- cgit v1.2.3 From 7f06a3b2c162573c924f425053227a52b4bd7cb1 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 26 Aug 2008 22:26:21 -0700 Subject: sparc: Kill videopix SBUS driver. This has been marked BROKEN for a long time and it's more likely to get rewritten from scratch than to be fixed up and made usable. Signed-off-by: David S. Miller --- drivers/sbus/char/Kconfig | 9 - drivers/sbus/char/Makefile | 2 - drivers/sbus/char/vfc.h | 171 ---------- drivers/sbus/char/vfc_dev.c | 736 -------------------------------------------- drivers/sbus/char/vfc_i2c.c | 335 -------------------- drivers/sbus/char/vfc_i2c.h | 44 --- 6 files changed, 1297 deletions(-) delete mode 100644 drivers/sbus/char/vfc.h delete mode 100644 drivers/sbus/char/vfc_dev.c delete mode 100644 drivers/sbus/char/vfc_i2c.c delete mode 100644 drivers/sbus/char/vfc_i2c.h (limited to 'drivers/sbus') diff --git a/drivers/sbus/char/Kconfig b/drivers/sbus/char/Kconfig index 9cd54ec63ae..3fd2bc95b51 100644 --- a/drivers/sbus/char/Kconfig +++ b/drivers/sbus/char/Kconfig @@ -30,15 +30,6 @@ config OBP_FLASH The OpenBoot PROM on Ultra systems is flashable. If you want to be able to upgrade the OBP firmware, say Y here. -config SUN_VIDEOPIX - tristate "Videopix Frame Grabber (EXPERIMENTAL)" - depends on EXPERIMENTAL && (BROKEN || !64BIT) - help - Say Y here to support the Videopix Frame Grabber from Sun - Microsystems, commonly found on SPARCstations. This card, which is - based on the Phillips SAA9051, can handle NTSC and PAL/SECAM and - SVIDEO signals. - config TADPOLE_TS102_UCTRL tristate "Tadpole TS102 Microcontroller support (EXPERIMENTAL)" depends on EXPERIMENTAL && SPARC32 diff --git a/drivers/sbus/char/Makefile b/drivers/sbus/char/Makefile index d8b2d0c0ebd..e15bd5e3946 100644 --- a/drivers/sbus/char/Makefile +++ b/drivers/sbus/char/Makefile @@ -7,7 +7,6 @@ # Rewritten to use lists instead of if-statements. # -vfc-objs := vfc_dev.o vfc_i2c.o bbc-objs := bbc_i2c.o bbc_envctrl.o obj-$(CONFIG_ENVCTRL) += envctrl.o @@ -17,7 +16,6 @@ obj-$(CONFIG_WATCHDOG_RIO) += riowatchdog.o obj-$(CONFIG_OBP_FLASH) += flash.o obj-$(CONFIG_SUN_OPENPROMIO) += openprom.o obj-$(CONFIG_SUN_MOSTEK_RTC) += rtc.o -obj-$(CONFIG_SUN_VIDEOPIX) += vfc.o obj-$(CONFIG_TADPOLE_TS102_UCTRL) += uctrl.o obj-$(CONFIG_SUN_JSFLASH) += jsflash.o obj-$(CONFIG_BBC_I2C) += bbc.o diff --git a/drivers/sbus/char/vfc.h b/drivers/sbus/char/vfc.h deleted file mode 100644 index a5240c52aa0..00000000000 --- a/drivers/sbus/char/vfc.h +++ /dev/null @@ -1,171 +0,0 @@ -#ifndef _LINUX_VFC_H_ -#define _LINUX_VFC_H_ - -/* - * The control register for the vfc is at offset 0x4000 - * The first field ram bank is located at offset 0x5000 - * The second field ram bank is at offset 0x7000 - * i2c_reg address the Phillips PCF8584(see notes in vfc_i2c.c) - * data and transmit register. - * i2c_s1 controls register s1 of the PCF8584 - * i2c_write seems to be similar to i2c_write but I am not - * quite sure why sun uses it - * - * I am also not sure whether or not you can read the fram bank as a - * whole or whether you must read each word individually from offset - * 0x5000 as soon as I figure it out I will update this file */ - -struct vfc_regs { - char pad1[0x4000]; - unsigned int control; /* Offset 0x4000 */ - char pad2[0xffb]; /* from offset 0x4004 to 0x5000 */ - unsigned int fram_bank1; /* Offset 0x5000 */ - char pad3[0xffb]; /* from offset 0x5004 to 0x6000 */ - unsigned int i2c_reg; /* Offset 0x6000 */ - unsigned int i2c_magic2; /* Offset 0x6004 */ - unsigned int i2c_s1; /* Offset 0x6008 */ - unsigned int i2c_write; /* Offset 0x600c */ - char pad4[0xff0]; /* from offset 0x6010 to 0x7000 */ - unsigned int fram_bank2; /* Offset 0x7000 */ - char pad5[0x1000]; -}; - -#define VFC_SAA9051_NR (13) -#define VFC_SAA9051_ADDR (0x8a) - /* The saa9051 returns the following for its status - * bit 0 - 0 - * bit 1 - SECAM color detected (1=found,0=not found) - * bit 2 - COLOR detected (1=found,0=not found) - * bit 3 - 0 - * bit 4 - Field frequency bit (1=60Hz (NTSC), 0=50Hz (PAL)) - * bit 5 - 1 - * bit 6 - horizontal frequency lock (1=transmitter found, - * 0=no transmitter) - * bit 7 - Power on reset bit (1=reset,0=at least one successful - * read of the status byte) - */ - -#define VFC_SAA9051_PONRES (0x80) -#define VFC_SAA9051_HLOCK (0x40) -#define VFC_SAA9051_FD (0x10) -#define VFC_SAA9051_CD (0x04) -#define VFC_SAA9051_CS (0x02) - - -/* The various saa9051 sub addresses */ - -#define VFC_SAA9051_IDEL (0) -#define VFC_SAA9051_HSY_START (1) -#define VFC_SAA9051_HSY_STOP (2) -#define VFC_SAA9051_HC_START (3) -#define VFC_SAA9051_HC_STOP (4) -#define VFC_SAA9051_HS_START (5) -#define VFC_SAA9051_HORIZ_PEAK (6) -#define VFC_SAA9051_HUE (7) -#define VFC_SAA9051_C1 (8) -#define VFC_SAA9051_C2 (9) -#define VFC_SAA9051_C3 (0xa) -#define VFC_SAA9051_SECAM_DELAY (0xb) - - -/* Bit settings for saa9051 sub address 0x06 */ - -#define VFC_SAA9051_AP1 (0x01) -#define VFC_SAA9051_AP2 (0x02) -#define VFC_SAA9051_COR1 (0x04) -#define VFC_SAA9051_COR2 (0x08) -#define VFC_SAA9051_BP1 (0x10) -#define VFC_SAA9051_BP2 (0x20) -#define VFC_SAA9051_PF (0x40) -#define VFC_SAA9051_BY (0x80) - - -/* Bit settings for saa9051 sub address 0x08 */ - -#define VFC_SAA9051_CCFR0 (0x01) -#define VFC_SAA9051_CCFR1 (0x02) -#define VFC_SAA9051_YPN (0x04) -#define VFC_SAA9051_ALT (0x08) -#define VFC_SAA9051_CO (0x10) -#define VFC_SAA9051_VTR (0x20) -#define VFC_SAA9051_FS (0x40) -#define VFC_SAA9051_HPLL (0x80) - - -/* Bit settings for saa9051 sub address 9 */ - -#define VFC_SAA9051_SS0 (0x01) -#define VFC_SAA9051_SS1 (0x02) -#define VFC_SAA9051_AFCC (0x04) -#define VFC_SAA9051_CI (0x08) -#define VFC_SAA9051_SA9D4 (0x10) /* Don't care bit */ -#define VFC_SAA9051_OEC (0x20) -#define VFC_SAA9051_OEY (0x40) -#define VFC_SAA9051_VNL (0x80) - - -/* Bit settings for saa9051 sub address 0x0A */ - -#define VFC_SAA9051_YDL0 (0x01) -#define VFC_SAA9051_YDL1 (0x02) -#define VFC_SAA9051_YDL2 (0x04) -#define VFC_SAA9051_SS2 (0x08) -#define VFC_SAA9051_SS3 (0x10) -#define VFC_SAA9051_YC (0x20) -#define VFC_SAA9051_CT (0x40) -#define VFC_SAA9051_SYC (0x80) - - -#define VFC_SAA9051_SA(a,b) ((a)->saa9051_state_array[(b)+1]) -#define vfc_update_saa9051(a) (vfc_i2c_sendbuf((a),VFC_SAA9051_ADDR,\ - (a)->saa9051_state_array,\ - VFC_SAA9051_NR)) - - -struct vfc_dev { - volatile struct vfc_regs __iomem *regs; - struct vfc_regs *phys_regs; - unsigned int control_reg; - struct mutex device_lock_mtx; - int instance; - int busy; - unsigned long which_io; - unsigned char saa9051_state_array[VFC_SAA9051_NR]; -}; - -void captstat_reset(struct vfc_dev *); -void memptr_reset(struct vfc_dev *); - -int vfc_pcf8584_init(struct vfc_dev *); -void vfc_i2c_delay_no_busy(struct vfc_dev *, unsigned long); -void vfc_i2c_delay(struct vfc_dev *); -int vfc_i2c_sendbuf(struct vfc_dev *, unsigned char, char *, int) ; -int vfc_i2c_recvbuf(struct vfc_dev *, unsigned char, char *, int) ; -int vfc_i2c_reset_bus(struct vfc_dev *); -int vfc_init_i2c_bus(struct vfc_dev *); - -#define VFC_CONTROL_DIAGMODE 0x10000000 -#define VFC_CONTROL_MEMPTR 0x20000000 -#define VFC_CONTROL_CAPTURE 0x02000000 -#define VFC_CONTROL_CAPTRESET 0x04000000 - -#define VFC_STATUS_CAPTURE 0x08000000 - -#ifdef VFC_IOCTL_DEBUG -#define VFC_IOCTL_DEBUG_PRINTK(a) printk a -#else -#define VFC_IOCTL_DEBUG_PRINTK(a) -#endif - -#ifdef VFC_I2C_DEBUG -#define VFC_I2C_DEBUG_PRINTK(a) printk a -#else -#define VFC_I2C_DEBUG_PRINTK(a) -#endif - -#endif /* _LINUX_VFC_H_ */ - - - - - diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c deleted file mode 100644 index 25181bb7d62..00000000000 --- a/drivers/sbus/char/vfc_dev.c +++ /dev/null @@ -1,736 +0,0 @@ -/* - * drivers/sbus/char/vfc_dev.c - * - * Driver for the Videopix Frame Grabber. - * - * In order to use the VFC you need to program the video controller - * chip. This chip is the Phillips SAA9051. You need to call their - * documentation ordering line to get the docs. - * - * There is very little documentation on the VFC itself. There is - * some useful info that can be found in the manuals that come with - * the card. I will hopefully write some better docs at a later date. - * - * Copyright (C) 1996 Manish Vachharajani (mvachhar@noc.rutgers.edu) - * */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#define VFC_MAJOR (60) - -#if 0 -#define VFC_IOCTL_DEBUG -#endif - -#include "vfc.h" -#include - -static const struct file_operations vfc_fops; -static struct vfc_dev **vfc_dev_lst; -static char vfcstr[]="vfc"; -static unsigned char saa9051_init_array[VFC_SAA9051_NR] = { - 0x00, 0x64, 0x72, 0x52, - 0x36, 0x18, 0xff, 0x20, - 0xfc, 0x77, 0xe3, 0x50, - 0x3e -}; - -static void vfc_lock_device(struct vfc_dev *dev) -{ - mutex_lock(&dev->device_lock_mtx); -} - -static void vfc_unlock_device(struct vfc_dev *dev) -{ - mutex_unlock(&dev->device_lock_mtx); -} - - -static void vfc_captstat_reset(struct vfc_dev *dev) -{ - dev->control_reg |= VFC_CONTROL_CAPTRESET; - sbus_writel(dev->control_reg, &dev->regs->control); - dev->control_reg &= ~VFC_CONTROL_CAPTRESET; - sbus_writel(dev->control_reg, &dev->regs->control); - dev->control_reg |= VFC_CONTROL_CAPTRESET; - sbus_writel(dev->control_reg, &dev->regs->control); -} - -static void vfc_memptr_reset(struct vfc_dev *dev) -{ - dev->control_reg |= VFC_CONTROL_MEMPTR; - sbus_writel(dev->control_reg, &dev->regs->control); - dev->control_reg &= ~VFC_CONTROL_MEMPTR; - sbus_writel(dev->control_reg, &dev->regs->control); - dev->control_reg |= VFC_CONTROL_MEMPTR; - sbus_writel(dev->control_reg, &dev->regs->control); -} - -static int vfc_csr_init(struct vfc_dev *dev) -{ - dev->control_reg = 0x80000000; - sbus_writel(dev->control_reg, &dev->regs->control); - udelay(200); - dev->control_reg &= ~0x80000000; - sbus_writel(dev->control_reg, &dev->regs->control); - udelay(100); - sbus_writel(0x0f000000, &dev->regs->i2c_magic2); - - vfc_memptr_reset(dev); - - dev->control_reg &= ~VFC_CONTROL_DIAGMODE; - dev->control_reg &= ~VFC_CONTROL_CAPTURE; - dev->control_reg |= 0x40000000; - sbus_writel(dev->control_reg, &dev->regs->control); - - vfc_captstat_reset(dev); - - return 0; -} - -static int vfc_saa9051_init(struct vfc_dev *dev) -{ - int i; - - for (i = 0; i < VFC_SAA9051_NR; i++) - dev->saa9051_state_array[i] = saa9051_init_array[i]; - - vfc_i2c_sendbuf(dev,VFC_SAA9051_ADDR, - dev->saa9051_state_array, VFC_SAA9051_NR); - return 0; -} - -static int init_vfc_hw(struct vfc_dev *dev) -{ - vfc_lock_device(dev); - vfc_csr_init(dev); - - vfc_pcf8584_init(dev); - vfc_init_i2c_bus(dev); /* hopefully this doesn't undo the magic - sun code above*/ - vfc_saa9051_init(dev); - vfc_unlock_device(dev); - return 0; -} - -static int init_vfc_devstruct(struct vfc_dev *dev, int instance) -{ - dev->instance=instance; - mutex_init(&dev->device_lock_mtx); - dev->control_reg=0; - dev->busy=0; - return 0; -} - -static int init_vfc_device(struct sbus_dev *sdev,struct vfc_dev *dev, - int instance) -{ - if(dev == NULL) { - printk(KERN_ERR "VFC: Bogus pointer passed\n"); - return -ENOMEM; - } - printk("Initializing vfc%d\n",instance); - dev->regs = NULL; - dev->regs = (volatile struct vfc_regs __iomem *) - sbus_ioremap(&sdev->resource[0], 0, - sizeof(struct vfc_regs), vfcstr); - dev->which_io = sdev->reg_addrs[0].which_io; - dev->phys_regs = (struct vfc_regs *) sdev->reg_addrs[0].phys_addr; - if (dev->regs == NULL) - return -EIO; - - printk("vfc%d: registers mapped at phys_addr: 0x%lx\n virt_addr: 0x%lx\n", - instance,(unsigned long)sdev->reg_addrs[0].phys_addr,(unsigned long)dev->regs); - - if (init_vfc_devstruct(dev, instance)) - return -EINVAL; - if (init_vfc_hw(dev)) - return -EIO; - return 0; -} - - -static struct vfc_dev *vfc_get_dev_ptr(int instance) -{ - return vfc_dev_lst[instance]; -} - -static DEFINE_SPINLOCK(vfc_dev_lock); - -static int vfc_open(struct inode *inode, struct file *file) -{ - struct vfc_dev *dev; - - lock_kernel(); - spin_lock(&vfc_dev_lock); - dev = vfc_get_dev_ptr(iminor(inode)); - if (dev == NULL) { - spin_unlock(&vfc_dev_lock); - unlock_kernel(); - return -ENODEV; - } - if (dev->busy) { - spin_unlock(&vfc_dev_lock); - unlock_kernel(); - return -EBUSY; - } - - dev->busy = 1; - spin_unlock(&vfc_dev_lock); - - vfc_lock_device(dev); - - vfc_csr_init(dev); - vfc_pcf8584_init(dev); - vfc_init_i2c_bus(dev); - vfc_saa9051_init(dev); - vfc_memptr_reset(dev); - vfc_captstat_reset(dev); - - vfc_unlock_device(dev); - unlock_kernel(); - return 0; -} - -static int vfc_release(struct inode *inode,struct file *file) -{ - struct vfc_dev *dev; - - spin_lock(&vfc_dev_lock); - dev = vfc_get_dev_ptr(iminor(inode)); - if (!dev || !dev->busy) { - spin_unlock(&vfc_dev_lock); - return -EINVAL; - } - dev->busy = 0; - spin_unlock(&vfc_dev_lock); - return 0; -} - -static int vfc_debug(struct vfc_dev *dev, int cmd, void __user *argp) -{ - struct vfc_debug_inout inout; - unsigned char *buffer; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - switch(cmd) { - case VFC_I2C_SEND: - if(copy_from_user(&inout, argp, sizeof(inout))) - return -EFAULT; - - buffer = kmalloc(inout.len, GFP_KERNEL); - if (buffer == NULL) - return -ENOMEM; - - if(copy_from_user(buffer, inout.buffer, inout.len)) { - kfree(buffer); - return -EFAULT; - } - - - vfc_lock_device(dev); - inout.ret= - vfc_i2c_sendbuf(dev,inout.addr & 0xff, - buffer,inout.len); - - if (copy_to_user(argp,&inout,sizeof(inout))) { - vfc_unlock_device(dev); - kfree(buffer); - return -EFAULT; - } - vfc_unlock_device(dev); - - break; - case VFC_I2C_RECV: - if (copy_from_user(&inout, argp, sizeof(inout))) - return -EFAULT; - - buffer = kzalloc(inout.len, GFP_KERNEL); - if (buffer == NULL) - return -ENOMEM; - - vfc_lock_device(dev); - inout.ret= - vfc_i2c_recvbuf(dev,inout.addr & 0xff - ,buffer,inout.len); - vfc_unlock_device(dev); - - if (copy_to_user(inout.buffer, buffer, inout.len)) { - kfree(buffer); - return -EFAULT; - } - if (copy_to_user(argp,&inout,sizeof(inout))) { - kfree(buffer); - return -EFAULT; - } - kfree(buffer); - break; - default: - return -EINVAL; - }; - - return 0; -} - -static int vfc_capture_start(struct vfc_dev *dev) -{ - vfc_captstat_reset(dev); - dev->control_reg = sbus_readl(&dev->regs->control); - if((dev->control_reg & VFC_STATUS_CAPTURE)) { - printk(KERN_ERR "vfc%d: vfc capture status not reset\n", - dev->instance); - return -EIO; - } - - vfc_lock_device(dev); - dev->control_reg &= ~VFC_CONTROL_CAPTURE; - sbus_writel(dev->control_reg, &dev->regs->control); - dev->control_reg |= VFC_CONTROL_CAPTURE; - sbus_writel(dev->control_reg, &dev->regs->control); - dev->control_reg &= ~VFC_CONTROL_CAPTURE; - sbus_writel(dev->control_reg, &dev->regs->control); - vfc_unlock_device(dev); - - return 0; -} - -static int vfc_capture_poll(struct vfc_dev *dev) -{ - int timeout = 1000; - - while (!timeout--) { - if (sbus_readl(&dev->regs->control) & VFC_STATUS_CAPTURE) - break; - vfc_i2c_delay_no_busy(dev, 100); - } - if(!timeout) { - printk(KERN_WARNING "vfc%d: capture timed out\n", - dev->instance); - return -ETIMEDOUT; - } - return 0; -} - - - -static int vfc_set_control_ioctl(struct inode *inode, struct file *file, - struct vfc_dev *dev, unsigned long arg) -{ - int setcmd, ret = 0; - - if (copy_from_user(&setcmd,(void __user *)arg,sizeof(unsigned int))) - return -EFAULT; - - VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSCTRL) arg=0x%x\n", - dev->instance,setcmd)); - - switch(setcmd) { - case MEMPRST: - vfc_lock_device(dev); - vfc_memptr_reset(dev); - vfc_unlock_device(dev); - ret=0; - break; - case CAPTRCMD: - vfc_capture_start(dev); - vfc_capture_poll(dev); - break; - case DIAGMODE: - if(capable(CAP_SYS_ADMIN)) { - vfc_lock_device(dev); - dev->control_reg |= VFC_CONTROL_DIAGMODE; - sbus_writel(dev->control_reg, &dev->regs->control); - vfc_unlock_device(dev); - ret = 0; - } else { - ret = -EPERM; - } - break; - case NORMMODE: - vfc_lock_device(dev); - dev->control_reg &= ~VFC_CONTROL_DIAGMODE; - sbus_writel(dev->control_reg, &dev->regs->control); - vfc_unlock_device(dev); - ret = 0; - break; - case CAPTRSTR: - vfc_capture_start(dev); - ret = 0; - break; - case CAPTRWAIT: - vfc_capture_poll(dev); - ret = 0; - break; - default: - ret = -EINVAL; - break; - }; - - return ret; -} - - -static int vfc_port_change_ioctl(struct inode *inode, struct file *file, - struct vfc_dev *dev, unsigned long arg) -{ - int ret = 0; - int cmd; - - if(copy_from_user(&cmd, (void __user *)arg, sizeof(unsigned int))) { - VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to " - "vfc_port_change_ioctl\n", - dev->instance)); - return -EFAULT; - } - - VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCPORTCHG) arg=0x%x\n", - dev->instance, cmd)); - - switch(cmd) { - case 1: - case 2: - VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_START) = 0x72; - VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_STOP) = 0x52; - VFC_SAA9051_SA(dev,VFC_SAA9051_HC_START) = 0x36; - VFC_SAA9051_SA(dev,VFC_SAA9051_HC_STOP) = 0x18; - VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) = VFC_SAA9051_BP2; - VFC_SAA9051_SA(dev,VFC_SAA9051_C3) = VFC_SAA9051_CT | VFC_SAA9051_SS3; - VFC_SAA9051_SA(dev,VFC_SAA9051_SECAM_DELAY) = 0x3e; - break; - case 3: - VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_START) = 0x3a; - VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_STOP) = 0x17; - VFC_SAA9051_SA(dev,VFC_SAA9051_HC_START) = 0xfa; - VFC_SAA9051_SA(dev,VFC_SAA9051_HC_STOP) = 0xde; - VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) = - VFC_SAA9051_BY | VFC_SAA9051_PF | VFC_SAA9051_BP2; - VFC_SAA9051_SA(dev,VFC_SAA9051_C3) = VFC_SAA9051_YC; - VFC_SAA9051_SA(dev,VFC_SAA9051_SECAM_DELAY) = 0; - VFC_SAA9051_SA(dev,VFC_SAA9051_C2) &= - ~(VFC_SAA9051_SS0 | VFC_SAA9051_SS1); - break; - default: - ret = -EINVAL; - return ret; - break; - } - - switch(cmd) { - case 1: - VFC_SAA9051_SA(dev,VFC_SAA9051_C2) |= - (VFC_SAA9051_SS0 | VFC_SAA9051_SS1); - break; - case 2: - VFC_SAA9051_SA(dev,VFC_SAA9051_C2) &= - ~(VFC_SAA9051_SS0 | VFC_SAA9051_SS1); - VFC_SAA9051_SA(dev,VFC_SAA9051_C2) |= VFC_SAA9051_SS0; - break; - case 3: - break; - default: - ret = -EINVAL; - return ret; - break; - } - VFC_SAA9051_SA(dev,VFC_SAA9051_C3) &= ~(VFC_SAA9051_SS2); - ret=vfc_update_saa9051(dev); - udelay(500); - VFC_SAA9051_SA(dev,VFC_SAA9051_C3) |= (VFC_SAA9051_SS2); - ret=vfc_update_saa9051(dev); - return ret; -} - -static int vfc_set_video_ioctl(struct inode *inode, struct file *file, - struct vfc_dev *dev, unsigned long arg) -{ - int ret = 0; - int cmd; - - if(copy_from_user(&cmd, (void __user *)arg, sizeof(unsigned int))) { - VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to " - "vfc_set_video_ioctl\n", - dev->instance)); - return ret; - } - - VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSVID) arg=0x%x\n", - dev->instance, cmd)); - switch(cmd) { - case STD_NTSC: - VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~VFC_SAA9051_ALT; - VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_YPN | - VFC_SAA9051_CCFR0 | VFC_SAA9051_CCFR1 | VFC_SAA9051_FS; - ret = vfc_update_saa9051(dev); - break; - case STD_PAL: - VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~(VFC_SAA9051_YPN | - VFC_SAA9051_CCFR1 | - VFC_SAA9051_CCFR0 | - VFC_SAA9051_FS); - VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_ALT; - ret = vfc_update_saa9051(dev); - break; - - case COLOR_ON: - VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_CO; - VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) &= - ~(VFC_SAA9051_BY | VFC_SAA9051_PF); - ret = vfc_update_saa9051(dev); - break; - case MONO: - VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~(VFC_SAA9051_CO); - VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) |= - (VFC_SAA9051_BY | VFC_SAA9051_PF); - ret = vfc_update_saa9051(dev); - break; - default: - ret = -EINVAL; - break; - }; - - return ret; -} - -static int vfc_get_video_ioctl(struct inode *inode, struct file *file, - struct vfc_dev *dev, unsigned long arg) -{ - int ret = 0; - unsigned int status = NO_LOCK; - unsigned char buf[1]; - - if(vfc_i2c_recvbuf(dev, VFC_SAA9051_ADDR, buf, 1)) { - printk(KERN_ERR "vfc%d: Unable to get status\n", - dev->instance); - return -EIO; - } - - if(buf[0] & VFC_SAA9051_HLOCK) { - status = NO_LOCK; - } else if(buf[0] & VFC_SAA9051_FD) { - if(buf[0] & VFC_SAA9051_CD) - status = NTSC_COLOR; - else - status = NTSC_NOCOLOR; - } else { - if(buf[0] & VFC_SAA9051_CD) - status = PAL_COLOR; - else - status = PAL_NOCOLOR; - } - VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGVID) returning status 0x%x; " - "buf[0]=%x\n", dev->instance, status, buf[0])); - - if (copy_to_user((void __user *)arg,&status,sizeof(unsigned int))) { - VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to " - "vfc_get_video_ioctl\n", - dev->instance)); - return ret; - } - return ret; -} - -static int vfc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) -{ - int ret = 0; - unsigned int tmp; - struct vfc_dev *dev; - void __user *argp = (void __user *)arg; - - dev = vfc_get_dev_ptr(iminor(inode)); - if(dev == NULL) - return -ENODEV; - - switch(cmd & 0x0000ffff) { - case VFCGCTRL: -#if 0 - VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGCTRL)\n", dev->instance)); -#endif - tmp = sbus_readl(&dev->regs->control); - if(copy_to_user(argp, &tmp, sizeof(unsigned int))) { - ret = -EFAULT; - break; - } - ret = 0; - break; - case VFCSCTRL: - ret = vfc_set_control_ioctl(inode, file, dev, arg); - break; - case VFCGVID: - ret = vfc_get_video_ioctl(inode, file, dev, arg); - break; - case VFCSVID: - ret = vfc_set_video_ioctl(inode, file, dev, arg); - break; - case VFCHUE: - VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCHUE)\n", dev->instance)); - if(copy_from_user(&tmp,argp,sizeof(unsigned int))) { - VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer " - "to IOCTL(VFCHUE)", dev->instance)); - ret = -EFAULT; - } else { - VFC_SAA9051_SA(dev,VFC_SAA9051_HUE) = tmp; - vfc_update_saa9051(dev); - ret = 0; - } - break; - case VFCPORTCHG: - ret = vfc_port_change_ioctl(inode, file, dev, arg); - break; - case VFCRDINFO: - ret = -EINVAL; - VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCRDINFO)\n", dev->instance)); - break; - default: - ret = vfc_debug(vfc_get_dev_ptr(iminor(inode)), cmd, argp); - break; - }; - - return ret; -} - -static int vfc_mmap(struct file *file, struct vm_area_struct *vma) -{ - unsigned int map_size, ret, map_offset; - struct vfc_dev *dev; - - dev = vfc_get_dev_ptr(iminor(file->f_path.dentry->d_inode)); - if(dev == NULL) - return -ENODEV; - - map_size = vma->vm_end - vma->vm_start; - if(map_size > sizeof(struct vfc_regs)) - map_size = sizeof(struct vfc_regs); - - vma->vm_flags |= - (VM_MAYREAD | VM_MAYWRITE | VM_MAYSHARE); - map_offset = (unsigned int) (long)dev->phys_regs; - ret = io_remap_pfn_range(vma, vma->vm_start, - MK_IOSPACE_PFN(dev->which_io, - map_offset >> PAGE_SHIFT), - map_size, vma->vm_page_prot); - - if(ret) - return -EAGAIN; - - return 0; -} - - -static const struct file_operations vfc_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = vfc_ioctl, - .mmap = vfc_mmap, - .open = vfc_open, - .release = vfc_release, -}; - -static int vfc_probe(void) -{ - struct sbus_bus *sbus; - struct sbus_dev *sdev = NULL; - int ret; - int instance = 0, cards = 0; - - for_all_sbusdev(sdev, sbus) { - if (strcmp(sdev->prom_name, "vfc") == 0) { - cards++; - continue; - } - } - - if (!cards) - return -ENODEV; - - vfc_dev_lst = kcalloc(cards + 1, sizeof(struct vfc_dev*), GFP_KERNEL); - if (vfc_dev_lst == NULL) - return -ENOMEM; - vfc_dev_lst[cards] = NULL; - - ret = register_chrdev(VFC_MAJOR, vfcstr, &vfc_fops); - if(ret) { - printk(KERN_ERR "Unable to get major number %d\n", VFC_MAJOR); - kfree(vfc_dev_lst); - return -EIO; - } - instance = 0; - for_all_sbusdev(sdev, sbus) { - if (strcmp(sdev->prom_name, "vfc") == 0) { - vfc_dev_lst[instance]=(struct vfc_dev *) - kmalloc(sizeof(struct vfc_dev), GFP_KERNEL); - if (vfc_dev_lst[instance] == NULL) - return -ENOMEM; - ret = init_vfc_device(sdev, - vfc_dev_lst[instance], - instance); - if(ret) { - printk(KERN_ERR "Unable to initialize" - " vfc%d device\n", - instance); - } else { - } - - instance++; - continue; - } - } - - return 0; -} - -#ifdef MODULE -int init_module(void) -#else -int vfc_init(void) -#endif -{ - return vfc_probe(); -} - -#ifdef MODULE -static void deinit_vfc_device(struct vfc_dev *dev) -{ - if(dev == NULL) - return; - sbus_iounmap(dev->regs, sizeof(struct vfc_regs)); - kfree(dev); -} - -void cleanup_module(void) -{ - struct vfc_dev **devp; - - unregister_chrdev(VFC_MAJOR,vfcstr); - - for (devp = vfc_dev_lst; *devp; devp++) - deinit_vfc_device(*devp); - - kfree(vfc_dev_lst); - return; -} -#endif - -MODULE_LICENSE("GPL"); - diff --git a/drivers/sbus/char/vfc_i2c.c b/drivers/sbus/char/vfc_i2c.c deleted file mode 100644 index 32b986e0ed7..00000000000 --- a/drivers/sbus/char/vfc_i2c.c +++ /dev/null @@ -1,335 +0,0 @@ -/* - * drivers/sbus/char/vfc_i2c.c - * - * Driver for the Videopix Frame Grabber. - * - * Functions that support the Phillips i2c(I squared C) bus on the vfc - * Documentation for the Phillips I2C bus can be found on the - * phillips home page - * - * Copyright (C) 1996 Manish Vachharajani (mvachhar@noc.rutgers.edu) - * - */ - -/* NOTE: It seems to me that the documentation regarding the -pcd8584t/pcf8584 does not show the correct way to address the i2c bus. -Based on the information on the I2C bus itself and the remainder of -the Phillips docs the following algorithms appear to be correct. I am -fairly certain that the flowcharts in the phillips docs are wrong. */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if 0 -#define VFC_I2C_DEBUG -#endif - -#include "vfc.h" -#include "vfc_i2c.h" - -#define WRITE_S1(__val) \ - sbus_writel(__val, &dev->regs->i2c_s1) -#define WRITE_REG(__val) \ - sbus_writel(__val, &dev->regs->i2c_reg) - -#define VFC_I2C_READ (0x1) -#define VFC_I2C_WRITE (0x0) - -/****** - The i2c bus controller chip on the VFC is a pcd8584t, but - phillips claims it doesn't exist. As far as I can tell it is - identical to the PCF8584 so I treat it like it is the pcf8584. - - NOTE: The pcf8584 only cares - about the msb of the word you feed it -*****/ - -int vfc_pcf8584_init(struct vfc_dev *dev) -{ - /* This will also choose register S0_OWN so we can set it. */ - WRITE_S1(RESET); - - /* The pcf8584 shifts this value left one bit and uses - * it as its i2c bus address. - */ - WRITE_REG(0x55000000); - - /* This will set the i2c bus at the same speed sun uses, - * and set another magic bit. - */ - WRITE_S1(SELECT(S2)); - WRITE_REG(0x14000000); - - /* Enable the serial port, idle the i2c bus and set - * the data reg to s0. - */ - WRITE_S1(CLEAR_I2C_BUS); - udelay(100); - return 0; -} - -void vfc_i2c_delay_no_busy(struct vfc_dev *dev, unsigned long usecs) -{ - schedule_timeout_uninterruptible(usecs_to_jiffies(usecs)); -} - -void inline vfc_i2c_delay(struct vfc_dev *dev) -{ - vfc_i2c_delay_no_busy(dev, 100); -} - -int vfc_init_i2c_bus(struct vfc_dev *dev) -{ - WRITE_S1(ENABLE_SERIAL | SELECT(S0) | ACK); - vfc_i2c_reset_bus(dev); - return 0; -} - -int vfc_i2c_reset_bus(struct vfc_dev *dev) -{ - VFC_I2C_DEBUG_PRINTK((KERN_DEBUG "vfc%d: Resetting the i2c bus\n", - dev->instance)); - if(dev == NULL) - return -EINVAL; - if(dev->regs == NULL) - return -EINVAL; - WRITE_S1(SEND_I2C_STOP); - WRITE_S1(SEND_I2C_STOP | ACK); - vfc_i2c_delay(dev); - WRITE_S1(CLEAR_I2C_BUS); - VFC_I2C_DEBUG_PRINTK((KERN_DEBUG "vfc%d: I2C status %x\n", - dev->instance, - sbus_readl(&dev->regs->i2c_s1))); - return 0; -} - -static int vfc_i2c_wait_for_bus(struct vfc_dev *dev) -{ - int timeout = 1000; - - while(!(sbus_readl(&dev->regs->i2c_s1) & BB)) { - if(!(timeout--)) - return -ETIMEDOUT; - vfc_i2c_delay(dev); - } - return 0; -} - -static int vfc_i2c_wait_for_pin(struct vfc_dev *dev, int ack) -{ - int timeout = 1000; - int s1; - - while ((s1 = sbus_readl(&dev->regs->i2c_s1)) & PIN) { - if (!(timeout--)) - return -ETIMEDOUT; - vfc_i2c_delay(dev); - } - if (ack == VFC_I2C_ACK_CHECK) { - if(s1 & LRB) - return -EIO; - } - return 0; -} - -#define SHIFT(a) ((a) << 24) -static int vfc_i2c_xmit_addr(struct vfc_dev *dev, unsigned char addr, - char mode) -{ - int ret, raddr; -#if 1 - WRITE_S1(SEND_I2C_STOP | ACK); - WRITE_S1(SELECT(S0) | ENABLE_SERIAL); - vfc_i2c_delay(dev); -#endif - - switch(mode) { - case VFC_I2C_READ: - raddr = SHIFT(((unsigned int)addr | 0x1)); - WRITE_REG(raddr); - VFC_I2C_DEBUG_PRINTK(("vfc%d: receiving from i2c addr 0x%x\n", - dev->instance, addr | 0x1)); - break; - case VFC_I2C_WRITE: - raddr = SHIFT((unsigned int)addr & ~0x1); - WRITE_REG(raddr); - VFC_I2C_DEBUG_PRINTK(("vfc%d: sending to i2c addr 0x%x\n", - dev->instance, addr & ~0x1)); - break; - default: - return -EINVAL; - }; - - WRITE_S1(SEND_I2C_START); - vfc_i2c_delay(dev); - ret = vfc_i2c_wait_for_pin(dev,VFC_I2C_ACK_CHECK); /* We wait - for the - i2c send - to finish - here but - Sun - doesn't, - hmm */ - if (ret) { - printk(KERN_ERR "vfc%d: VFC xmit addr timed out or no ack\n", - dev->instance); - return ret; - } else if (mode == VFC_I2C_READ) { - if ((ret = sbus_readl(&dev->regs->i2c_reg) & 0xff000000) != raddr) { - printk(KERN_WARNING - "vfc%d: returned slave address " - "mismatch(%x,%x)\n", - dev->instance, raddr, ret); - } - } - return 0; -} - -static int vfc_i2c_xmit_byte(struct vfc_dev *dev,unsigned char *byte) -{ - int ret; - u32 val = SHIFT((unsigned int)*byte); - - WRITE_REG(val); - - ret = vfc_i2c_wait_for_pin(dev, VFC_I2C_ACK_CHECK); - switch(ret) { - case -ETIMEDOUT: - printk(KERN_ERR "vfc%d: VFC xmit byte timed out or no ack\n", - dev->instance); - break; - case -EIO: - ret = XMIT_LAST_BYTE; - break; - default: - break; - }; - - return ret; -} - -static int vfc_i2c_recv_byte(struct vfc_dev *dev, unsigned char *byte, - int last) -{ - int ret; - - if (last) { - WRITE_REG(NEGATIVE_ACK); - VFC_I2C_DEBUG_PRINTK(("vfc%d: sending negative ack\n", - dev->instance)); - } else { - WRITE_S1(ACK); - } - - ret = vfc_i2c_wait_for_pin(dev, VFC_I2C_NO_ACK_CHECK); - if(ret) { - printk(KERN_ERR "vfc%d: " - "VFC recv byte timed out\n", - dev->instance); - } - *byte = (sbus_readl(&dev->regs->i2c_reg)) >> 24; - return ret; -} - -int vfc_i2c_recvbuf(struct vfc_dev *dev, unsigned char addr, - char *buf, int count) -{ - int ret, last; - - if(!(count && buf && dev && dev->regs) ) - return -EINVAL; - - if ((ret = vfc_i2c_wait_for_bus(dev))) { - printk(KERN_ERR "vfc%d: VFC I2C bus busy\n", dev->instance); - return ret; - } - - if ((ret = vfc_i2c_xmit_addr(dev, addr, VFC_I2C_READ))) { - WRITE_S1(SEND_I2C_STOP); - vfc_i2c_delay(dev); - return ret; - } - - last = 0; - while (count--) { - if (!count) - last = 1; - if ((ret = vfc_i2c_recv_byte(dev, buf, last))) { - printk(KERN_ERR "vfc%d: " - "VFC error while receiving byte\n", - dev->instance); - WRITE_S1(SEND_I2C_STOP); - ret = -EINVAL; - } - buf++; - } - WRITE_S1(SEND_I2C_STOP | ACK); - vfc_i2c_delay(dev); - return ret; -} - -int vfc_i2c_sendbuf(struct vfc_dev *dev, unsigned char addr, - char *buf, int count) -{ - int ret; - - if (!(buf && dev && dev->regs)) - return -EINVAL; - - if ((ret = vfc_i2c_wait_for_bus(dev))) { - printk(KERN_ERR "vfc%d: VFC I2C bus busy\n", dev->instance); - return ret; - } - - if ((ret = vfc_i2c_xmit_addr(dev, addr, VFC_I2C_WRITE))) { - WRITE_S1(SEND_I2C_STOP); - vfc_i2c_delay(dev); - return ret; - } - - while(count--) { - ret = vfc_i2c_xmit_byte(dev, buf); - switch(ret) { - case XMIT_LAST_BYTE: - VFC_I2C_DEBUG_PRINTK(("vfc%d: " - "Receiver ended transmission with " - " %d bytes remaining\n", - dev->instance, count)); - ret = 0; - goto done; - break; - case 0: - break; - default: - printk(KERN_ERR "vfc%d: " - "VFC error while sending byte\n", dev->instance); - break; - }; - - buf++; - } -done: - WRITE_S1(SEND_I2C_STOP | ACK); - vfc_i2c_delay(dev); - return ret; -} - - - - - - - - - diff --git a/drivers/sbus/char/vfc_i2c.h b/drivers/sbus/char/vfc_i2c.h deleted file mode 100644 index a2e6973209d..00000000000 --- a/drivers/sbus/char/vfc_i2c.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef _LINUX_VFC_I2C_H_ -#define _LINUX_VFC_I2C_H_ - -/* control bits */ -#define PIN (0x80000000) -#define ESO (0x40000000) -#define ES1 (0x20000000) -#define ES2 (0x10000000) -#define ENI (0x08000000) -#define STA (0x04000000) -#define STO (0x02000000) -#define ACK (0x01000000) - -/* status bits */ -#define STS (0x20000000) -#define BER (0x10000000) -#define LRB (0x08000000) -#define AAS (0x04000000) -#define LAB (0x02000000) -#define BB (0x01000000) - -#define SEND_I2C_START (PIN | ESO | STA) -#define SEND_I2C_STOP (PIN | ESO | STO) -#define CLEAR_I2C_BUS (PIN | ESO | ACK) -#define NEGATIVE_ACK ((ESO) & ~ACK) - -#define SELECT(a) (a) -#define S0 (PIN | ESO | ES1) -#define S0_OWN (PIN) -#define S2 (PIN | ES1) -#define S3 (PIN | ES2) - -#define ENABLE_SERIAL (PIN | ESO) -#define DISABLE_SERIAL (PIN) -#define RESET (PIN) - -#define XMIT_LAST_BYTE (1) -#define VFC_I2C_ACK_CHECK (1) -#define VFC_I2C_NO_ACK_CHECK (0) - -#endif /* _LINUX_VFC_I2C_H_ */ - - - -- cgit v1.2.3 From 334ae614772b1147435dce9be3911f9040dff0d9 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 27 Aug 2008 17:01:57 -0700 Subject: sparc: Kill SBUS DVMA layer. This thing was completely pointless. Just find the OF device in the parent of drivers that want to program this device, and map the DMA regs inside such drivers too. This also moves the dummy claim_dma_lock() and release_dma_lock() implementation to floppy_32.h, which makes it handle this issue just like floppy_64.h does. Signed-off-by: David S. Miller --- drivers/sbus/Makefile | 2 +- drivers/sbus/dvma.c | 136 -------------------------------------------------- drivers/sbus/sbus.c | 2 - 3 files changed, 1 insertion(+), 139 deletions(-) delete mode 100644 drivers/sbus/dvma.c (limited to 'drivers/sbus') diff --git a/drivers/sbus/Makefile b/drivers/sbus/Makefile index 7b1d24d9530..56f73318eba 100644 --- a/drivers/sbus/Makefile +++ b/drivers/sbus/Makefile @@ -3,7 +3,7 @@ # ifneq ($(ARCH),m68k) -obj-y := sbus.o dvma.o +obj-y := sbus.o endif obj-$(CONFIG_SBUSCHAR) += char/ diff --git a/drivers/sbus/dvma.c b/drivers/sbus/dvma.c deleted file mode 100644 index ab0d2de3324..00000000000 --- a/drivers/sbus/dvma.c +++ /dev/null @@ -1,136 +0,0 @@ -/* dvma.c: Routines that are used to access DMA on the Sparc SBus. - * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -struct sbus_dma *dma_chain; - -static void __init init_one_dvma(struct sbus_dma *dma, int num_dma) -{ - printk("dma%d: ", num_dma); - - dma->next = NULL; - dma->running = 0; /* No transfers going on as of yet */ - dma->allocated = 0; /* No one has allocated us yet */ - switch(sbus_readl(dma->regs + DMA_CSR)&DMA_DEVICE_ID) { - case DMA_VERS0: - dma->revision = dvmarev0; - printk("Revision 0 "); - break; - case DMA_ESCV1: - dma->revision = dvmaesc1; - printk("ESC Revision 1 "); - break; - case DMA_VERS1: - dma->revision = dvmarev1; - printk("Revision 1 "); - break; - case DMA_VERS2: - dma->revision = dvmarev2; - printk("Revision 2 "); - break; - case DMA_VERHME: - dma->revision = dvmahme; - printk("HME DVMA gate array "); - break; - case DMA_VERSPLUS: - dma->revision = dvmarevplus; - printk("Revision 1 PLUS "); - break; - default: - printk("unknown dma version %08x", - sbus_readl(dma->regs + DMA_CSR) & DMA_DEVICE_ID); - dma->allocated = 1; - break; - } - printk("\n"); -} - -/* Probe this SBus DMA module(s) */ -void __init dvma_init(struct sbus_bus *sbus) -{ - struct sbus_dev *this_dev; - struct sbus_dma *dma; - struct sbus_dma *dchain; - static int num_dma = 0; - - for_each_sbusdev(this_dev, sbus) { - char *name = this_dev->prom_name; - int hme = 0; - - if(!strcmp(name, "SUNW,fas")) - hme = 1; - else if(strcmp(name, "dma") && - strcmp(name, "ledma") && - strcmp(name, "espdma")) - continue; - - /* Found one... */ - dma = kmalloc(sizeof(struct sbus_dma), GFP_ATOMIC); - - dma->sdev = this_dev; - - /* Put at end of dma chain */ - dchain = dma_chain; - if(dchain) { - while(dchain->next) - dchain = dchain->next; - dchain->next = dma; - } else { - /* We're the first in line */ - dma_chain = dma; - } - - dma->regs = sbus_ioremap(&dma->sdev->resource[0], 0, - dma->sdev->resource[0].end - dma->sdev->resource[0].start + 1, - "dma"); - - dma->node = dma->sdev->prom_node; - - init_one_dvma(dma, num_dma++); - } -} - -#ifdef CONFIG_SUN4 - -#include - -void __init sun4_dvma_init(void) -{ - struct sbus_dma *dma; - struct resource r; - - if(sun4_dma_physaddr) { - dma = kmalloc(sizeof(struct sbus_dma), GFP_ATOMIC); - - /* No SBUS */ - dma->sdev = NULL; - - /* Only one DMA device */ - dma_chain = dma; - - memset(&r, 0, sizeof(r)); - r.start = sun4_dma_physaddr; - dma->regs = sbus_ioremap(&r, 0, PAGE_SIZE, "dma"); - - /* No prom node */ - dma->node = 0x0; - - init_one_dvma(dma, 0); - } else { - dma_chain = NULL; - } -} - -#endif diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c index 53e5e7bf545..69491625d86 100644 --- a/drivers/sbus/sbus.c +++ b/drivers/sbus/sbus.c @@ -285,8 +285,6 @@ static void __init build_one_sbus(struct device_node *dp, int num_sbus) } sbus_fixup_all_regs(sbus->devices); - - dvma_init(sbus); } static int __init sbus_init(void) -- cgit v1.2.3 From 5778002874de0fb7e3d8c4a0a4afb6b1a6297069 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 25 Aug 2008 22:52:37 -0700 Subject: sparc: Propagate SBUS iommu archdata into real of_device objects. Signed-off-by: David S. Miller --- drivers/sbus/sbus.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'drivers/sbus') diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c index 69491625d86..db0766e5c7d 100644 --- a/drivers/sbus/sbus.c +++ b/drivers/sbus/sbus.c @@ -30,6 +30,24 @@ static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_sbusobppath_attr, struct sbus_bus *sbus_root; +static void __init fill_sbus_device_iommu(struct sbus_dev *sdev) +{ + struct of_device *op = of_find_device_by_node(sdev->ofdev.node); + struct dev_archdata *sd, *bus_sd; + struct sbus_bus *sbus; + + sbus = sdev->bus; + bus_sd = &sbus->ofdev.dev.archdata; + + sd = &sdev->ofdev.dev.archdata; + sd->iommu = bus_sd->iommu; + sd->stc = bus_sd->stc; + + sd = &op->dev.archdata; + sd->iommu = bus_sd->iommu; + sd->stc = bus_sd->stc; +} + static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev) { struct dev_archdata *sd; @@ -85,6 +103,8 @@ static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sde /* WE HAVE BEEN INVADED BY ALIENS! */ err = sysfs_create_file(&sdev->ofdev.dev.kobj, &dev_attr_obppath.attr); + + fill_sbus_device_iommu(sdev); } static void __init sbus_bus_ranges_init(struct device_node *dp, struct sbus_bus *sbus) @@ -209,10 +229,6 @@ static void __init walk_children(struct device_node *dp, struct sbus_dev *parent sdev->bus = sbus; sdev->parent = parent; - sdev->ofdev.dev.archdata.iommu = - sbus->ofdev.dev.archdata.iommu; - sdev->ofdev.dev.archdata.stc = - sbus->ofdev.dev.archdata.stc; fill_sbus_device(dp, sdev); -- cgit v1.2.3 From a9540d34229c0ec1fceb9a9d1e41ea45d016044d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 27 Aug 2008 01:13:12 -0700 Subject: sparc: Convert flash driver to OF device probing. Signed-off-by: David S. Miller --- drivers/sbus/char/flash.c | 130 ++++++++++++++++++---------------------------- 1 file changed, 50 insertions(+), 80 deletions(-) (limited to 'drivers/sbus') diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c index 7d95e151513..715996f5c53 100644 --- a/drivers/sbus/char/flash.c +++ b/drivers/sbus/char/flash.c @@ -1,5 +1,4 @@ -/* $Id: flash.c,v 1.25 2001/12/21 04:56:16 davem Exp $ - * flash.c: Allow mmap access to the OBP Flash, for OBP updates. +/* flash.c: Allow mmap access to the OBP Flash, for OBP updates. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) */ @@ -15,13 +14,13 @@ #include #include #include +#include +#include #include #include #include #include -#include -#include #include static DEFINE_SPINLOCK(flash_lock); @@ -161,97 +160,68 @@ static const struct file_operations flash_fops = { static struct miscdevice flash_dev = { FLASH_MINOR, "flash", &flash_fops }; -static int __init flash_init(void) +static int __devinit flash_probe(struct of_device *op, + const struct of_device_id *match) { - struct sbus_bus *sbus; - struct sbus_dev *sdev = NULL; -#ifdef CONFIG_PCI - struct linux_ebus *ebus; - struct linux_ebus_device *edev = NULL; - struct linux_prom_registers regs[2]; - int len, nregs; -#endif - int err; - - for_all_sbusdev(sdev, sbus) { - if (!strcmp(sdev->prom_name, "flashprom")) { - if (sdev->reg_addrs[0].phys_addr == sdev->reg_addrs[1].phys_addr) { - flash.read_base = ((unsigned long)sdev->reg_addrs[0].phys_addr) | - (((unsigned long)sdev->reg_addrs[0].which_io)<<32UL); - flash.read_size = sdev->reg_addrs[0].reg_size; - flash.write_base = flash.read_base; - flash.write_size = flash.read_size; - } else { - flash.read_base = ((unsigned long)sdev->reg_addrs[0].phys_addr) | - (((unsigned long)sdev->reg_addrs[0].which_io)<<32UL); - flash.read_size = sdev->reg_addrs[0].reg_size; - flash.write_base = ((unsigned long)sdev->reg_addrs[1].phys_addr) | - (((unsigned long)sdev->reg_addrs[1].which_io)<<32UL); - flash.write_size = sdev->reg_addrs[1].reg_size; - } - flash.busy = 0; - break; - } - } - if (!sdev) { -#ifdef CONFIG_PCI - const struct linux_prom_registers *ebus_regs; - - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_node->name, "flashprom")) - goto ebus_done; - } - } - ebus_done: - if (!edev) - return -ENODEV; - - ebus_regs = of_get_property(edev->prom_node, "reg", &len); - if (!ebus_regs || (len % sizeof(regs[0])) != 0) { - printk("flash: Strange reg property size %d\n", len); - return -ENODEV; - } - - nregs = len / sizeof(ebus_regs[0]); + struct device_node *dp = op->node; + struct device_node *parent; - flash.read_base = edev->resource[0].start; - flash.read_size = ebus_regs[0].reg_size; + parent = dp->parent; - if (nregs == 1) { - flash.write_base = edev->resource[0].start; - flash.write_size = ebus_regs[0].reg_size; - } else if (nregs == 2) { - flash.write_base = edev->resource[1].start; - flash.write_size = ebus_regs[1].reg_size; - } else { - printk("flash: Strange number of regs %d\n", nregs); - return -ENODEV; - } - - flash.busy = 0; - -#else + if (strcmp(parent->name, "sbus") && + strcmp(parent->name, "sbi") && + strcmp(parent->name, "ebus")) return -ENODEV; -#endif + + flash.read_base = op->resource[0].start; + flash.read_size = resource_size(&op->resource[0]); + if (op->resource[1].flags) { + flash.write_base = op->resource[1].start; + flash.write_size = resource_size(&op->resource[1]); + } else { + flash.write_base = op->resource[0].start; + flash.write_size = resource_size(&op->resource[0]); } + flash.busy = 0; - printk("OBP Flash: RD %lx[%lx] WR %lx[%lx]\n", + printk(KERN_INFO "%s: OBP Flash, RD %lx[%lx] WR %lx[%lx]\n", + op->node->full_name, flash.read_base, flash.read_size, flash.write_base, flash.write_size); - err = misc_register(&flash_dev); - if (err) { - printk(KERN_ERR "flash: unable to get misc minor\n"); - return err; - } + return misc_register(&flash_dev); +} + +static int __devexit flash_remove(struct of_device *op) +{ + misc_deregister(&flash_dev); return 0; } +static struct of_device_id flash_match[] = { + { + .name = "flashprom", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, flash_match); + +static struct of_platform_driver flash_driver = { + .name = "flash", + .match_table = flash_match, + .probe = flash_probe, + .remove = __devexit_p(flash_remove), +}; + +static int __init flash_init(void) +{ + return of_register_driver(&flash_driver, &of_bus_type); +} + static void __exit flash_cleanup(void) { - misc_deregister(&flash_dev); + of_unregister_driver(&flash_driver); } module_init(flash_init); -- cgit v1.2.3 From 237f8aafa348d56e6ad24c49ebd23bd927fedb31 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 27 Aug 2008 18:39:47 -0700 Subject: sparc: Convert uctrl driver to OF driver. Signed-off-by: David S. Miller --- drivers/sbus/char/Kconfig | 2 +- drivers/sbus/char/uctrl.c | 216 +++++++++++++++++++++++++--------------------- 2 files changed, 121 insertions(+), 97 deletions(-) (limited to 'drivers/sbus') diff --git a/drivers/sbus/char/Kconfig b/drivers/sbus/char/Kconfig index 3fd2bc95b51..1d5d1b4580c 100644 --- a/drivers/sbus/char/Kconfig +++ b/drivers/sbus/char/Kconfig @@ -32,7 +32,7 @@ config OBP_FLASH config TADPOLE_TS102_UCTRL tristate "Tadpole TS102 Microcontroller support (EXPERIMENTAL)" - depends on EXPERIMENTAL && SPARC32 + depends on EXPERIMENTAL help Say Y here to directly support the TS102 Microcontroller interface on the Tadpole Sparcbook 3. This device handles power-management diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c index 777637594ac..6cff9777bbc 100644 --- a/drivers/sbus/char/uctrl.c +++ b/drivers/sbus/char/uctrl.c @@ -1,7 +1,7 @@ -/* $Id: uctrl.c,v 1.12 2001/10/08 22:19:51 davem Exp $ - * uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3 +/* uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3 * * Copyright 1999 Derrick J Brashear (shadow@dementia.org) + * Copyright 2008 David S. Miller (davem@davemloft.net) */ #include @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include @@ -21,7 +23,6 @@ #include #include #include -#include #define UCTRL_MINOR 174 @@ -33,26 +34,26 @@ #endif struct uctrl_regs { - volatile u32 uctrl_intr; - volatile u32 uctrl_data; - volatile u32 uctrl_stat; - volatile u32 uctrl_xxx[5]; + u32 uctrl_intr; + u32 uctrl_data; + u32 uctrl_stat; + u32 uctrl_xxx[5]; }; struct ts102_regs { - volatile u32 card_a_intr; - volatile u32 card_a_stat; - volatile u32 card_a_ctrl; - volatile u32 card_a_xxx; - volatile u32 card_b_intr; - volatile u32 card_b_stat; - volatile u32 card_b_ctrl; - volatile u32 card_b_xxx; - volatile u32 uctrl_intr; - volatile u32 uctrl_data; - volatile u32 uctrl_stat; - volatile u32 uctrl_xxx; - volatile u32 ts102_xxx[4]; + u32 card_a_intr; + u32 card_a_stat; + u32 card_a_ctrl; + u32 card_a_xxx; + u32 card_b_intr; + u32 card_b_stat; + u32 card_b_ctrl; + u32 card_b_xxx; + u32 uctrl_intr; + u32 uctrl_data; + u32 uctrl_stat; + u32 uctrl_xxx; + u32 ts102_xxx[4]; }; /* Bits for uctrl_intr register */ @@ -186,17 +187,15 @@ enum uctrl_opcode { POWER_RESTART=0x83, }; -struct uctrl_driver { - struct uctrl_regs *regs; +static struct uctrl_driver { + struct uctrl_regs __iomem *regs; int irq; int pending; struct uctrl_status status; -}; - -static struct uctrl_driver drv; +} *global_driver; -static void uctrl_get_event_status(void); -static void uctrl_get_external_status(void); +static void uctrl_get_event_status(struct uctrl_driver *); +static void uctrl_get_external_status(struct uctrl_driver *); static int uctrl_ioctl(struct inode *inode, struct file *file, @@ -213,16 +212,14 @@ static int uctrl_open(struct inode *inode, struct file *file) { lock_kernel(); - uctrl_get_event_status(); - uctrl_get_external_status(); + uctrl_get_event_status(global_driver); + uctrl_get_external_status(global_driver); unlock_kernel(); return 0; } static irqreturn_t uctrl_interrupt(int irq, void *dev_id) { - struct uctrl_driver *driver = (struct uctrl_driver *)dev_id; - printk("in uctrl_interrupt\n"); return IRQ_HANDLED; } @@ -244,11 +241,11 @@ static struct miscdevice uctrl_dev = { { \ unsigned int i; \ for (i = 0; i < 10000; i++) { \ - if (UCTRL_STAT_TXNF_STA & driver->regs->uctrl_stat) \ + if (UCTRL_STAT_TXNF_STA & sbus_readl(&driver->regs->uctrl_stat)) \ break; \ } \ dprintk(("write data 0x%02x\n", value)); \ - driver->regs->uctrl_data = value; \ + sbus_writel(value, &driver->regs->uctrl_data); \ } /* Wait for something to read, read it, then clear the bit */ @@ -257,24 +254,23 @@ static struct miscdevice uctrl_dev = { unsigned int i; \ value = 0; \ for (i = 0; i < 10000; i++) { \ - if ((UCTRL_STAT_RXNE_STA & driver->regs->uctrl_stat) == 0) \ + if ((UCTRL_STAT_RXNE_STA & sbus_readl(&driver->regs->uctrl_stat)) == 0) \ break; \ udelay(1); \ } \ - value = driver->regs->uctrl_data; \ + value = sbus_readl(&driver->regs->uctrl_data); \ dprintk(("read data 0x%02x\n", value)); \ - driver->regs->uctrl_stat = UCTRL_STAT_RXNE_STA; \ + sbus_writel(UCTRL_STAT_RXNE_STA, &driver->regs->uctrl_stat); \ } -static void uctrl_do_txn(struct uctrl_txn *txn) +static void uctrl_do_txn(struct uctrl_driver *driver, struct uctrl_txn *txn) { - struct uctrl_driver *driver = &drv; int stat, incnt, outcnt, bytecnt, intr; u32 byte; - stat = driver->regs->uctrl_stat; - intr = driver->regs->uctrl_intr; - driver->regs->uctrl_stat = stat; + stat = sbus_readl(&driver->regs->uctrl_stat); + intr = sbus_readl(&driver->regs->uctrl_intr); + sbus_writel(stat, &driver->regs->uctrl_stat); dprintk(("interrupt stat 0x%x int 0x%x\n", stat, intr)); @@ -305,9 +301,8 @@ static void uctrl_do_txn(struct uctrl_txn *txn) } } -static void uctrl_get_event_status(void) +static void uctrl_get_event_status(struct uctrl_driver *driver) { - struct uctrl_driver *driver = &drv; struct uctrl_txn txn; u8 outbits[2]; @@ -317,7 +312,7 @@ static void uctrl_get_event_status(void) txn.inbuf = NULL; txn.outbuf = outbits; - uctrl_do_txn(&txn); + uctrl_do_txn(driver, &txn); dprintk(("bytes %x %x\n", (outbits[0] & 0xff), (outbits[1] & 0xff))); driver->status.event_status = @@ -325,9 +320,8 @@ static void uctrl_get_event_status(void) dprintk(("ev is %x\n", driver->status.event_status)); } -static void uctrl_get_external_status(void) +static void uctrl_get_external_status(struct uctrl_driver *driver) { - struct uctrl_driver *driver = &drv; struct uctrl_txn txn; u8 outbits[2]; int i, v; @@ -338,7 +332,7 @@ static void uctrl_get_external_status(void) txn.inbuf = NULL; txn.outbuf = outbits; - uctrl_do_txn(&txn); + uctrl_do_txn(driver, &txn); dprintk(("bytes %x %x\n", (outbits[0] & 0xff), (outbits[1] & 0xff))); driver->status.external_status = @@ -354,71 +348,101 @@ static void uctrl_get_external_status(void) } -static int __init ts102_uctrl_init(void) +static int __devinit uctrl_probe(struct of_device *op, + const struct of_device_id *match) { - struct uctrl_driver *driver = &drv; - int len; - struct linux_prom_irqs tmp_irq[2]; - unsigned int vaddr[2] = { 0, 0 }; - int tmpnode, uctrlnode = prom_getchild(prom_root_node); - int err; + struct uctrl_driver *p; + int err = -ENOMEM; - tmpnode = prom_searchsiblings(uctrlnode, "obio"); + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) { + printk(KERN_ERR "uctrl: Unable to allocate device struct.\n"); + goto out; + } - if (tmpnode) - uctrlnode = prom_getchild(tmpnode); + p->regs = of_ioremap(&op->resource[0], 0, + resource_size(&op->resource[0]), + "uctrl"); + if (!p->regs) { + printk(KERN_ERR "uctrl: Unable to map registers.\n"); + goto out_free; + } - uctrlnode = prom_searchsiblings(uctrlnode, "uctrl"); + p->irq = op->irqs[0]; + err = request_irq(p->irq, uctrl_interrupt, 0, "uctrl", p); + if (err) { + printk(KERN_ERR "uctrl: Unable to register irq.\n"); + goto out_iounmap; + } - if (!uctrlnode) - return -ENODEV; + err = misc_register(&uctrl_dev); + if (err) { + printk(KERN_ERR "uctrl: Unable to register misc device.\n"); + goto out_free_irq; + } - /* the prom mapped it for us */ - len = prom_getproperty(uctrlnode, "address", (void *) vaddr, - sizeof(vaddr)); - driver->regs = (struct uctrl_regs *)vaddr[0]; + sbus_writel(UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK, &p->regs->uctrl_intr); + printk(KERN_INFO "%s: uctrl regs[0x%p] (irq %d)\n", + op->node->full_name, p->regs, p->irq); + uctrl_get_event_status(p); + uctrl_get_external_status(p); - len = prom_getproperty(uctrlnode, "intr", (char *) tmp_irq, - sizeof(tmp_irq)); + dev_set_drvdata(&op->dev, p); + global_driver = p; - /* Flush device */ - READUCTLDATA(len); +out: + return err; - if(!driver->irq) - driver->irq = tmp_irq[0].pri; +out_free_irq: + free_irq(p->irq, p); - err = request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver); - if (err) { - printk("%s: unable to register irq %d\n", - __func__, driver->irq); - return err; - } +out_iounmap: + of_iounmap(&op->resource[0], p->regs, resource_size(&op->resource[0])); - if (misc_register(&uctrl_dev)) { - printk("%s: unable to get misc minor %d\n", - __func__, uctrl_dev.minor); - free_irq(driver->irq, driver); - return -ENODEV; - } +out_free: + kfree(p); + goto out; +} - driver->regs->uctrl_intr = UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK; - printk("uctrl: 0x%p (irq %d)\n", driver->regs, driver->irq); - uctrl_get_event_status(); - uctrl_get_external_status(); - return 0; +static int __devexit uctrl_remove(struct of_device *op) +{ + struct uctrl_driver *p = dev_get_drvdata(&op->dev); + + if (p) { + misc_deregister(&uctrl_dev); + free_irq(p->irq, p); + of_iounmap(&op->resource[0], p->regs, resource_size(&op->resource[0])); + kfree(p); + } + return 0; } -static void __exit ts102_uctrl_cleanup(void) +static struct of_device_id uctrl_match[] = { + { + .name = "uctrl", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, uctrl_match); + +static struct of_platform_driver uctrl_driver = { + .name = "uctrl", + .match_table = uctrl_match, + .probe = uctrl_probe, + .remove = __devexit_p(uctrl_remove), +}; + + +static int __init uctrl_init(void) { - struct uctrl_driver *driver = &drv; + return of_register_driver(&uctrl_driver, &of_bus_type); +} - misc_deregister(&uctrl_dev); - if (driver->irq) - free_irq(driver->irq, driver); - if (driver->regs) - driver->regs = NULL; +static void __exit uctrl_exit(void) +{ + of_unregister_driver(&uctrl_driver); } -module_init(ts102_uctrl_init); -module_exit(ts102_uctrl_cleanup); +module_init(uctrl_init); +module_exit(uctrl_exit); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 33c4655c00e6af3ec4023f2cafd63dd4a42de49b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 27 Aug 2008 02:56:39 -0700 Subject: sparc: Kill SBUS layer IRQ hooks. IRQs are obtained by drivers from the of_device struct. Signed-off-by: David S. Miller --- drivers/sbus/sbus.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/sbus') diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c index db0766e5c7d..08f4667188d 100644 --- a/drivers/sbus/sbus.c +++ b/drivers/sbus/sbus.c @@ -83,8 +83,6 @@ static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sde len / sizeof(struct linux_prom_ranges); } - sbus_fill_device_irq(sdev); - sd = &sdev->ofdev.dev.archdata; sd->prom_node = dp; sd->op = &sdev->ofdev; @@ -265,8 +263,6 @@ static void __init build_one_sbus(struct device_node *dp, int num_sbus) strcpy(sbus->prom_name, dp->name); - sbus_setup_arch_props(sbus, dp); - sbus_bus_ranges_init(dp, sbus); sbus->ofdev.node = dp; -- cgit v1.2.3 From 104364810ff5b0844a2183fbca989f70e86d486b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 27 Aug 2008 03:38:42 -0700 Subject: sparc: Remove SBUS layer resource and irq handling. All the drivers use OF device objects now for this information. Signed-off-by: David S. Miller --- drivers/sbus/sbus.c | 124 +--------------------------------------------------- 1 file changed, 1 insertion(+), 123 deletions(-) (limited to 'drivers/sbus') diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c index 08f4667188d..89eb922a6ac 100644 --- a/drivers/sbus/sbus.c +++ b/drivers/sbus/sbus.c @@ -51,38 +51,11 @@ static void __init fill_sbus_device_iommu(struct sbus_dev *sdev) static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev) { struct dev_archdata *sd; - unsigned long base; - const void *pval; - int len, err; + int err; sdev->prom_node = dp->node; strcpy(sdev->prom_name, dp->name); - pval = of_get_property(dp, "reg", &len); - sdev->num_registers = 0; - if (pval) { - memcpy(sdev->reg_addrs, pval, len); - - sdev->num_registers = - len / sizeof(struct linux_prom_registers); - - base = (unsigned long) sdev->reg_addrs[0].phys_addr; - - /* Compute the slot number. */ - if (base >= SUN_SBUS_BVADDR && sparc_cpu_model == sun4m) - sdev->slot = sbus_dev_slot(base); - else - sdev->slot = sdev->reg_addrs[0].which_io; - } - - pval = of_get_property(dp, "ranges", &len); - sdev->num_device_ranges = 0; - if (pval) { - memcpy(sdev->device_ranges, pval, len); - sdev->num_device_ranges = - len / sizeof(struct linux_prom_ranges); - } - sd = &sdev->ofdev.dev.archdata; sd->prom_node = dp; sd->op = &sdev->ofdev; @@ -105,97 +78,6 @@ static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sde fill_sbus_device_iommu(sdev); } -static void __init sbus_bus_ranges_init(struct device_node *dp, struct sbus_bus *sbus) -{ - const void *pval; - int len; - - pval = of_get_property(dp, "ranges", &len); - sbus->num_sbus_ranges = 0; - if (pval) { - memcpy(sbus->sbus_ranges, pval, len); - sbus->num_sbus_ranges = - len / sizeof(struct linux_prom_ranges); - - sbus_arch_bus_ranges_init(dp->parent, sbus); - } -} - -static void __init __apply_ranges_to_regs(struct linux_prom_ranges *ranges, - int num_ranges, - struct linux_prom_registers *regs, - int num_regs) -{ - if (num_ranges) { - int regnum; - - for (regnum = 0; regnum < num_regs; regnum++) { - int rngnum; - - for (rngnum = 0; rngnum < num_ranges; rngnum++) { - if (regs[regnum].which_io == ranges[rngnum].ot_child_space) - break; - } - if (rngnum == num_ranges) { - /* We used to flag this as an error. Actually - * some devices do not report the regs as we expect. - * For example, see SUNW,pln device. In that case - * the reg property is in a format internal to that - * node, ie. it is not in the SBUS register space - * per se. -DaveM - */ - return; - } - regs[regnum].which_io = ranges[rngnum].ot_parent_space; - regs[regnum].phys_addr -= ranges[rngnum].ot_child_base; - regs[regnum].phys_addr += ranges[rngnum].ot_parent_base; - } - } -} - -static void __init __fixup_regs_sdev(struct sbus_dev *sdev) -{ - if (sdev->num_registers != 0) { - struct sbus_dev *parent = sdev->parent; - int i; - - while (parent != NULL) { - __apply_ranges_to_regs(parent->device_ranges, - parent->num_device_ranges, - sdev->reg_addrs, - sdev->num_registers); - - parent = parent->parent; - } - - __apply_ranges_to_regs(sdev->bus->sbus_ranges, - sdev->bus->num_sbus_ranges, - sdev->reg_addrs, - sdev->num_registers); - - for (i = 0; i < sdev->num_registers; i++) { - struct resource *res = &sdev->resource[i]; - - res->start = sdev->reg_addrs[i].phys_addr; - res->end = (res->start + - (unsigned long)sdev->reg_addrs[i].reg_size - 1UL); - res->flags = IORESOURCE_IO | - (sdev->reg_addrs[i].which_io & 0xff); - } - } -} - -static void __init sbus_fixup_all_regs(struct sbus_dev *first_sdev) -{ - struct sbus_dev *sdev; - - for (sdev = first_sdev; sdev; sdev = sdev->next) { - if (sdev->child) - sbus_fixup_all_regs(sdev->child); - __fixup_regs_sdev(sdev); - } -} - /* We preserve the "probe order" of these bus and device lists to give * the same ordering as the old code. */ @@ -263,8 +145,6 @@ static void __init build_one_sbus(struct device_node *dp, int num_sbus) strcpy(sbus->prom_name, dp->name); - sbus_bus_ranges_init(dp, sbus); - sbus->ofdev.node = dp; sbus->ofdev.dev.parent = NULL; sbus->ofdev.dev.bus = &sbus_bus_type; @@ -295,8 +175,6 @@ static void __init build_one_sbus(struct device_node *dp, int num_sbus) } dev_dp = dev_dp->sibling; } - - sbus_fixup_all_regs(sbus->devices); } static int __init sbus_init(void) -- cgit v1.2.3 From 98261dd1a393777f4400d8ad5a29e97cb30e5422 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 27 Aug 2008 03:47:56 -0700 Subject: sparc: Remove dinky old-style SBUS probing facilities. No drivers or code uses this stuff any more, every driver has been converted over to OF device probing. Signed-off-by: David S. Miller --- drivers/sbus/sbus.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'drivers/sbus') diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c index 89eb922a6ac..3b30f999512 100644 --- a/drivers/sbus/sbus.c +++ b/drivers/sbus/sbus.c @@ -28,8 +28,6 @@ show_sbusobppath_attr(struct device * dev, struct device_attribute * attr, char static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_sbusobppath_attr, NULL); -struct sbus_bus *sbus_root; - static void __init fill_sbus_device_iommu(struct sbus_dev *sdev) { struct of_device *op = of_find_device_by_node(sdev->ofdev.node); @@ -78,17 +76,6 @@ static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sde fill_sbus_device_iommu(sdev); } -/* We preserve the "probe order" of these bus and device lists to give - * the same ordering as the old code. - */ -static void __init sbus_insert(struct sbus_bus *sbus, struct sbus_bus **root) -{ - while (*root) - root = &(*root)->next; - *root = sbus; - sbus->next = NULL; -} - static void __init sdev_insert(struct sbus_dev *sdev, struct sbus_dev **root) { while (*root) @@ -128,7 +115,6 @@ static void __init build_one_sbus(struct device_node *dp, int num_sbus) if (!sbus) return; - sbus_insert(sbus, &sbus_root); sbus->prom_node = dp->node; sbus_setup_iommu(sbus, dp); -- cgit v1.2.3 From c6e5f661eee0ff62e7fdb263cfeee73c20dd6e99 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 27 Aug 2008 04:18:02 -0700 Subject: sparc: Kill OBP property members of sbus_dev and sbus_bus Unused. Signed-off-by: David S. Miller --- drivers/sbus/sbus.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) (limited to 'drivers/sbus') diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c index 3b30f999512..64c3e45875f 100644 --- a/drivers/sbus/sbus.c +++ b/drivers/sbus/sbus.c @@ -51,9 +51,6 @@ static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sde struct dev_archdata *sd; int err; - sdev->prom_node = dp->node; - strcpy(sdev->prom_name, dp->name); - sd = &sdev->ofdev.dev.archdata; sd->prom_node = dp; sd->op = &sdev->ofdev; @@ -107,30 +104,17 @@ static void __init walk_children(struct device_node *dp, struct sbus_dev *parent static void __init build_one_sbus(struct device_node *dp, int num_sbus) { - struct sbus_bus *sbus; - unsigned int sbus_clock; struct device_node *dev_dp; + struct sbus_bus *sbus; sbus = kzalloc(sizeof(struct sbus_bus), GFP_ATOMIC); if (!sbus) return; - sbus->prom_node = dp->node; - sbus_setup_iommu(sbus, dp); printk("sbus%d: ", num_sbus); - sbus_clock = of_getintprop_default(dp, "clock-frequency", - (25*1000*1000)); - sbus->clock_freq = sbus_clock; - - printk("Clock %d.%d MHz\n", (int) ((sbus_clock/1000)/1000), - (int) (((sbus_clock/1000)%1000 != 0) ? - (((sbus_clock/1000)%1000) + 1000) : 0)); - - strcpy(sbus->prom_name, dp->name); - sbus->ofdev.node = dp; sbus->ofdev.dev.parent = NULL; sbus->ofdev.dev.bus = &sbus_bus_type; -- cgit v1.2.3 From f8e4d32cb5153a9d6a8e8864e357dad1349f3b85 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 27 Aug 2008 04:20:14 -0700 Subject: sparc: Kill sbus_arch_preinit(). 32-bit sparc just needed it to register the ioport procfs bits, do this via an arch_initcall() instead. Signed-off-by: David S. Miller --- drivers/sbus/sbus.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/sbus') diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c index 64c3e45875f..399567b7e15 100644 --- a/drivers/sbus/sbus.c +++ b/drivers/sbus/sbus.c @@ -153,9 +153,6 @@ static int __init sbus_init(void) const char *sbus_name = "sbus"; int num_sbus = 0; - if (sbus_arch_preinit()) - return 0; - if (sparc_cpu_model == sun4d) sbus_name = "sbi"; -- cgit v1.2.3 From 046e26a8ba10b8ceff822f8d91451ab6c1e08c4e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 27 Aug 2008 04:54:04 -0700 Subject: sparc: Remove generic SBUS probing layer. The individual SBUS IOMMU arch code now sets the IOMMU information directly into the OF device objects. Signed-off-by: David S. Miller --- drivers/sbus/Makefile | 4 -- drivers/sbus/sbus.c | 170 -------------------------------------------------- 2 files changed, 174 deletions(-) delete mode 100644 drivers/sbus/sbus.c (limited to 'drivers/sbus') diff --git a/drivers/sbus/Makefile b/drivers/sbus/Makefile index 56f73318eba..e94dc25805f 100644 --- a/drivers/sbus/Makefile +++ b/drivers/sbus/Makefile @@ -2,8 +2,4 @@ # Makefile for the linux kernel. # -ifneq ($(ARCH),m68k) -obj-y := sbus.o -endif - obj-$(CONFIG_SBUSCHAR) += char/ diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c deleted file mode 100644 index 399567b7e15..00000000000 --- a/drivers/sbus/sbus.c +++ /dev/null @@ -1,170 +0,0 @@ -/* sbus.c: SBus support routines. - * - * Copyright (C) 1995, 2006 David S. Miller (davem@davemloft.net) - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -static ssize_t -show_sbusobppath_attr(struct device * dev, struct device_attribute * attr, char * buf) -{ - struct sbus_dev *sbus; - - sbus = to_sbus_device(dev); - - return snprintf (buf, PAGE_SIZE, "%s\n", sbus->ofdev.node->full_name); -} - -static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_sbusobppath_attr, NULL); - -static void __init fill_sbus_device_iommu(struct sbus_dev *sdev) -{ - struct of_device *op = of_find_device_by_node(sdev->ofdev.node); - struct dev_archdata *sd, *bus_sd; - struct sbus_bus *sbus; - - sbus = sdev->bus; - bus_sd = &sbus->ofdev.dev.archdata; - - sd = &sdev->ofdev.dev.archdata; - sd->iommu = bus_sd->iommu; - sd->stc = bus_sd->stc; - - sd = &op->dev.archdata; - sd->iommu = bus_sd->iommu; - sd->stc = bus_sd->stc; -} - -static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev) -{ - struct dev_archdata *sd; - int err; - - sd = &sdev->ofdev.dev.archdata; - sd->prom_node = dp; - sd->op = &sdev->ofdev; - - sdev->ofdev.node = dp; - if (sdev->parent) - sdev->ofdev.dev.parent = &sdev->parent->ofdev.dev; - else - sdev->ofdev.dev.parent = &sdev->bus->ofdev.dev; - sdev->ofdev.dev.bus = &sbus_bus_type; - dev_set_name(&sdev->ofdev.dev, "sbus[%08x]", dp->node); - - if (of_device_register(&sdev->ofdev) != 0) - printk(KERN_DEBUG "sbus: device registration error for %s!\n", - dp->path_component_name); - - /* WE HAVE BEEN INVADED BY ALIENS! */ - err = sysfs_create_file(&sdev->ofdev.dev.kobj, &dev_attr_obppath.attr); - - fill_sbus_device_iommu(sdev); -} - -static void __init sdev_insert(struct sbus_dev *sdev, struct sbus_dev **root) -{ - while (*root) - root = &(*root)->next; - *root = sdev; - sdev->next = NULL; -} - -static void __init walk_children(struct device_node *dp, struct sbus_dev *parent, struct sbus_bus *sbus) -{ - dp = dp->child; - while (dp) { - struct sbus_dev *sdev; - - sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC); - if (sdev) { - sdev_insert(sdev, &parent->child); - - sdev->bus = sbus; - sdev->parent = parent; - - fill_sbus_device(dp, sdev); - - walk_children(dp, sdev, sbus); - } - dp = dp->sibling; - } -} - -static void __init build_one_sbus(struct device_node *dp, int num_sbus) -{ - struct device_node *dev_dp; - struct sbus_bus *sbus; - - sbus = kzalloc(sizeof(struct sbus_bus), GFP_ATOMIC); - if (!sbus) - return; - - sbus_setup_iommu(sbus, dp); - - printk("sbus%d: ", num_sbus); - - sbus->ofdev.node = dp; - sbus->ofdev.dev.parent = NULL; - sbus->ofdev.dev.bus = &sbus_bus_type; - dev_set_name(&sbus->ofdev.dev, "sbus%d", num_sbus); - - if (of_device_register(&sbus->ofdev) != 0) - printk(KERN_DEBUG "sbus: device registration error for %s!\n", - dev_name(&sbus->ofdev.dev)); - - dev_dp = dp->child; - while (dev_dp) { - struct sbus_dev *sdev; - - sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC); - if (sdev) { - sdev_insert(sdev, &sbus->devices); - - sdev->bus = sbus; - sdev->parent = NULL; - sdev->ofdev.dev.archdata.iommu = - sbus->ofdev.dev.archdata.iommu; - sdev->ofdev.dev.archdata.stc = - sbus->ofdev.dev.archdata.stc; - - fill_sbus_device(dev_dp, sdev); - - walk_children(dev_dp, sdev, sbus); - } - dev_dp = dev_dp->sibling; - } -} - -static int __init sbus_init(void) -{ - struct device_node *dp; - const char *sbus_name = "sbus"; - int num_sbus = 0; - - if (sparc_cpu_model == sun4d) - sbus_name = "sbi"; - - for_each_node_by_name(dp, sbus_name) { - build_one_sbus(dp, num_sbus); - num_sbus++; - - } - - sbus_arch_postinit(); - - return 0; -} - -subsys_initcall(sbus_init); -- cgit v1.2.3 From e42311d75107ca78868ded0286b691aad2df1f29 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 29 Aug 2008 15:35:59 -0700 Subject: riowatchdog: Convert to pure OF driver. This also cleans up a lot of crud in this driver: 1) Don't touch the BBC regs, just leave the watchdog trigger behavior whatever the firmware programmed it to. 2) Use WATCHDOG_MINOR instead of hardcoded and not properly allocated RIOWD_MINOR. Hey, I haven't touched it since I wrote it years ago :-) Signed-off-by: David S. Miller --- drivers/sbus/char/riowatchdog.c | 234 +++++++++++++++++----------------------- 1 file changed, 99 insertions(+), 135 deletions(-) (limited to 'drivers/sbus') diff --git a/drivers/sbus/char/riowatchdog.c b/drivers/sbus/char/riowatchdog.c index 88c0fc6395e..b53af832a3a 100644 --- a/drivers/sbus/char/riowatchdog.c +++ b/drivers/sbus/char/riowatchdog.c @@ -1,7 +1,6 @@ -/* $Id: riowatchdog.c,v 1.3.2.2 2002/01/23 18:48:02 davem Exp $ - * riowatchdog.c - driver for hw watchdog inside Super I/O of RIO +/* riowatchdog.c - driver for hw watchdog inside Super I/O of RIO * - * Copyright (C) 2001 David S. Miller (davem@redhat.com) + * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net) */ #include @@ -12,14 +11,13 @@ #include #include #include +#include +#include +#include #include -#include -#include -#include #include -#include /* RIO uses the NatSemi Super I/O power management logical device * as its' watchdog. @@ -45,74 +43,35 @@ * The watchdog device generates no interrupts. */ -MODULE_AUTHOR("David S. Miller "); +MODULE_AUTHOR("David S. Miller "); MODULE_DESCRIPTION("Hardware watchdog driver for Sun RIO"); MODULE_SUPPORTED_DEVICE("watchdog"); MODULE_LICENSE("GPL"); #define RIOWD_NAME "pmc" -#define RIOWD_MINOR 215 +#define PFX RIOWD_NAME ": " -static DEFINE_SPINLOCK(riowd_lock); +struct riowd { + void __iomem *regs; + spinlock_t lock; +}; + +static struct riowd *riowd_device; -static void __iomem *bbc_regs; -static void __iomem *riowd_regs; #define WDTO_INDEX 0x05 static int riowd_timeout = 1; /* in minutes */ module_param(riowd_timeout, int, 0); MODULE_PARM_DESC(riowd_timeout, "Watchdog timeout in minutes"); -#if 0 /* Currently unused. */ -static u8 riowd_readreg(int index) +static void riowd_writereg(struct riowd *p, u8 val, int index) { unsigned long flags; - u8 ret; - spin_lock_irqsave(&riowd_lock, flags); - writeb(index, riowd_regs + 0); - ret = readb(riowd_regs + 1); - spin_unlock_irqrestore(&riowd_lock, flags); - - return ret; -} -#endif - -static void riowd_writereg(u8 val, int index) -{ - unsigned long flags; - - spin_lock_irqsave(&riowd_lock, flags); - writeb(index, riowd_regs + 0); - writeb(val, riowd_regs + 1); - spin_unlock_irqrestore(&riowd_lock, flags); -} - -static void riowd_pingtimer(void) -{ - riowd_writereg(riowd_timeout, WDTO_INDEX); -} - -static void riowd_stoptimer(void) -{ - u8 val; - - riowd_writereg(0, WDTO_INDEX); - - val = readb(bbc_regs + BBC_WDACTION); - val &= ~BBC_WDACTION_RST; - writeb(val, bbc_regs + BBC_WDACTION); -} - -static void riowd_starttimer(void) -{ - u8 val; - - riowd_writereg(riowd_timeout, WDTO_INDEX); - - val = readb(bbc_regs + BBC_WDACTION); - val |= BBC_WDACTION_RST; - writeb(val, bbc_regs + BBC_WDACTION); + spin_lock_irqsave(&p->lock, flags); + writeb(index, p->regs + 0); + writeb(val, p->regs + 1); + spin_unlock_irqrestore(&p->lock, flags); } static int riowd_open(struct inode *inode, struct file *filp) @@ -131,9 +90,12 @@ static int riowd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { static struct watchdog_info info = { - WDIOF_SETTIMEOUT, 0, "Natl. Semiconductor PC97317" + .options = WDIOF_SETTIMEOUT, + .firmware_version = 1, + .identity = "riowd", }; void __user *argp = (void __user *)arg; + struct riowd *p = riowd_device; unsigned int options; int new_margin; @@ -150,7 +112,7 @@ static int riowd_ioctl(struct inode *inode, struct file *filp, break; case WDIOC_KEEPALIVE: - riowd_pingtimer(); + riowd_writereg(p, riowd_timeout, WDTO_INDEX); break; case WDIOC_SETOPTIONS: @@ -158,9 +120,9 @@ static int riowd_ioctl(struct inode *inode, struct file *filp, return -EFAULT; if (options & WDIOS_DISABLECARD) - riowd_stoptimer(); + riowd_writereg(p, 0, WDTO_INDEX); else if (options & WDIOS_ENABLECARD) - riowd_starttimer(); + riowd_writereg(p, riowd_timeout, WDTO_INDEX); else return -EINVAL; @@ -170,9 +132,9 @@ static int riowd_ioctl(struct inode *inode, struct file *filp, if (get_user(new_margin, (int __user *)argp)) return -EFAULT; if ((new_margin < 60) || (new_margin > (255 * 60))) - return -EINVAL; + return -EINVAL; riowd_timeout = (new_margin + 59) / 60; - riowd_pingtimer(); + riowd_writereg(p, riowd_timeout, WDTO_INDEX); /* Fall */ case WDIOC_GETTIMEOUT: @@ -187,8 +149,10 @@ static int riowd_ioctl(struct inode *inode, struct file *filp, static ssize_t riowd_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { + struct riowd *p = riowd_device; + if (count) { - riowd_pingtimer(); + riowd_writereg(p, riowd_timeout, WDTO_INDEX); return 1; } @@ -197,99 +161,99 @@ static ssize_t riowd_write(struct file *file, const char __user *buf, size_t cou static const struct file_operations riowd_fops = { .owner = THIS_MODULE, + .llseek = no_llseek, .ioctl = riowd_ioctl, .open = riowd_open, .write = riowd_write, .release = riowd_release, }; -static struct miscdevice riowd_miscdev = { RIOWD_MINOR, RIOWD_NAME, &riowd_fops }; +static struct miscdevice riowd_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &riowd_fops +}; -static int __init riowd_bbc_init(void) +static int __devinit riowd_probe(struct of_device *op, + const struct of_device_id *match) { - struct linux_ebus *ebus = NULL; - struct linux_ebus_device *edev = NULL; - u8 val; - - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->ofdev.node->name, "bbc")) - goto found_bbc; - } - } + struct riowd *p; + int err = -EINVAL; -found_bbc: - if (!edev) - return -ENODEV; - bbc_regs = ioremap(edev->resource[0].start, BBC_REGS_SIZE); - if (!bbc_regs) - return -ENODEV; + if (riowd_device) + goto out; - /* Turn it off. */ - val = readb(bbc_regs + BBC_WDACTION); - val &= ~BBC_WDACTION_RST; - writeb(val, bbc_regs + BBC_WDACTION); + err = -ENOMEM; + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + goto out; - return 0; -} + spin_lock_init(&p->lock); -static int __init riowd_init(void) -{ - struct linux_ebus *ebus = NULL; - struct linux_ebus_device *edev = NULL; - - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->ofdev.node->name, RIOWD_NAME)) - goto ebus_done; - } + p->regs = of_ioremap(&op->resource[0], 0, 2, "riowd"); + if (!p->regs) { + printk(KERN_ERR PFX "Cannot map registers.\n"); + goto out_free; } -ebus_done: - if (!edev) - goto fail; - - riowd_regs = ioremap(edev->resource[0].start, 2); - if (riowd_regs == NULL) { - printk(KERN_ERR "pmc: Cannot map registers.\n"); - return -ENODEV; + err = misc_register(&riowd_miscdev); + if (err) { + printk(KERN_ERR PFX "Cannot register watchdog misc device.\n"); + goto out_iounmap; } - if (riowd_bbc_init()) { - printk(KERN_ERR "pmc: Failure initializing BBC config.\n"); - goto fail; - } + printk(KERN_INFO PFX "Hardware watchdog [%i minutes], " + "regs at %p\n", riowd_timeout, p->regs); - if (misc_register(&riowd_miscdev)) { - printk(KERN_ERR "pmc: Cannot register watchdog misc device.\n"); - goto fail; - } + dev_set_drvdata(&op->dev, p); + riowd_device = p; + err = 0; - printk(KERN_INFO "pmc: Hardware watchdog [%i minutes], " - "regs at %p\n", riowd_timeout, riowd_regs); +out_iounmap: + of_iounmap(&op->resource[0], p->regs, 2); - return 0; +out_free: + kfree(p); -fail: - if (riowd_regs) { - iounmap(riowd_regs); - riowd_regs = NULL; - } - if (bbc_regs) { - iounmap(bbc_regs); - bbc_regs = NULL; - } - return -ENODEV; +out: + return err; } -static void __exit riowd_cleanup(void) +static int __devexit riowd_remove(struct of_device *op) { + struct riowd *p = dev_get_drvdata(&op->dev); + misc_deregister(&riowd_miscdev); - iounmap(riowd_regs); - riowd_regs = NULL; - iounmap(bbc_regs); - bbc_regs = NULL; + of_iounmap(&op->resource[0], p->regs, 2); + kfree(p); + + return 0; +} + +static struct of_device_id riowd_match[] = { + { + .name = "pmc", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, riowd_match); + +static struct of_platform_driver riowd_driver = { + .name = "riowd", + .match_table = riowd_match, + .probe = riowd_probe, + .remove = __devexit_p(riowd_remove), +}; + +static int __init riowd_init(void) +{ + return of_register_driver(&riowd_driver, &of_bus_type); +} + +static void __exit riowd_exit(void) +{ + of_unregister_driver(&riowd_driver); } module_init(riowd_init); -module_exit(riowd_cleanup); +module_exit(riowd_exit); -- cgit v1.2.3 From 957183f32e136450eb9a4b8eed52dfac46834eed Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 29 Aug 2008 15:40:24 -0700 Subject: riowatchdog: Move under drivers/watchdog The config stuff was already in drivers/watchdog/Kconfig Signed-off-by: David S. Miller --- drivers/sbus/char/Makefile | 1 - drivers/sbus/char/riowatchdog.c | 259 ---------------------------------------- 2 files changed, 260 deletions(-) delete mode 100644 drivers/sbus/char/riowatchdog.c (limited to 'drivers/sbus') diff --git a/drivers/sbus/char/Makefile b/drivers/sbus/char/Makefile index e15bd5e3946..b29c186b695 100644 --- a/drivers/sbus/char/Makefile +++ b/drivers/sbus/char/Makefile @@ -12,7 +12,6 @@ bbc-objs := bbc_i2c.o bbc_envctrl.o obj-$(CONFIG_ENVCTRL) += envctrl.o obj-$(CONFIG_DISPLAY7SEG) += display7seg.o obj-$(CONFIG_WATCHDOG_CP1XXX) += cpwatchdog.o -obj-$(CONFIG_WATCHDOG_RIO) += riowatchdog.o obj-$(CONFIG_OBP_FLASH) += flash.o obj-$(CONFIG_SUN_OPENPROMIO) += openprom.o obj-$(CONFIG_SUN_MOSTEK_RTC) += rtc.o diff --git a/drivers/sbus/char/riowatchdog.c b/drivers/sbus/char/riowatchdog.c deleted file mode 100644 index b53af832a3a..00000000000 --- a/drivers/sbus/char/riowatchdog.c +++ /dev/null @@ -1,259 +0,0 @@ -/* riowatchdog.c - driver for hw watchdog inside Super I/O of RIO - * - * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - - -/* RIO uses the NatSemi Super I/O power management logical device - * as its' watchdog. - * - * When the watchdog triggers, it asserts a line to the BBC (Boot Bus - * Controller) of the machine. The BBC can only be configured to - * trigger a power-on reset when the signal is asserted. The BBC - * can be configured to ignore the signal entirely as well. - * - * The only Super I/O device register we care about is at index - * 0x05 (WDTO_INDEX) which is the watchdog time-out in minutes (1-255). - * If set to zero, this disables the watchdog. When set, the system - * must periodically (before watchdog expires) clear (set to zero) and - * re-set the watchdog else it will trigger. - * - * There are two other indexed watchdog registers inside this Super I/O - * logical device, but they are unused. The first, at index 0x06 is - * the watchdog control and can be used to make the watchdog timer re-set - * when the PS/2 mouse or serial lines show activity. The second, at - * index 0x07 is merely a sampling of the line from the watchdog to the - * BBC. - * - * The watchdog device generates no interrupts. - */ - -MODULE_AUTHOR("David S. Miller "); -MODULE_DESCRIPTION("Hardware watchdog driver for Sun RIO"); -MODULE_SUPPORTED_DEVICE("watchdog"); -MODULE_LICENSE("GPL"); - -#define RIOWD_NAME "pmc" -#define PFX RIOWD_NAME ": " - -struct riowd { - void __iomem *regs; - spinlock_t lock; -}; - -static struct riowd *riowd_device; - -#define WDTO_INDEX 0x05 - -static int riowd_timeout = 1; /* in minutes */ -module_param(riowd_timeout, int, 0); -MODULE_PARM_DESC(riowd_timeout, "Watchdog timeout in minutes"); - -static void riowd_writereg(struct riowd *p, u8 val, int index) -{ - unsigned long flags; - - spin_lock_irqsave(&p->lock, flags); - writeb(index, p->regs + 0); - writeb(val, p->regs + 1); - spin_unlock_irqrestore(&p->lock, flags); -} - -static int riowd_open(struct inode *inode, struct file *filp) -{ - cycle_kernel_lock(); - nonseekable_open(inode, filp); - return 0; -} - -static int riowd_release(struct inode *inode, struct file *filp) -{ - return 0; -} - -static int riowd_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - static struct watchdog_info info = { - .options = WDIOF_SETTIMEOUT, - .firmware_version = 1, - .identity = "riowd", - }; - void __user *argp = (void __user *)arg; - struct riowd *p = riowd_device; - unsigned int options; - int new_margin; - - switch (cmd) { - case WDIOC_GETSUPPORT: - if (copy_to_user(argp, &info, sizeof(info))) - return -EFAULT; - break; - - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - if (put_user(0, (int __user *)argp)) - return -EFAULT; - break; - - case WDIOC_KEEPALIVE: - riowd_writereg(p, riowd_timeout, WDTO_INDEX); - break; - - case WDIOC_SETOPTIONS: - if (copy_from_user(&options, argp, sizeof(options))) - return -EFAULT; - - if (options & WDIOS_DISABLECARD) - riowd_writereg(p, 0, WDTO_INDEX); - else if (options & WDIOS_ENABLECARD) - riowd_writereg(p, riowd_timeout, WDTO_INDEX); - else - return -EINVAL; - - break; - - case WDIOC_SETTIMEOUT: - if (get_user(new_margin, (int __user *)argp)) - return -EFAULT; - if ((new_margin < 60) || (new_margin > (255 * 60))) - return -EINVAL; - riowd_timeout = (new_margin + 59) / 60; - riowd_writereg(p, riowd_timeout, WDTO_INDEX); - /* Fall */ - - case WDIOC_GETTIMEOUT: - return put_user(riowd_timeout * 60, (int __user *)argp); - - default: - return -EINVAL; - }; - - return 0; -} - -static ssize_t riowd_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) -{ - struct riowd *p = riowd_device; - - if (count) { - riowd_writereg(p, riowd_timeout, WDTO_INDEX); - return 1; - } - - return 0; -} - -static const struct file_operations riowd_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = riowd_ioctl, - .open = riowd_open, - .write = riowd_write, - .release = riowd_release, -}; - -static struct miscdevice riowd_miscdev = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &riowd_fops -}; - -static int __devinit riowd_probe(struct of_device *op, - const struct of_device_id *match) -{ - struct riowd *p; - int err = -EINVAL; - - if (riowd_device) - goto out; - - err = -ENOMEM; - p = kzalloc(sizeof(*p), GFP_KERNEL); - if (!p) - goto out; - - spin_lock_init(&p->lock); - - p->regs = of_ioremap(&op->resource[0], 0, 2, "riowd"); - if (!p->regs) { - printk(KERN_ERR PFX "Cannot map registers.\n"); - goto out_free; - } - - err = misc_register(&riowd_miscdev); - if (err) { - printk(KERN_ERR PFX "Cannot register watchdog misc device.\n"); - goto out_iounmap; - } - - printk(KERN_INFO PFX "Hardware watchdog [%i minutes], " - "regs at %p\n", riowd_timeout, p->regs); - - dev_set_drvdata(&op->dev, p); - riowd_device = p; - err = 0; - -out_iounmap: - of_iounmap(&op->resource[0], p->regs, 2); - -out_free: - kfree(p); - -out: - return err; -} - -static int __devexit riowd_remove(struct of_device *op) -{ - struct riowd *p = dev_get_drvdata(&op->dev); - - misc_deregister(&riowd_miscdev); - of_iounmap(&op->resource[0], p->regs, 2); - kfree(p); - - return 0; -} - -static struct of_device_id riowd_match[] = { - { - .name = "pmc", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, riowd_match); - -static struct of_platform_driver riowd_driver = { - .name = "riowd", - .match_table = riowd_match, - .probe = riowd_probe, - .remove = __devexit_p(riowd_remove), -}; - -static int __init riowd_init(void) -{ - return of_register_driver(&riowd_driver, &of_bus_type); -} - -static void __exit riowd_exit(void) -{ - of_unregister_driver(&riowd_driver); -} - -module_init(riowd_init); -module_exit(riowd_exit); -- cgit v1.2.3 From c5f8556cb5b8ab020f234191a6071cbeeeabd638 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 29 Aug 2008 17:05:51 -0700 Subject: cpwatchdog: Cleanup and convert to pure OF driver. Signed-off-by: David S. Miller --- drivers/sbus/char/cpwatchdog.c | 1035 +++++++++++++++++----------------------- 1 file changed, 436 insertions(+), 599 deletions(-) (limited to 'drivers/sbus') diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c index 23abfdfb44f..c88df62e705 100644 --- a/drivers/sbus/char/cpwatchdog.c +++ b/drivers/sbus/char/cpwatchdog.c @@ -11,6 +11,7 @@ * reset 'stopped' watchdogs on affected platforms. * * Copyright (c) 2000 Eric Brower (ebrower@usa.net) + * Copyright (C) 2008 David S. Miller */ #include @@ -25,36 +26,34 @@ #include #include #include +#include +#include + #include -#include -#include #include #include +#define DRIVER_NAME "cpwd" +#define PFX DRIVER_NAME ": " + #define WD_OBPNAME "watchdog" -#define WD_BADMODEL "SUNW,501-5336" +#define WD_BADMODEL "SUNW,501-5336" #define WD_BTIMEOUT (jiffies + (HZ * 1000)) #define WD_BLIMIT 0xFFFF -#define WD0_DEVNAME "watchdog0" -#define WD1_DEVNAME "watchdog1" -#define WD2_DEVNAME "watchdog2" - #define WD0_MINOR 212 #define WD1_MINOR 213 #define WD2_MINOR 214 +/* Internal driver definitions. */ +#define WD0_ID 0 +#define WD1_ID 1 +#define WD2_ID 2 +#define WD_NUMDEVS 3 -/* Internal driver definitions - */ -#define WD0_ID 0 /* Watchdog0 */ -#define WD1_ID 1 /* Watchdog1 */ -#define WD2_ID 2 /* Watchdog2 */ -#define WD_NUMDEVS 3 /* Device contains 3 timers */ - -#define WD_INTR_OFF 0 /* Interrupt disable value */ -#define WD_INTR_ON 1 /* Interrupt enable value */ +#define WD_INTR_OFF 0 +#define WD_INTR_ON 1 #define WD_STAT_INIT 0x01 /* Watchdog timer is initialized */ #define WD_STAT_BSTOP 0x02 /* Watchdog timer is brokenstopped */ @@ -69,6 +68,29 @@ #define WD_S_RUNNING 0x01 /* Watchdog device status running */ #define WD_S_EXPIRED 0x02 /* Watchdog device status expired */ +struct cpwd { + void __iomem *regs; + spinlock_t lock; + + unsigned int irq; + + unsigned long timeout; + bool enabled; + bool reboot; + bool broken; + bool initialized; + + struct { + struct miscdevice misc; + void __iomem *regs; + u8 intr_mask; + u8 runstatus; + u16 timeout; + } devs[WD_NUMDEVS]; +}; + +static struct cpwd *cpwd_device; + /* Sun uses Altera PLD EPF8820ATC144-4 * providing three hardware watchdogs: * @@ -130,40 +152,12 @@ #define PLD_IMASK (PLD_OFF + 0x00) #define PLD_STATUS (PLD_OFF + 0x04) -/* Individual timer structure - */ -struct wd_timer { - __u16 timeout; - __u8 intr_mask; - unsigned char runstatus; - void __iomem *regs; -}; - -/* Device structure - */ -struct wd_device { - int irq; - spinlock_t lock; - unsigned char isbaddoggie; /* defective PLD */ - unsigned char opt_enable; - unsigned char opt_reboot; - unsigned short opt_timeout; - unsigned char initialized; - struct wd_timer watchdog[WD_NUMDEVS]; - void __iomem *regs; -}; - -static struct wd_device wd_dev = { - 0, __SPIN_LOCK_UNLOCKED(wd_dev.lock), 0, 0, 0, 0, -}; - -static struct timer_list wd_timer; +static struct timer_list cpwd_timer; static int wd0_timeout = 0; static int wd1_timeout = 0; static int wd2_timeout = 0; -#ifdef MODULE module_param (wd0_timeout, int, 0); MODULE_PARM_DESC(wd0_timeout, "Default watchdog0 timeout in 1/10secs"); module_param (wd1_timeout, int, 0); @@ -171,234 +165,313 @@ MODULE_PARM_DESC(wd1_timeout, "Default watchdog1 timeout in 1/10secs"); module_param (wd2_timeout, int, 0); MODULE_PARM_DESC(wd2_timeout, "Default watchdog2 timeout in 1/10secs"); -MODULE_AUTHOR - ("Eric Brower "); -MODULE_DESCRIPTION - ("Hardware watchdog driver for Sun Microsystems CP1400/1500"); +MODULE_AUTHOR("Eric Brower "); +MODULE_DESCRIPTION("Hardware watchdog driver for Sun Microsystems CP1400/1500"); MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE - ("watchdog"); -#endif /* ifdef MODULE */ +MODULE_SUPPORTED_DEVICE("watchdog"); + +static void cpwd_writew(u16 val, void __iomem *addr) +{ + writew(cpu_to_le16(val), addr); +} +static u16 cpwd_readw(void __iomem *addr) +{ + u16 val = readw(addr); + + return le16_to_cpu(val); +} + +static void cpwd_writeb(u8 val, void __iomem *addr) +{ + writeb(val, addr); +} + +static u8 cpwd_readb(void __iomem *addr) +{ + return readb(addr); +} -/* Forward declarations of internal methods +/* Enable or disable watchdog interrupts + * Because of the CP1400 defect this should only be + * called during initialzation or by wd_[start|stop]timer() + * + * index - sub-device index, or -1 for 'all' + * enable - non-zero to enable interrupts, zero to disable */ -#ifdef WD_DEBUG -static void wd_dumpregs(void); -#endif -static irqreturn_t wd_interrupt(int irq, void *dev_id); -static void wd_toggleintr(struct wd_timer* pTimer, int enable); -static void wd_pingtimer(struct wd_timer* pTimer); -static void wd_starttimer(struct wd_timer* pTimer); -static void wd_resetbrokentimer(struct wd_timer* pTimer); -static void wd_stoptimer(struct wd_timer* pTimer); -static void wd_brokentimer(unsigned long data); -static int wd_getstatus(struct wd_timer* pTimer); - -/* PLD expects words to be written in LSB format, - * so we must flip all words prior to writing them to regs +static void cpwd_toggleintr(struct cpwd *p, int index, int enable) +{ + unsigned char curregs = cpwd_readb(p->regs + PLD_IMASK); + unsigned char setregs = + (index == -1) ? + (WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) : + (p->devs[index].intr_mask); + + if (enable == WD_INTR_ON) + curregs &= ~setregs; + else + curregs |= setregs; + + cpwd_writeb(curregs, p->regs + PLD_IMASK); +} + +/* Restarts timer with maximum limit value and + * does not unset 'brokenstop' value. */ -static inline unsigned short flip_word(unsigned short word) +static void cpwd_resetbrokentimer(struct cpwd *p, int index) { - return ((word & 0xff) << 8) | ((word >> 8) & 0xff); + cpwd_toggleintr(p, index, WD_INTR_ON); + cpwd_writew(WD_BLIMIT, p->devs[index].regs + WD_LIMIT); } -#define wd_writew(val, addr) (writew(flip_word(val), addr)) -#define wd_readw(addr) (flip_word(readw(addr))) -#define wd_writeb(val, addr) (writeb(val, addr)) -#define wd_readb(addr) (readb(addr)) +/* Timer method called to reset stopped watchdogs-- + * because of the PLD bug on CP1400, we cannot mask + * interrupts within the PLD so me must continually + * reset the timers ad infinitum. + */ +static void cpwd_brokentimer(unsigned long data) +{ + struct cpwd *p = (struct cpwd *) data; + int id, tripped = 0; + + /* kill a running timer instance, in case we + * were called directly instead of by kernel timer + */ + if (timer_pending(&cpwd_timer)) + del_timer(&cpwd_timer); + for (id = 0; id < WD_NUMDEVS; id++) { + if (p->devs[id].runstatus & WD_STAT_BSTOP) { + ++tripped; + cpwd_resetbrokentimer(p, id); + } + } -/* CP1400s seem to have broken PLD implementations-- - * the interrupt_mask register cannot be written, so - * no timer interrupts can be masked within the PLD. + if (tripped) { + /* there is at least one timer brokenstopped-- reschedule */ + cpwd_timer.expires = WD_BTIMEOUT; + add_timer(&cpwd_timer); + } +} + +/* Reset countdown timer with 'limit' value and continue countdown. + * This will not start a stopped timer. */ -static inline int wd_isbroken(void) +static void cpwd_pingtimer(struct cpwd *p, int index) { - /* we could test this by read/write/read/restore - * on the interrupt mask register only if OBP - * 'watchdog-enable?' == FALSE, but it seems - * ubiquitous on CP1400s - */ - char val[32]; - prom_getproperty(prom_root_node, "model", val, sizeof(val)); - return((!strcmp(val, WD_BADMODEL)) ? 1 : 0); + if (cpwd_readb(p->devs[index].regs + WD_STATUS) & WD_S_RUNNING) + cpwd_readw(p->devs[index].regs + WD_DCNTR); } - -/* Retrieve watchdog-enable? option from OBP - * Returns 0 if false, 1 if true + +/* Stop a running watchdog timer-- the timer actually keeps + * running, but the interrupt is masked so that no action is + * taken upon expiration. */ -static inline int wd_opt_enable(void) +static void cpwd_stoptimer(struct cpwd *p, int index) { - int opt_node; + if (cpwd_readb(p->devs[index].regs + WD_STATUS) & WD_S_RUNNING) { + cpwd_toggleintr(p, index, WD_INTR_OFF); - opt_node = prom_getchild(prom_root_node); - opt_node = prom_searchsiblings(opt_node, "options"); - return((-1 == prom_getint(opt_node, "watchdog-enable?")) ? 0 : 1); + if (p->broken) { + p->devs[index].runstatus |= WD_STAT_BSTOP; + cpwd_brokentimer((unsigned long) p); + } + } } -/* Retrieve watchdog-reboot? option from OBP - * Returns 0 if false, 1 if true +/* Start a watchdog timer with the specified limit value + * If the watchdog is running, it will be restarted with + * the provided limit value. + * + * This function will enable interrupts on the specified + * watchdog. */ -static inline int wd_opt_reboot(void) +static void cpwd_starttimer(struct cpwd *p, int index) { - int opt_node; + if (p->broken) + p->devs[index].runstatus &= ~WD_STAT_BSTOP; + + p->devs[index].runstatus &= ~WD_STAT_SVCD; - opt_node = prom_getchild(prom_root_node); - opt_node = prom_searchsiblings(opt_node, "options"); - return((-1 == prom_getint(opt_node, "watchdog-reboot?")) ? 0 : 1); + cpwd_writew(p->devs[index].timeout, p->devs[index].regs + WD_LIMIT); + cpwd_toggleintr(p, index, WD_INTR_ON); } -/* Retrieve watchdog-timeout option from OBP - * Returns OBP value, or 0 if not located - */ -static inline int wd_opt_timeout(void) +static int cpwd_getstatus(struct cpwd *p, int index) { - int opt_node; - char value[32]; - char *p = value; - - opt_node = prom_getchild(prom_root_node); - opt_node = prom_searchsiblings(opt_node, "options"); - opt_node = prom_getproperty(opt_node, - "watchdog-timeout", - value, - sizeof(value)); - if(-1 != opt_node) { - /* atoi implementation */ - for(opt_node = 0; /* nop */; p++) { - if(*p >= '0' && *p <= '9') { - opt_node = (10*opt_node)+(*p-'0'); - } - else { - break; + unsigned char stat = cpwd_readb(p->devs[index].regs + WD_STATUS); + unsigned char intr = cpwd_readb(p->devs[index].regs + PLD_IMASK); + unsigned char ret = WD_STOPPED; + + /* determine STOPPED */ + if (!stat) + return ret; + + /* determine EXPIRED vs FREERUN vs RUNNING */ + else if (WD_S_EXPIRED & stat) { + ret = WD_EXPIRED; + } else if(WD_S_RUNNING & stat) { + if (intr & p->devs[index].intr_mask) { + ret = WD_FREERUN; + } else { + /* Fudge WD_EXPIRED status for defective CP1400-- + * IF timer is running + * AND brokenstop is set + * AND an interrupt has been serviced + * we are WD_EXPIRED. + * + * IF timer is running + * AND brokenstop is set + * AND no interrupt has been serviced + * we are WD_FREERUN. + */ + if (p->broken && + (p->devs[index].runstatus & WD_STAT_BSTOP)) { + if (p->devs[index].runstatus & WD_STAT_SVCD) { + ret = WD_EXPIRED; + } else { + /* we could as well pretend we are expired */ + ret = WD_FREERUN; + } + } else { + ret = WD_RUNNING; } } } - return((-1 == opt_node) ? (0) : (opt_node)); + + /* determine SERVICED */ + if (p->devs[index].runstatus & WD_STAT_SVCD) + ret |= WD_SERVICED; + + return(ret); +} + +static irqreturn_t cpwd_interrupt(int irq, void *dev_id) +{ + struct cpwd *p = dev_id; + + /* Only WD0 will interrupt-- others are NMI and we won't + * see them here.... + */ + spin_lock_irq(&p->lock); + + cpwd_stoptimer(p, WD0_ID); + p->devs[WD0_ID].runstatus |= WD_STAT_SVCD; + + spin_unlock_irq(&p->lock); + + return IRQ_HANDLED; } -static int wd_open(struct inode *inode, struct file *f) +static int cpwd_open(struct inode *inode, struct file *f) { + struct cpwd *p = cpwd_device; + lock_kernel(); - switch(iminor(inode)) - { + switch(iminor(inode)) { case WD0_MINOR: - f->private_data = &wd_dev.watchdog[WD0_ID]; - break; case WD1_MINOR: - f->private_data = &wd_dev.watchdog[WD1_ID]; - break; case WD2_MINOR: - f->private_data = &wd_dev.watchdog[WD2_ID]; break; + default: unlock_kernel(); - return(-ENODEV); + return -ENODEV; } /* Register IRQ on first open of device */ - if(0 == wd_dev.initialized) - { - if (request_irq(wd_dev.irq, - &wd_interrupt, - IRQF_SHARED, - WD_OBPNAME, - (void *)wd_dev.regs)) { - printk("%s: Cannot register IRQ %d\n", - WD_OBPNAME, wd_dev.irq); + if (!p->initialized) { + if (request_irq(p->irq, &cpwd_interrupt, + IRQF_SHARED, DRIVER_NAME, p)) { + printk(KERN_ERR PFX "Cannot register IRQ %d\n", + p->irq); unlock_kernel(); - return(-EBUSY); + return -EBUSY; } - wd_dev.initialized = 1; + p->initialized = true; } unlock_kernel(); - return(nonseekable_open(inode, f)); + + return nonseekable_open(inode, f); } -static int wd_release(struct inode *inode, struct file *file) +static int cpwd_release(struct inode *inode, struct file *file) { return 0; } -static int wd_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int cpwd_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { - int setopt = 0; - struct wd_timer* pTimer = (struct wd_timer*)file->private_data; - void __user *argp = (void __user *)arg; - struct watchdog_info info = { - 0, - 0, - "Altera EPF8820ATC144-4" + static struct watchdog_info info = { + .options = WDIOF_SETTIMEOUT, + .firmware_version = 1, + .identity = DRIVER_NAME, }; + void __user *argp = (void __user *)arg; + int index = iminor(inode) - WD0_MINOR; + struct cpwd *p = cpwd_device; + int setopt = 0; - if(NULL == pTimer) { - return(-EINVAL); - } + switch (cmd) { + /* Generic Linux IOCTLs */ + case WDIOC_GETSUPPORT: + if (copy_to_user(argp, &info, sizeof(struct watchdog_info))) + return -EFAULT; + break; - switch(cmd) - { - /* Generic Linux IOCTLs */ - case WDIOC_GETSUPPORT: - if(copy_to_user(argp, &info, sizeof(struct watchdog_info))) { - return(-EFAULT); - } - break; - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - if (put_user(0, (int __user *)argp)) - return -EFAULT; - break; - case WDIOC_KEEPALIVE: - wd_pingtimer(pTimer); - break; - case WDIOC_SETOPTIONS: - if(copy_from_user(&setopt, argp, sizeof(unsigned int))) { - return -EFAULT; - } - if(setopt & WDIOS_DISABLECARD) { - if(wd_dev.opt_enable) { - printk( - "%s: cannot disable watchdog in ENABLED mode\n", - WD_OBPNAME); - return(-EINVAL); - } - wd_stoptimer(pTimer); - } - else if(setopt & WDIOS_ENABLECARD) { - wd_starttimer(pTimer); - } - else { - return(-EINVAL); - } - break; - /* Solaris-compatible IOCTLs */ - case WIOCGSTAT: - setopt = wd_getstatus(pTimer); - if(copy_to_user(argp, &setopt, sizeof(unsigned int))) { - return(-EFAULT); - } - break; - case WIOCSTART: - wd_starttimer(pTimer); - break; - case WIOCSTOP: - if(wd_dev.opt_enable) { - printk("%s: cannot disable watchdog in ENABLED mode\n", - WD_OBPNAME); - return(-EINVAL); - } - wd_stoptimer(pTimer); - break; - default: + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + if (put_user(0, (int __user *)argp)) + return -EFAULT; + break; + + case WDIOC_KEEPALIVE: + cpwd_pingtimer(p, index); + break; + + case WDIOC_SETOPTIONS: + if (copy_from_user(&setopt, argp, sizeof(unsigned int))) + return -EFAULT; + + if (setopt & WDIOS_DISABLECARD) { + if (p->enabled) + return -EINVAL; + cpwd_stoptimer(p, index); + } else if (setopt & WDIOS_ENABLECARD) { + cpwd_starttimer(p, index); + } else { + return -EINVAL; + } + break; + + /* Solaris-compatible IOCTLs */ + case WIOCGSTAT: + setopt = cpwd_getstatus(p, index); + if (copy_to_user(argp, &setopt, sizeof(unsigned int))) + return -EFAULT; + break; + + case WIOCSTART: + cpwd_starttimer(p, index); + break; + + case WIOCSTOP: + if (p->enabled) return(-EINVAL); + + cpwd_stoptimer(p, index); + break; + + default: + return -EINVAL; } - return(0); + + return 0; } -static long wd_compat_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) +static long cpwd_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { int rval = -ENOIOCTLCMD; @@ -408,9 +481,10 @@ static long wd_compat_ioctl(struct file *file, unsigned int cmd, case WIOCSTOP: case WIOCGSTAT: lock_kernel(); - rval = wd_ioctl(file->f_path.dentry->d_inode, file, cmd, arg); + rval = cpwd_ioctl(file->f_path.dentry->d_inode, file, cmd, arg); unlock_kernel(); break; + /* everything else is handled by the generic compat layer */ default: break; @@ -419,440 +493,203 @@ static long wd_compat_ioctl(struct file *file, unsigned int cmd, return rval; } -static ssize_t wd_write(struct file *file, - const char __user *buf, - size_t count, - loff_t *ppos) +static ssize_t cpwd_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) { - struct wd_timer* pTimer = (struct wd_timer*)file->private_data; - - if(NULL == pTimer) { - return(-EINVAL); - } + struct inode *inode = file->f_path.dentry->d_inode; + struct cpwd *p = cpwd_device; + int index = iminor(inode); if (count) { - wd_pingtimer(pTimer); + cpwd_pingtimer(p, index); return 1; } - return 0; -} -static ssize_t wd_read(struct file * file, char __user *buffer, - size_t count, loff_t *ppos) -{ -#ifdef WD_DEBUG - wd_dumpregs(); - return(0); -#else - return(-EINVAL); -#endif /* ifdef WD_DEBUG */ + return 0; } -static irqreturn_t wd_interrupt(int irq, void *dev_id) +static ssize_t cpwd_read(struct file * file, char __user *buffer, + size_t count, loff_t *ppos) { - /* Only WD0 will interrupt-- others are NMI and we won't - * see them here.... - */ - spin_lock_irq(&wd_dev.lock); - if((unsigned long)wd_dev.regs == (unsigned long)dev_id) - { - wd_stoptimer(&wd_dev.watchdog[WD0_ID]); - wd_dev.watchdog[WD0_ID].runstatus |= WD_STAT_SVCD; - } - spin_unlock_irq(&wd_dev.lock); - return IRQ_HANDLED; + return -EINVAL; } -static const struct file_operations wd_fops = { +static const struct file_operations cpwd_fops = { .owner = THIS_MODULE, - .ioctl = wd_ioctl, - .compat_ioctl = wd_compat_ioctl, - .open = wd_open, - .write = wd_write, - .read = wd_read, - .release = wd_release, + .ioctl = cpwd_ioctl, + .compat_ioctl = cpwd_compat_ioctl, + .open = cpwd_open, + .write = cpwd_write, + .read = cpwd_read, + .release = cpwd_release, }; -static struct miscdevice wd0_miscdev = { WD0_MINOR, WD0_DEVNAME, &wd_fops }; -static struct miscdevice wd1_miscdev = { WD1_MINOR, WD1_DEVNAME, &wd_fops }; -static struct miscdevice wd2_miscdev = { WD2_MINOR, WD2_DEVNAME, &wd_fops }; - -#ifdef WD_DEBUG -static void wd_dumpregs(void) +static int __devinit cpwd_probe(struct of_device *op, + const struct of_device_id *match) { - /* Reading from downcounters initiates watchdog countdown-- - * Example is included below for illustration purposes. - */ - int i; - printk("%s: dumping register values\n", WD_OBPNAME); - for(i = WD0_ID; i < WD_NUMDEVS; ++i) { - /* printk("\t%s%i: dcntr at 0x%lx: 0x%x\n", - * WD_OBPNAME, - * i, - * (unsigned long)(&wd_dev.watchdog[i].regs->dcntr), - * readw(&wd_dev.watchdog[i].regs->dcntr)); - */ - printk("\t%s%i: limit at 0x%lx: 0x%x\n", - WD_OBPNAME, - i, - (unsigned long)(&wd_dev.watchdog[i].regs->limit), - readw(&wd_dev.watchdog[i].regs->limit)); - printk("\t%s%i: status at 0x%lx: 0x%x\n", - WD_OBPNAME, - i, - (unsigned long)(&wd_dev.watchdog[i].regs->status), - readb(&wd_dev.watchdog[i].regs->status)); - printk("\t%s%i: driver status: 0x%x\n", - WD_OBPNAME, - i, - wd_getstatus(&wd_dev.watchdog[i])); - } - printk("\tintr_mask at %p: 0x%x\n", - wd_dev.regs + PLD_IMASK, - readb(wd_dev.regs + PLD_IMASK)); - printk("\tpld_status at %p: 0x%x\n", - wd_dev.regs + PLD_STATUS, - readb(wd_dev.regs + PLD_STATUS)); -} -#endif - -/* Enable or disable watchdog interrupts - * Because of the CP1400 defect this should only be - * called during initialzation or by wd_[start|stop]timer() - * - * pTimer - pointer to timer device, or NULL to indicate all timers - * enable - non-zero to enable interrupts, zero to disable - */ -static void wd_toggleintr(struct wd_timer* pTimer, int enable) -{ - unsigned char curregs = wd_readb(wd_dev.regs + PLD_IMASK); - unsigned char setregs = - (NULL == pTimer) ? - (WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) : - (pTimer->intr_mask); - - (WD_INTR_ON == enable) ? - (curregs &= ~setregs): - (curregs |= setregs); + struct device_node *options; + const char *str_prop; + const void *prop_val; + int i, err = -EINVAL; + struct cpwd *p; - wd_writeb(curregs, wd_dev.regs + PLD_IMASK); - return; -} + if (cpwd_device) + return -EINVAL; -/* Reset countdown timer with 'limit' value and continue countdown. - * This will not start a stopped timer. - * - * pTimer - pointer to timer device - */ -static void wd_pingtimer(struct wd_timer* pTimer) -{ - if (wd_readb(pTimer->regs + WD_STATUS) & WD_S_RUNNING) { - wd_readw(pTimer->regs + WD_DCNTR); + p = kzalloc(sizeof(*p), GFP_KERNEL); + err = -ENOMEM; + if (!p) { + printk(KERN_ERR PFX "Unable to allocate struct cpwd.\n"); + goto out; } -} -/* Stop a running watchdog timer-- the timer actually keeps - * running, but the interrupt is masked so that no action is - * taken upon expiration. - * - * pTimer - pointer to timer device - */ -static void wd_stoptimer(struct wd_timer* pTimer) -{ - if(wd_readb(pTimer->regs + WD_STATUS) & WD_S_RUNNING) { - wd_toggleintr(pTimer, WD_INTR_OFF); + p->irq = op->irqs[0]; - if(wd_dev.isbaddoggie) { - pTimer->runstatus |= WD_STAT_BSTOP; - wd_brokentimer((unsigned long)&wd_dev); - } - } -} + spin_lock_init(&p->lock); -/* Start a watchdog timer with the specified limit value - * If the watchdog is running, it will be restarted with - * the provided limit value. - * - * This function will enable interrupts on the specified - * watchdog. - * - * pTimer - pointer to timer device - * limit - limit (countdown) value in 1/10th seconds - */ -static void wd_starttimer(struct wd_timer* pTimer) -{ - if(wd_dev.isbaddoggie) { - pTimer->runstatus &= ~WD_STAT_BSTOP; + p->regs = of_ioremap(&op->resource[0], 0, + 4 * WD_TIMER_REGSZ, DRIVER_NAME); + if (!p->regs) { + printk(KERN_ERR PFX "Unable to map registers.\n"); + goto out_free; } - pTimer->runstatus &= ~WD_STAT_SVCD; - wd_writew(pTimer->timeout, pTimer->regs + WD_LIMIT); - wd_toggleintr(pTimer, WD_INTR_ON); -} + options = of_find_node_by_path("/options"); + err = -ENODEV; + if (!options) { + printk(KERN_ERR PFX "Unable to find /options node.\n"); + goto out_iounmap; + } -/* Restarts timer with maximum limit value and - * does not unset 'brokenstop' value. - */ -static void wd_resetbrokentimer(struct wd_timer* pTimer) -{ - wd_toggleintr(pTimer, WD_INTR_ON); - wd_writew(WD_BLIMIT, pTimer->regs + WD_LIMIT); -} + prop_val = of_get_property(options, "watchdog-enable?", NULL); + p->enabled = (prop_val ? true : false); -/* Timer device initialization helper. - * Returns 0 on success, other on failure - */ -static int wd_inittimer(int whichdog) -{ - struct miscdevice *whichmisc; - void __iomem *whichregs; - char whichident[8]; - int whichmask; - __u16 whichlimit; + prop_val = of_get_property(options, "watchdog-reboot?", NULL); + p->reboot = (prop_val ? true : false); - switch(whichdog) - { - case WD0_ID: - whichmisc = &wd0_miscdev; - strcpy(whichident, "RIC"); - whichregs = wd_dev.regs + WD0_OFF; - whichmask = WD0_INTR_MASK; - whichlimit= (0 == wd0_timeout) ? - (wd_dev.opt_timeout): - (wd0_timeout); - break; - case WD1_ID: - whichmisc = &wd1_miscdev; - strcpy(whichident, "XIR"); - whichregs = wd_dev.regs + WD1_OFF; - whichmask = WD1_INTR_MASK; - whichlimit= (0 == wd1_timeout) ? - (wd_dev.opt_timeout): - (wd1_timeout); - break; - case WD2_ID: - whichmisc = &wd2_miscdev; - strcpy(whichident, "POR"); - whichregs = wd_dev.regs + WD2_OFF; - whichmask = WD2_INTR_MASK; - whichlimit= (0 == wd2_timeout) ? - (wd_dev.opt_timeout): - (wd2_timeout); - break; - default: - printk("%s: %s: invalid watchdog id: %i\n", - WD_OBPNAME, __func__, whichdog); - return(1); - } - if(0 != misc_register(whichmisc)) - { - return(1); - } - wd_dev.watchdog[whichdog].regs = whichregs; - wd_dev.watchdog[whichdog].timeout = whichlimit; - wd_dev.watchdog[whichdog].intr_mask = whichmask; - wd_dev.watchdog[whichdog].runstatus &= ~WD_STAT_BSTOP; - wd_dev.watchdog[whichdog].runstatus |= WD_STAT_INIT; - - printk("%s%i: %s hardware watchdog [%01i.%i sec] %s\n", - WD_OBPNAME, - whichdog, - whichident, - wd_dev.watchdog[whichdog].timeout / 10, - wd_dev.watchdog[whichdog].timeout % 10, - (0 != wd_dev.opt_enable) ? "in ENABLED mode" : ""); - return(0); -} + str_prop = of_get_property(options, "watchdog-timeout", NULL); + if (str_prop) + p->timeout = simple_strtoul(str_prop, NULL, 10); -/* Timer method called to reset stopped watchdogs-- - * because of the PLD bug on CP1400, we cannot mask - * interrupts within the PLD so me must continually - * reset the timers ad infinitum. - */ -static void wd_brokentimer(unsigned long data) -{ - struct wd_device* pDev = (struct wd_device*)data; - int id, tripped = 0; - - /* kill a running timer instance, in case we - * were called directly instead of by kernel timer + /* CP1400s seem to have broken PLD implementations-- the + * interrupt_mask register cannot be written, so no timer + * interrupts can be masked within the PLD. */ - if(timer_pending(&wd_timer)) { - del_timer(&wd_timer); - } - - for(id = WD0_ID; id < WD_NUMDEVS; ++id) { - if(pDev->watchdog[id].runstatus & WD_STAT_BSTOP) { - ++tripped; - wd_resetbrokentimer(&pDev->watchdog[id]); + str_prop = of_get_property(op->node, "model", NULL); + p->broken = (str_prop && !strcmp(str_prop, WD_BADMODEL)); + + if (!p->enabled) + cpwd_toggleintr(p, -1, WD_INTR_OFF); + + for (i = 0; i < WD_NUMDEVS; i++) { + static const char *cpwd_names[] = { "RIC", "XIR", "POR" }; + static int *parms[] = { &wd0_timeout, + &wd1_timeout, + &wd2_timeout }; + struct miscdevice *mp = &p->devs[i].misc; + + mp->minor = WD0_MINOR + i; + mp->name = cpwd_names[i]; + mp->fops = &cpwd_fops; + + p->devs[i].regs = p->regs + (i * WD_TIMER_REGSZ); + p->devs[i].intr_mask = (WD0_INTR_MASK << i); + p->devs[i].runstatus &= ~WD_STAT_BSTOP; + p->devs[i].runstatus |= WD_STAT_INIT; + p->devs[i].timeout = p->timeout; + if (*parms[i]) + p->devs[i].timeout = *parms[i]; + + err = misc_register(&p->devs[i].misc); + if (err) { + printk(KERN_ERR "Could not register misc device for " + "dev %d\n", i); + goto out_unregister; } } - if(tripped) { - /* there is at least one timer brokenstopped-- reschedule */ - init_timer(&wd_timer); - wd_timer.expires = WD_BTIMEOUT; - add_timer(&wd_timer); + if (p->broken) { + init_timer(&cpwd_timer); + cpwd_timer.function = cpwd_brokentimer; + cpwd_timer.data = (unsigned long) p; + cpwd_timer.expires = WD_BTIMEOUT; + + printk(KERN_INFO PFX "PLD defect workaround enabled for " + "model " WD_BADMODEL ".\n"); } -} -static int wd_getstatus(struct wd_timer* pTimer) -{ - unsigned char stat = wd_readb(pTimer->regs + WD_STATUS); - unsigned char intr = wd_readb(wd_dev.regs + PLD_IMASK); - unsigned char ret = WD_STOPPED; + dev_set_drvdata(&op->dev, p); + cpwd_device = p; + err = 0; - /* determine STOPPED */ - if(0 == stat ) { - return(ret); - } - /* determine EXPIRED vs FREERUN vs RUNNING */ - else if(WD_S_EXPIRED & stat) { - ret = WD_EXPIRED; - } - else if(WD_S_RUNNING & stat) { - if(intr & pTimer->intr_mask) { - ret = WD_FREERUN; - } - else { - /* Fudge WD_EXPIRED status for defective CP1400-- - * IF timer is running - * AND brokenstop is set - * AND an interrupt has been serviced - * we are WD_EXPIRED. - * - * IF timer is running - * AND brokenstop is set - * AND no interrupt has been serviced - * we are WD_FREERUN. - */ - if(wd_dev.isbaddoggie && (pTimer->runstatus & WD_STAT_BSTOP)) { - if(pTimer->runstatus & WD_STAT_SVCD) { - ret = WD_EXPIRED; - } - else { - /* we could as well pretend we are expired */ - ret = WD_FREERUN; - } - } - else { - ret = WD_RUNNING; - } - } - } +out: + return err; - /* determine SERVICED */ - if(pTimer->runstatus & WD_STAT_SVCD) { - ret |= WD_SERVICED; - } +out_unregister: + for (i--; i >= 0; i--) + misc_deregister(&p->devs[i].misc); - return(ret); +out_iounmap: + of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ); + +out_free: + kfree(p); + goto out; } -static int __init wd_init(void) +static int __devexit cpwd_remove(struct of_device *op) { - int id; - struct linux_ebus *ebus = NULL; - struct linux_ebus_device *edev = NULL; - - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->ofdev.node->name, WD_OBPNAME)) - goto ebus_done; + struct cpwd *p = dev_get_drvdata(&op->dev); + int i; + + for (i = 0; i < 4; i++) { + misc_deregister(&p->devs[i].misc); + + if (!p->enabled) { + cpwd_stoptimer(p, i); + if (p->devs[i].runstatus & WD_STAT_BSTOP) + cpwd_resetbrokentimer(p, i); } } -ebus_done: - if(!edev) { - printk("%s: unable to locate device\n", WD_OBPNAME); - return -ENODEV; - } + if (p->broken) + del_timer_sync(&cpwd_timer); - wd_dev.regs = - ioremap(edev->resource[0].start, 4 * WD_TIMER_REGSZ); /* ? */ + if (p->initialized) + free_irq(p->irq, p); - if(NULL == wd_dev.regs) { - printk("%s: unable to map registers\n", WD_OBPNAME); - return(-ENODEV); - } + of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ); + kfree(p); - /* initialize device structure from OBP parameters */ - wd_dev.irq = edev->irqs[0]; - wd_dev.opt_enable = wd_opt_enable(); - wd_dev.opt_reboot = wd_opt_reboot(); - wd_dev.opt_timeout = wd_opt_timeout(); - wd_dev.isbaddoggie = wd_isbroken(); + cpwd_device = NULL; - /* disable all interrupts unless watchdog-enabled? == true */ - if(! wd_dev.opt_enable) { - wd_toggleintr(NULL, WD_INTR_OFF); - } + return 0; +} - /* register miscellaneous devices */ - for(id = WD0_ID; id < WD_NUMDEVS; ++id) { - if(0 != wd_inittimer(id)) { - printk("%s%i: unable to initialize\n", WD_OBPNAME, id); - } - } +static struct of_device_id cpwd_match[] = { + { + .name = "watchdog", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, cpwd_match); - /* warn about possible defective PLD */ - if(wd_dev.isbaddoggie) { - init_timer(&wd_timer); - wd_timer.function = wd_brokentimer; - wd_timer.data = (unsigned long)&wd_dev; - wd_timer.expires = WD_BTIMEOUT; +static struct of_platform_driver cpwd_driver = { + .name = DRIVER_NAME, + .match_table = cpwd_match, + .probe = cpwd_probe, + .remove = __devexit_p(cpwd_remove), +}; - printk("%s: PLD defect workaround enabled for model %s\n", - WD_OBPNAME, WD_BADMODEL); - } - return(0); +static int __init cpwd_init(void) +{ + return of_register_driver(&cpwd_driver, &of_bus_type); } -static void __exit wd_cleanup(void) +static void __exit cpwd_exit(void) { - int id; - - /* if 'watchdog-enable?' == TRUE, timers are not stopped - * when module is unloaded. All brokenstopped timers will - * also now eventually trip. - */ - for(id = WD0_ID; id < WD_NUMDEVS; ++id) { - if(WD_S_RUNNING == wd_readb(wd_dev.watchdog[id].regs + WD_STATUS)) { - if(wd_dev.opt_enable) { - printk(KERN_WARNING "%s%i: timer not stopped at release\n", - WD_OBPNAME, id); - } - else { - wd_stoptimer(&wd_dev.watchdog[id]); - if(wd_dev.watchdog[id].runstatus & WD_STAT_BSTOP) { - wd_resetbrokentimer(&wd_dev.watchdog[id]); - printk(KERN_WARNING - "%s%i: defect workaround disabled at release, "\ - "timer expires in ~%01i sec\n", - WD_OBPNAME, id, - wd_readw(wd_dev.watchdog[id].regs + WD_LIMIT) / 10); - } - } - } - } - - if(wd_dev.isbaddoggie && timer_pending(&wd_timer)) { - del_timer(&wd_timer); - } - if(0 != (wd_dev.watchdog[WD0_ID].runstatus & WD_STAT_INIT)) { - misc_deregister(&wd0_miscdev); - } - if(0 != (wd_dev.watchdog[WD1_ID].runstatus & WD_STAT_INIT)) { - misc_deregister(&wd1_miscdev); - } - if(0 != (wd_dev.watchdog[WD2_ID].runstatus & WD_STAT_INIT)) { - misc_deregister(&wd2_miscdev); - } - if(0 != wd_dev.initialized) { - free_irq(wd_dev.irq, (void *)wd_dev.regs); - } - iounmap(wd_dev.regs); + of_unregister_driver(&cpwd_driver); } -module_init(wd_init); -module_exit(wd_cleanup); +module_init(cpwd_init); +module_exit(cpwd_exit); -- cgit v1.2.3 From 8ab0dc333eacb2249c63d1fc7c5241299fa0493f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 29 Aug 2008 17:07:01 -0700 Subject: cpwatchdog: Move to drivers/watchdog/cpwd.c Signed-off-by: David S. Miller --- drivers/sbus/char/Makefile | 1 - drivers/sbus/char/cpwatchdog.c | 695 ----------------------------------------- 2 files changed, 696 deletions(-) delete mode 100644 drivers/sbus/char/cpwatchdog.c (limited to 'drivers/sbus') diff --git a/drivers/sbus/char/Makefile b/drivers/sbus/char/Makefile index b29c186b695..d83212ec541 100644 --- a/drivers/sbus/char/Makefile +++ b/drivers/sbus/char/Makefile @@ -11,7 +11,6 @@ bbc-objs := bbc_i2c.o bbc_envctrl.o obj-$(CONFIG_ENVCTRL) += envctrl.o obj-$(CONFIG_DISPLAY7SEG) += display7seg.o -obj-$(CONFIG_WATCHDOG_CP1XXX) += cpwatchdog.o obj-$(CONFIG_OBP_FLASH) += flash.o obj-$(CONFIG_SUN_OPENPROMIO) += openprom.o obj-$(CONFIG_SUN_MOSTEK_RTC) += rtc.o diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c deleted file mode 100644 index c88df62e705..00000000000 --- a/drivers/sbus/char/cpwatchdog.c +++ /dev/null @@ -1,695 +0,0 @@ -/* cpwatchdog.c - driver implementation for hardware watchdog - * timers found on Sun Microsystems CP1400 and CP1500 boards. - * - * This device supports both the generic Linux watchdog - * interface and Solaris-compatible ioctls as best it is - * able. - * - * NOTE: CP1400 systems appear to have a defective intr_mask - * register on the PLD, preventing the disabling of - * timer interrupts. We use a timer to periodically - * reset 'stopped' watchdogs on affected platforms. - * - * Copyright (c) 2000 Eric Brower (ebrower@usa.net) - * Copyright (C) 2008 David S. Miller - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#define DRIVER_NAME "cpwd" -#define PFX DRIVER_NAME ": " - -#define WD_OBPNAME "watchdog" -#define WD_BADMODEL "SUNW,501-5336" -#define WD_BTIMEOUT (jiffies + (HZ * 1000)) -#define WD_BLIMIT 0xFFFF - -#define WD0_MINOR 212 -#define WD1_MINOR 213 -#define WD2_MINOR 214 - -/* Internal driver definitions. */ -#define WD0_ID 0 -#define WD1_ID 1 -#define WD2_ID 2 -#define WD_NUMDEVS 3 - -#define WD_INTR_OFF 0 -#define WD_INTR_ON 1 - -#define WD_STAT_INIT 0x01 /* Watchdog timer is initialized */ -#define WD_STAT_BSTOP 0x02 /* Watchdog timer is brokenstopped */ -#define WD_STAT_SVCD 0x04 /* Watchdog interrupt occurred */ - -/* Register value definitions - */ -#define WD0_INTR_MASK 0x01 /* Watchdog device interrupt masks */ -#define WD1_INTR_MASK 0x02 -#define WD2_INTR_MASK 0x04 - -#define WD_S_RUNNING 0x01 /* Watchdog device status running */ -#define WD_S_EXPIRED 0x02 /* Watchdog device status expired */ - -struct cpwd { - void __iomem *regs; - spinlock_t lock; - - unsigned int irq; - - unsigned long timeout; - bool enabled; - bool reboot; - bool broken; - bool initialized; - - struct { - struct miscdevice misc; - void __iomem *regs; - u8 intr_mask; - u8 runstatus; - u16 timeout; - } devs[WD_NUMDEVS]; -}; - -static struct cpwd *cpwd_device; - -/* Sun uses Altera PLD EPF8820ATC144-4 - * providing three hardware watchdogs: - * - * 1) RIC - sends an interrupt when triggered - * 2) XIR - asserts XIR_B_RESET when triggered, resets CPU - * 3) POR - asserts POR_B_RESET when triggered, resets CPU, backplane, board - * - *** Timer register block definition (struct wd_timer_regblk) - * - * dcntr and limit registers (halfword access): - * ------------------- - * | 15 | ...| 1 | 0 | - * ------------------- - * |- counter val -| - * ------------------- - * dcntr - Current 16-bit downcounter value. - * When downcounter reaches '0' watchdog expires. - * Reading this register resets downcounter with 'limit' value. - * limit - 16-bit countdown value in 1/10th second increments. - * Writing this register begins countdown with input value. - * Reading from this register does not affect counter. - * NOTES: After watchdog reset, dcntr and limit contain '1' - * - * status register (byte access): - * --------------------------- - * | 7 | ... | 2 | 1 | 0 | - * --------------+------------ - * |- UNUSED -| EXP | RUN | - * --------------------------- - * status- Bit 0 - Watchdog is running - * Bit 1 - Watchdog has expired - * - *** PLD register block definition (struct wd_pld_regblk) - * - * intr_mask register (byte access): - * --------------------------------- - * | 7 | ... | 3 | 2 | 1 | 0 | - * +-------------+------------------ - * |- UNUSED -| WD3 | WD2 | WD1 | - * --------------------------------- - * WD3 - 1 == Interrupt disabled for watchdog 3 - * WD2 - 1 == Interrupt disabled for watchdog 2 - * WD1 - 1 == Interrupt disabled for watchdog 1 - * - * pld_status register (byte access): - * UNKNOWN, MAGICAL MYSTERY REGISTER - * - */ -#define WD_TIMER_REGSZ 16 -#define WD0_OFF 0 -#define WD1_OFF (WD_TIMER_REGSZ * 1) -#define WD2_OFF (WD_TIMER_REGSZ * 2) -#define PLD_OFF (WD_TIMER_REGSZ * 3) - -#define WD_DCNTR 0x00 -#define WD_LIMIT 0x04 -#define WD_STATUS 0x08 - -#define PLD_IMASK (PLD_OFF + 0x00) -#define PLD_STATUS (PLD_OFF + 0x04) - -static struct timer_list cpwd_timer; - -static int wd0_timeout = 0; -static int wd1_timeout = 0; -static int wd2_timeout = 0; - -module_param (wd0_timeout, int, 0); -MODULE_PARM_DESC(wd0_timeout, "Default watchdog0 timeout in 1/10secs"); -module_param (wd1_timeout, int, 0); -MODULE_PARM_DESC(wd1_timeout, "Default watchdog1 timeout in 1/10secs"); -module_param (wd2_timeout, int, 0); -MODULE_PARM_DESC(wd2_timeout, "Default watchdog2 timeout in 1/10secs"); - -MODULE_AUTHOR("Eric Brower "); -MODULE_DESCRIPTION("Hardware watchdog driver for Sun Microsystems CP1400/1500"); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("watchdog"); - -static void cpwd_writew(u16 val, void __iomem *addr) -{ - writew(cpu_to_le16(val), addr); -} -static u16 cpwd_readw(void __iomem *addr) -{ - u16 val = readw(addr); - - return le16_to_cpu(val); -} - -static void cpwd_writeb(u8 val, void __iomem *addr) -{ - writeb(val, addr); -} - -static u8 cpwd_readb(void __iomem *addr) -{ - return readb(addr); -} - -/* Enable or disable watchdog interrupts - * Because of the CP1400 defect this should only be - * called during initialzation or by wd_[start|stop]timer() - * - * index - sub-device index, or -1 for 'all' - * enable - non-zero to enable interrupts, zero to disable - */ -static void cpwd_toggleintr(struct cpwd *p, int index, int enable) -{ - unsigned char curregs = cpwd_readb(p->regs + PLD_IMASK); - unsigned char setregs = - (index == -1) ? - (WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) : - (p->devs[index].intr_mask); - - if (enable == WD_INTR_ON) - curregs &= ~setregs; - else - curregs |= setregs; - - cpwd_writeb(curregs, p->regs + PLD_IMASK); -} - -/* Restarts timer with maximum limit value and - * does not unset 'brokenstop' value. - */ -static void cpwd_resetbrokentimer(struct cpwd *p, int index) -{ - cpwd_toggleintr(p, index, WD_INTR_ON); - cpwd_writew(WD_BLIMIT, p->devs[index].regs + WD_LIMIT); -} - -/* Timer method called to reset stopped watchdogs-- - * because of the PLD bug on CP1400, we cannot mask - * interrupts within the PLD so me must continually - * reset the timers ad infinitum. - */ -static void cpwd_brokentimer(unsigned long data) -{ - struct cpwd *p = (struct cpwd *) data; - int id, tripped = 0; - - /* kill a running timer instance, in case we - * were called directly instead of by kernel timer - */ - if (timer_pending(&cpwd_timer)) - del_timer(&cpwd_timer); - - for (id = 0; id < WD_NUMDEVS; id++) { - if (p->devs[id].runstatus & WD_STAT_BSTOP) { - ++tripped; - cpwd_resetbrokentimer(p, id); - } - } - - if (tripped) { - /* there is at least one timer brokenstopped-- reschedule */ - cpwd_timer.expires = WD_BTIMEOUT; - add_timer(&cpwd_timer); - } -} - -/* Reset countdown timer with 'limit' value and continue countdown. - * This will not start a stopped timer. - */ -static void cpwd_pingtimer(struct cpwd *p, int index) -{ - if (cpwd_readb(p->devs[index].regs + WD_STATUS) & WD_S_RUNNING) - cpwd_readw(p->devs[index].regs + WD_DCNTR); -} - -/* Stop a running watchdog timer-- the timer actually keeps - * running, but the interrupt is masked so that no action is - * taken upon expiration. - */ -static void cpwd_stoptimer(struct cpwd *p, int index) -{ - if (cpwd_readb(p->devs[index].regs + WD_STATUS) & WD_S_RUNNING) { - cpwd_toggleintr(p, index, WD_INTR_OFF); - - if (p->broken) { - p->devs[index].runstatus |= WD_STAT_BSTOP; - cpwd_brokentimer((unsigned long) p); - } - } -} - -/* Start a watchdog timer with the specified limit value - * If the watchdog is running, it will be restarted with - * the provided limit value. - * - * This function will enable interrupts on the specified - * watchdog. - */ -static void cpwd_starttimer(struct cpwd *p, int index) -{ - if (p->broken) - p->devs[index].runstatus &= ~WD_STAT_BSTOP; - - p->devs[index].runstatus &= ~WD_STAT_SVCD; - - cpwd_writew(p->devs[index].timeout, p->devs[index].regs + WD_LIMIT); - cpwd_toggleintr(p, index, WD_INTR_ON); -} - -static int cpwd_getstatus(struct cpwd *p, int index) -{ - unsigned char stat = cpwd_readb(p->devs[index].regs + WD_STATUS); - unsigned char intr = cpwd_readb(p->devs[index].regs + PLD_IMASK); - unsigned char ret = WD_STOPPED; - - /* determine STOPPED */ - if (!stat) - return ret; - - /* determine EXPIRED vs FREERUN vs RUNNING */ - else if (WD_S_EXPIRED & stat) { - ret = WD_EXPIRED; - } else if(WD_S_RUNNING & stat) { - if (intr & p->devs[index].intr_mask) { - ret = WD_FREERUN; - } else { - /* Fudge WD_EXPIRED status for defective CP1400-- - * IF timer is running - * AND brokenstop is set - * AND an interrupt has been serviced - * we are WD_EXPIRED. - * - * IF timer is running - * AND brokenstop is set - * AND no interrupt has been serviced - * we are WD_FREERUN. - */ - if (p->broken && - (p->devs[index].runstatus & WD_STAT_BSTOP)) { - if (p->devs[index].runstatus & WD_STAT_SVCD) { - ret = WD_EXPIRED; - } else { - /* we could as well pretend we are expired */ - ret = WD_FREERUN; - } - } else { - ret = WD_RUNNING; - } - } - } - - /* determine SERVICED */ - if (p->devs[index].runstatus & WD_STAT_SVCD) - ret |= WD_SERVICED; - - return(ret); -} - -static irqreturn_t cpwd_interrupt(int irq, void *dev_id) -{ - struct cpwd *p = dev_id; - - /* Only WD0 will interrupt-- others are NMI and we won't - * see them here.... - */ - spin_lock_irq(&p->lock); - - cpwd_stoptimer(p, WD0_ID); - p->devs[WD0_ID].runstatus |= WD_STAT_SVCD; - - spin_unlock_irq(&p->lock); - - return IRQ_HANDLED; -} - -static int cpwd_open(struct inode *inode, struct file *f) -{ - struct cpwd *p = cpwd_device; - - lock_kernel(); - switch(iminor(inode)) { - case WD0_MINOR: - case WD1_MINOR: - case WD2_MINOR: - break; - - default: - unlock_kernel(); - return -ENODEV; - } - - /* Register IRQ on first open of device */ - if (!p->initialized) { - if (request_irq(p->irq, &cpwd_interrupt, - IRQF_SHARED, DRIVER_NAME, p)) { - printk(KERN_ERR PFX "Cannot register IRQ %d\n", - p->irq); - unlock_kernel(); - return -EBUSY; - } - p->initialized = true; - } - - unlock_kernel(); - - return nonseekable_open(inode, f); -} - -static int cpwd_release(struct inode *inode, struct file *file) -{ - return 0; -} - -static int cpwd_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - static struct watchdog_info info = { - .options = WDIOF_SETTIMEOUT, - .firmware_version = 1, - .identity = DRIVER_NAME, - }; - void __user *argp = (void __user *)arg; - int index = iminor(inode) - WD0_MINOR; - struct cpwd *p = cpwd_device; - int setopt = 0; - - switch (cmd) { - /* Generic Linux IOCTLs */ - case WDIOC_GETSUPPORT: - if (copy_to_user(argp, &info, sizeof(struct watchdog_info))) - return -EFAULT; - break; - - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - if (put_user(0, (int __user *)argp)) - return -EFAULT; - break; - - case WDIOC_KEEPALIVE: - cpwd_pingtimer(p, index); - break; - - case WDIOC_SETOPTIONS: - if (copy_from_user(&setopt, argp, sizeof(unsigned int))) - return -EFAULT; - - if (setopt & WDIOS_DISABLECARD) { - if (p->enabled) - return -EINVAL; - cpwd_stoptimer(p, index); - } else if (setopt & WDIOS_ENABLECARD) { - cpwd_starttimer(p, index); - } else { - return -EINVAL; - } - break; - - /* Solaris-compatible IOCTLs */ - case WIOCGSTAT: - setopt = cpwd_getstatus(p, index); - if (copy_to_user(argp, &setopt, sizeof(unsigned int))) - return -EFAULT; - break; - - case WIOCSTART: - cpwd_starttimer(p, index); - break; - - case WIOCSTOP: - if (p->enabled) - return(-EINVAL); - - cpwd_stoptimer(p, index); - break; - - default: - return -EINVAL; - } - - return 0; -} - -static long cpwd_compat_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - int rval = -ENOIOCTLCMD; - - switch (cmd) { - /* solaris ioctls are specific to this driver */ - case WIOCSTART: - case WIOCSTOP: - case WIOCGSTAT: - lock_kernel(); - rval = cpwd_ioctl(file->f_path.dentry->d_inode, file, cmd, arg); - unlock_kernel(); - break; - - /* everything else is handled by the generic compat layer */ - default: - break; - } - - return rval; -} - -static ssize_t cpwd_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct inode *inode = file->f_path.dentry->d_inode; - struct cpwd *p = cpwd_device; - int index = iminor(inode); - - if (count) { - cpwd_pingtimer(p, index); - return 1; - } - - return 0; -} - -static ssize_t cpwd_read(struct file * file, char __user *buffer, - size_t count, loff_t *ppos) -{ - return -EINVAL; -} - -static const struct file_operations cpwd_fops = { - .owner = THIS_MODULE, - .ioctl = cpwd_ioctl, - .compat_ioctl = cpwd_compat_ioctl, - .open = cpwd_open, - .write = cpwd_write, - .read = cpwd_read, - .release = cpwd_release, -}; - -static int __devinit cpwd_probe(struct of_device *op, - const struct of_device_id *match) -{ - struct device_node *options; - const char *str_prop; - const void *prop_val; - int i, err = -EINVAL; - struct cpwd *p; - - if (cpwd_device) - return -EINVAL; - - p = kzalloc(sizeof(*p), GFP_KERNEL); - err = -ENOMEM; - if (!p) { - printk(KERN_ERR PFX "Unable to allocate struct cpwd.\n"); - goto out; - } - - p->irq = op->irqs[0]; - - spin_lock_init(&p->lock); - - p->regs = of_ioremap(&op->resource[0], 0, - 4 * WD_TIMER_REGSZ, DRIVER_NAME); - if (!p->regs) { - printk(KERN_ERR PFX "Unable to map registers.\n"); - goto out_free; - } - - options = of_find_node_by_path("/options"); - err = -ENODEV; - if (!options) { - printk(KERN_ERR PFX "Unable to find /options node.\n"); - goto out_iounmap; - } - - prop_val = of_get_property(options, "watchdog-enable?", NULL); - p->enabled = (prop_val ? true : false); - - prop_val = of_get_property(options, "watchdog-reboot?", NULL); - p->reboot = (prop_val ? true : false); - - str_prop = of_get_property(options, "watchdog-timeout", NULL); - if (str_prop) - p->timeout = simple_strtoul(str_prop, NULL, 10); - - /* CP1400s seem to have broken PLD implementations-- the - * interrupt_mask register cannot be written, so no timer - * interrupts can be masked within the PLD. - */ - str_prop = of_get_property(op->node, "model", NULL); - p->broken = (str_prop && !strcmp(str_prop, WD_BADMODEL)); - - if (!p->enabled) - cpwd_toggleintr(p, -1, WD_INTR_OFF); - - for (i = 0; i < WD_NUMDEVS; i++) { - static const char *cpwd_names[] = { "RIC", "XIR", "POR" }; - static int *parms[] = { &wd0_timeout, - &wd1_timeout, - &wd2_timeout }; - struct miscdevice *mp = &p->devs[i].misc; - - mp->minor = WD0_MINOR + i; - mp->name = cpwd_names[i]; - mp->fops = &cpwd_fops; - - p->devs[i].regs = p->regs + (i * WD_TIMER_REGSZ); - p->devs[i].intr_mask = (WD0_INTR_MASK << i); - p->devs[i].runstatus &= ~WD_STAT_BSTOP; - p->devs[i].runstatus |= WD_STAT_INIT; - p->devs[i].timeout = p->timeout; - if (*parms[i]) - p->devs[i].timeout = *parms[i]; - - err = misc_register(&p->devs[i].misc); - if (err) { - printk(KERN_ERR "Could not register misc device for " - "dev %d\n", i); - goto out_unregister; - } - } - - if (p->broken) { - init_timer(&cpwd_timer); - cpwd_timer.function = cpwd_brokentimer; - cpwd_timer.data = (unsigned long) p; - cpwd_timer.expires = WD_BTIMEOUT; - - printk(KERN_INFO PFX "PLD defect workaround enabled for " - "model " WD_BADMODEL ".\n"); - } - - dev_set_drvdata(&op->dev, p); - cpwd_device = p; - err = 0; - -out: - return err; - -out_unregister: - for (i--; i >= 0; i--) - misc_deregister(&p->devs[i].misc); - -out_iounmap: - of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ); - -out_free: - kfree(p); - goto out; -} - -static int __devexit cpwd_remove(struct of_device *op) -{ - struct cpwd *p = dev_get_drvdata(&op->dev); - int i; - - for (i = 0; i < 4; i++) { - misc_deregister(&p->devs[i].misc); - - if (!p->enabled) { - cpwd_stoptimer(p, i); - if (p->devs[i].runstatus & WD_STAT_BSTOP) - cpwd_resetbrokentimer(p, i); - } - } - - if (p->broken) - del_timer_sync(&cpwd_timer); - - if (p->initialized) - free_irq(p->irq, p); - - of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ); - kfree(p); - - cpwd_device = NULL; - - return 0; -} - -static struct of_device_id cpwd_match[] = { - { - .name = "watchdog", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, cpwd_match); - -static struct of_platform_driver cpwd_driver = { - .name = DRIVER_NAME, - .match_table = cpwd_match, - .probe = cpwd_probe, - .remove = __devexit_p(cpwd_remove), -}; - -static int __init cpwd_init(void) -{ - return of_register_driver(&cpwd_driver, &of_bus_type); -} - -static void __exit cpwd_exit(void) -{ - of_unregister_driver(&cpwd_driver); -} - -module_init(cpwd_init); -module_exit(cpwd_exit); -- cgit v1.2.3 From 95d4390579e02e168a14f19506fbadd30daffced Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 29 Aug 2008 18:01:58 -0700 Subject: display7seg: Convert to pure OF device driver. Signed-off-by: David S. Miller --- drivers/sbus/char/display7seg.c | 251 +++++++++++++++++++++++----------------- 1 file changed, 146 insertions(+), 105 deletions(-) (limited to 'drivers/sbus') diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c index d8f5c0ca236..2f16d78e92d 100644 --- a/drivers/sbus/char/display7seg.c +++ b/drivers/sbus/char/display7seg.c @@ -1,10 +1,7 @@ -/* $Id: display7seg.c,v 1.6 2002/01/08 16:00:16 davem Exp $ - * - * display7seg - Driver implementation for the 7-segment display - * present on Sun Microsystems CP1400 and CP1500 +/* display7seg.c - Driver implementation for the 7-segment display + * present on Sun Microsystems CP1400 and CP1500 * * Copyright (c) 2000 Eric Brower (ebrower@usa.net) - * */ #include @@ -16,22 +13,20 @@ #include #include /* request_region */ #include +#include +#include #include -#include /* EBus device */ -#include /* OpenProm Library */ #include /* put_/get_user */ #include #include #define D7S_MINOR 193 -#define D7S_OBPNAME "display7seg" -#define D7S_DEVNAME "d7s" +#define DRIVER_NAME "d7s" +#define PFX DRIVER_NAME ": " static int sol_compat = 0; /* Solaris compatibility mode */ -#ifdef MODULE - /* Solaris compatibility flag - * The Solaris implementation omits support for several * documented driver features (ref Sun doc 806-0180-03). @@ -46,20 +41,20 @@ static int sol_compat = 0; /* Solaris compatibility mode */ * If you wish the device to operate as under Solaris, * omitting above features, set this parameter to non-zero. */ -module_param - (sol_compat, int, 0); -MODULE_PARM_DESC - (sol_compat, - "Disables documented functionality omitted from Solaris driver"); - -MODULE_AUTHOR - ("Eric Brower "); -MODULE_DESCRIPTION - ("7-Segment Display driver for Sun Microsystems CP1400/1500"); +module_param(sol_compat, int, 0); +MODULE_PARM_DESC(sol_compat, + "Disables documented functionality omitted from Solaris driver"); + +MODULE_AUTHOR("Eric Brower "); +MODULE_DESCRIPTION("7-Segment Display driver for Sun Microsystems CP1400/1500"); MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE - ("d7s"); -#endif /* ifdef MODULE */ +MODULE_SUPPORTED_DEVICE("d7s"); + +struct d7s { + void __iomem *regs; + bool flipped; +}; +struct d7s *d7s_device; /* * Register block address- see header for details @@ -72,22 +67,6 @@ MODULE_SUPPORTED_DEVICE * FLIP - Inverts display for upside-down mounted board * bits 0-4 - 7-segment display contents */ -static void __iomem* d7s_regs; - -static inline void d7s_free(void) -{ - iounmap(d7s_regs); -} - -static inline int d7s_obpflipped(void) -{ - int opt_node; - - opt_node = prom_getchild(prom_root_node); - opt_node = prom_searchsiblings(opt_node, "options"); - return ((-1 != prom_getintdefault(opt_node, "d7s-flipped?", -1)) ? 0 : 1); -} - static atomic_t d7s_users = ATOMIC_INIT(0); static int d7s_open(struct inode *inode, struct file *f) @@ -106,12 +85,15 @@ static int d7s_release(struct inode *inode, struct file *f) * are not operating in solaris-compat mode */ if (atomic_dec_and_test(&d7s_users) && !sol_compat) { - int regval = 0; - - regval = readb(d7s_regs); - (0 == d7s_obpflipped()) ? - writeb(regval |= D7S_FLIP, d7s_regs): - writeb(regval &= ~D7S_FLIP, d7s_regs); + struct d7s *p = d7s_device; + u8 regval = 0; + + regval = readb(p->regs); + if (p->flipped) + regval |= D7S_FLIP; + else + regval &= ~D7S_FLIP; + writeb(regval, p->regs); } return 0; @@ -119,9 +101,10 @@ static int d7s_release(struct inode *inode, struct file *f) static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - __u8 regs = readb(d7s_regs); - __u8 ireg = 0; + struct d7s *p = d7s_device; + u8 regs = readb(p->regs); int error = 0; + u8 ireg = 0; if (D7S_MINOR != iminor(file->f_path.dentry->d_inode)) return -ENODEV; @@ -129,18 +112,20 @@ static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg) lock_kernel(); switch (cmd) { case D7SIOCWR: - /* assign device register values - * we mask-out D7S_FLIP if in sol_compat mode + /* assign device register values we mask-out D7S_FLIP + * if in sol_compat mode */ if (get_user(ireg, (int __user *) arg)) { error = -EFAULT; break; } - if (0 != sol_compat) { - (regs & D7S_FLIP) ? - (ireg |= D7S_FLIP) : (ireg &= ~D7S_FLIP); + if (sol_compat) { + if (regs & D7S_FLIP) + ireg |= D7S_FLIP; + else + ireg &= ~D7S_FLIP; } - writeb(ireg, d7s_regs); + writeb(ireg, p->regs); break; case D7SIOCRD: @@ -158,9 +143,11 @@ static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case D7SIOCTM: /* toggle device mode-- flip display orientation */ - (regs & D7S_FLIP) ? - (regs &= ~D7S_FLIP) : (regs |= D7S_FLIP); - writeb(regs, d7s_regs); + if (regs & D7S_FLIP) + regs &= ~D7S_FLIP; + else + regs |= D7S_FLIP; + writeb(regs, p->regs); break; }; unlock_kernel(); @@ -176,69 +163,123 @@ static const struct file_operations d7s_fops = { .release = d7s_release, }; -static struct miscdevice d7s_miscdev = { D7S_MINOR, D7S_DEVNAME, &d7s_fops }; +static struct miscdevice d7s_miscdev = { + .minor = D7S_MINOR, + .name = DRIVER_NAME, + .fops = &d7s_fops +}; -static int __init d7s_init(void) +static int __devinit d7s_probe(struct of_device *op, + const struct of_device_id *match) { - struct linux_ebus *ebus = NULL; - struct linux_ebus_device *edev = NULL; - int iTmp = 0, regs = 0; - - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_node->name, D7S_OBPNAME)) - goto ebus_done; - } + struct device_node *opts; + int err = -EINVAL; + struct d7s *p; + u8 regs; + + if (d7s_device) + goto out; + + p = kzalloc(sizeof(*p), GFP_KERNEL); + err = -ENOMEM; + if (!p) + goto out; + + p->regs = of_ioremap(&op->resource[0], 0, sizeof(u8), "d7s"); + if (!p->regs) { + printk(KERN_ERR PFX "Cannot map chip registers\n"); + goto out_free; } -ebus_done: - if(!edev) { - printk("%s: unable to locate device\n", D7S_DEVNAME); - return -ENODEV; + err = misc_register(&d7s_miscdev); + if (err) { + printk(KERN_ERR PFX "Unable to acquire miscdevice minor %i\n", + D7S_MINOR); + goto out_iounmap; } - d7s_regs = ioremap(edev->resource[0].start, sizeof(__u8)); - - iTmp = misc_register(&d7s_miscdev); - if (0 != iTmp) { - printk("%s: unable to acquire miscdevice minor %i\n", - D7S_DEVNAME, D7S_MINOR); - iounmap(d7s_regs); - return iTmp; - } - - /* OBP option "d7s-flipped?" is honored as default - * for the device, and reset default when detached + /* OBP option "d7s-flipped?" is honored as default for the + * device, and reset default when detached */ - regs = readb(d7s_regs); - iTmp = d7s_obpflipped(); - (0 == iTmp) ? - writeb(regs |= D7S_FLIP, d7s_regs): - writeb(regs &= ~D7S_FLIP, d7s_regs); - - printk("%s: 7-Segment Display%s at 0x%lx %s\n", - D7S_DEVNAME, - (0 == iTmp) ? (" (FLIPPED)") : (""), - edev->resource[0].start, - (0 != sol_compat) ? ("in sol_compat mode") : ("")); - - return 0; + regs = readb(p->regs); + opts = of_find_node_by_path("/options"); + if (opts && + of_get_property(opts, "d7s-flipped?", NULL)) + p->flipped = true; + + if (p->flipped) + regs |= D7S_FLIP; + else + regs &= ~D7S_FLIP; + + writeb(regs, p->regs); + + printk(KERN_INFO PFX "7-Segment Display%s at [%s:0x%lx] %s\n", + op->node->full_name, + (regs & D7S_FLIP) ? " (FLIPPED)" : "", + op->resource[0].start, + sol_compat ? "in sol_compat mode" : ""); + + dev_set_drvdata(&op->dev, p); + d7s_device = p; + err = 0; + +out: + return err; + +out_iounmap: + of_iounmap(&op->resource[0], p->regs, sizeof(u8)); + +out_free: + kfree(p); + goto out; } -static void __exit d7s_cleanup(void) +static int __devexit d7s_remove(struct of_device *op) { - int regs = readb(d7s_regs); + struct d7s *p = dev_get_drvdata(&op->dev); + u8 regs = readb(p->regs); /* Honor OBP d7s-flipped? unless operating in solaris-compat mode */ - if (0 == sol_compat) { - (0 == d7s_obpflipped()) ? - writeb(regs |= D7S_FLIP, d7s_regs): - writeb(regs &= ~D7S_FLIP, d7s_regs); + if (sol_compat) { + if (p->flipped) + regs |= D7S_FLIP; + else + regs &= ~D7S_FLIP; + writeb(regs, p->regs); } misc_deregister(&d7s_miscdev); - d7s_free(); + of_iounmap(&op->resource[0], p->regs, sizeof(u8)); + kfree(p); + + return 0; +} + +static struct of_device_id d7s_match[] = { + { + .name = "display7seg", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, d7s_match); + +static struct of_platform_driver d7s_driver = { + .name = DRIVER_NAME, + .match_table = d7s_match, + .probe = d7s_probe, + .remove = __devexit_p(d7s_remove), +}; + +static int __init d7s_init(void) +{ + return of_register_driver(&d7s_driver, &of_bus_type); +} + +static void __exit d7s_exit(void) +{ + of_unregister_driver(&d7s_driver); } module_init(d7s_init); -module_exit(d7s_cleanup); +module_exit(d7s_exit); -- cgit v1.2.3 From 6b8c90f24e24505f97efaef1a46572d6b45929b9 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 29 Aug 2008 21:05:15 -0700 Subject: envctrl: Convert to pure OF driver. Signed-off-by: David S. Miller --- drivers/sbus/char/envctrl.c | 147 ++++++++++++++++++++++++-------------------- 1 file changed, 79 insertions(+), 68 deletions(-) (limited to 'drivers/sbus') diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index a408402426f..ea8c35cbffd 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -1,5 +1,4 @@ -/* $Id: envctrl.c,v 1.25 2002/01/15 09:01:26 davem Exp $ - * envctrl.c: Temperature and Fan monitoring on Machines providing it. +/* envctrl.c: Temperature and Fan monitoring on Machines providing it. * * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 2000 Vinh Truong (vinh.truong@eng.sun.com) @@ -28,12 +27,16 @@ #include #include #include +#include +#include -#include #include #include #include +#define DRIVER_NAME "envctrl" +#define PFX DRIVER_NAME ": " + #define ENVCTRL_MINOR 162 #define PCF8584_ADDRESS 0x55 @@ -193,7 +196,7 @@ static void envtrl_i2c_test_pin(void) } if (limit <= 0) - printk(KERN_INFO "envctrl: Pin status will not clear.\n"); + printk(KERN_INFO PFX "Pin status will not clear.\n"); } /* Function Description: Test busy bit. @@ -211,7 +214,7 @@ static void envctrl_i2c_test_bb(void) } if (limit <= 0) - printk(KERN_INFO "envctrl: Busy bit will not clear.\n"); + printk(KERN_INFO PFX "Busy bit will not clear.\n"); } /* Function Description: Send the address for a read access. @@ -858,11 +861,10 @@ static void envctrl_init_voltage_status(struct i2c_child_t *pchild) /* Function Description: Initialize i2c child device. * Return: None. */ -static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, +static void envctrl_init_i2c_child(struct device_node *dp, struct i2c_child_t *pchild) { int len, i, tbls_size = 0; - struct device_node *dp = edev_child->prom_node; const void *pval; /* Get device address. */ @@ -882,12 +884,12 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, pchild->tables = kmalloc(tbls_size, GFP_KERNEL); if (pchild->tables == NULL){ - printk("envctrl: Failed to allocate table.\n"); + printk(KERN_ERR PFX "Failed to allocate table.\n"); return; } pval = of_get_property(dp, "tables", &len); if (!pval || len <= 0) { - printk("envctrl: Failed to get table.\n"); + printk(KERN_ERR PFX "Failed to get table.\n"); return; } memcpy(pchild->tables, pval, len); @@ -993,14 +995,14 @@ static int kenvctrld(void *__unused) struct i2c_child_t *cputemp; if (NULL == (cputemp = envctrl_get_i2c_child(ENVCTRL_CPUTEMP_MON))) { - printk(KERN_ERR - "envctrl: kenvctrld unable to monitor CPU temp-- exiting\n"); + printk(KERN_ERR PFX + "kenvctrld unable to monitor CPU temp-- exiting\n"); return -ENODEV; } poll_interval = 5000; /* TODO env_mon_interval */ - printk(KERN_INFO "envctrl: %s starting...\n", current->comm); + printk(KERN_INFO PFX "%s starting...\n", current->comm); for (;;) { msleep_interruptible(poll_interval); @@ -1022,54 +1024,35 @@ static int kenvctrld(void *__unused) } } } - printk(KERN_INFO "envctrl: %s exiting...\n", current->comm); + printk(KERN_INFO PFX "%s exiting...\n", current->comm); return 0; } -static int __init envctrl_init(void) +static int __devinit envctrl_probe(struct of_device *op, + const struct of_device_id *match) { - struct linux_ebus *ebus = NULL; - struct linux_ebus_device *edev = NULL; - struct linux_ebus_child *edev_child = NULL; - int err, i = 0; - - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_node->name, "bbc")) { - /* If we find a boot-bus controller node, - * then this envctrl driver is not for us. - */ - return -ENODEV; - } - } - } + struct device_node *dp; + int index, err; - /* Traverse through ebus and ebus device list for i2c device and - * adc and gpio nodes. - */ - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_node->name, "i2c")) { - i2c = ioremap(edev->resource[0].start, 0x2); - for_each_edevchild(edev, edev_child) { - if (!strcmp("gpio", edev_child->prom_node->name)) { - i2c_childlist[i].i2ctype = I2C_GPIO; - envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++])); - } - if (!strcmp("adc", edev_child->prom_node->name)) { - i2c_childlist[i].i2ctype = I2C_ADC; - envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++])); - } - } - goto done; - } + if (i2c) + return -EINVAL; + + i2c = of_ioremap(&op->resource[0], 0, 0x2, DRIVER_NAME); + if (!i2c) + return -ENOMEM; + + index = 0; + dp = op->node->child; + while (dp) { + if (!strcmp(dp->name, "gpio")) { + i2c_childlist[index].i2ctype = I2C_GPIO; + envctrl_init_i2c_child(dp, &(i2c_childlist[index++])); + } else if (!strcmp(dp->name, "adc")) { + i2c_childlist[index].i2ctype = I2C_ADC; + envctrl_init_i2c_child(dp, &(i2c_childlist[index++])); } - } -done: - if (!edev) { - printk("envctrl: I2C device not found.\n"); - return -ENODEV; + dp = dp->sibling; } /* Set device address. */ @@ -1087,7 +1070,7 @@ done: /* Register the device as a minor miscellaneous device. */ err = misc_register(&envctrl_dev); if (err) { - printk("envctrl: Unable to get misc minor %d\n", + printk(KERN_ERR PFX "Unable to get misc minor %d\n", envctrl_dev.minor); goto out_iounmap; } @@ -1096,12 +1079,12 @@ done: * a next child device, so we decrement before reverse-traversal of * child devices. */ - printk("envctrl: initialized "); - for (--i; i >= 0; --i) { + printk(KERN_INFO PFX "Initialized "); + for (--index; index >= 0; --index) { printk("[%s 0x%lx]%s", - (I2C_ADC == i2c_childlist[i].i2ctype) ? ("adc") : - ((I2C_GPIO == i2c_childlist[i].i2ctype) ? ("gpio") : ("unknown")), - i2c_childlist[i].addr, (0 == i) ? ("\n") : (" ")); + (I2C_ADC == i2c_childlist[index].i2ctype) ? "adc" : + ((I2C_GPIO == i2c_childlist[index].i2ctype) ? "gpio" : "unknown"), + i2c_childlist[index].addr, (0 == index) ? "\n" : " "); } kenvctrld_task = kthread_run(kenvctrld, NULL, "kenvctrld"); @@ -1115,26 +1098,54 @@ done: out_deregister: misc_deregister(&envctrl_dev); out_iounmap: - iounmap(i2c); - for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++) - kfree(i2c_childlist[i].tables); + of_iounmap(&op->resource[0], i2c, 0x2); + for (index = 0; index < ENVCTRL_MAX_CPU * 2; index++) + kfree(i2c_childlist[index].tables); return err; } -static void __exit envctrl_cleanup(void) +static int __devexit envctrl_remove(struct of_device *op) { - int i; + int index; kthread_stop(kenvctrld_task); - iounmap(i2c); + of_iounmap(&op->resource[0], i2c, 0x2); misc_deregister(&envctrl_dev); - for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++) - kfree(i2c_childlist[i].tables); + for (index = 0; index < ENVCTRL_MAX_CPU * 2; index++) + kfree(i2c_childlist[index].tables); + + return 0; +} + +static struct of_device_id envctrl_match[] = { + { + .name = "i2c", + .compatible = "i2cpcf,8584", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, envctrl_match); + +static struct of_platform_driver envctrl_driver = { + .name = DRIVER_NAME, + .match_table = envctrl_match, + .probe = envctrl_probe, + .remove = __devexit_p(envctrl_remove), +}; + +static int __init envctrl_init(void) +{ + return of_register_driver(&envctrl_driver, &of_bus_type); +} + +static void __exit envctrl_exit(void) +{ + of_unregister_driver(&envctrl_driver); } module_init(envctrl_init); -module_exit(envctrl_cleanup); +module_exit(envctrl_exit); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From e21e245bcd9d5244735799387d14421789b20557 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 29 Aug 2008 22:34:14 -0700 Subject: bbc_i2c: Convert to pure OF driver. This thing was a mess, who wrote this junk? :) Luckily we'll soon have nice generic I2C layer drivers for this PCF based I2C stuff on sparc64. Signed-off-by: David S. Miller --- drivers/sbus/char/bbc_envctrl.c | 121 ++++++------------ drivers/sbus/char/bbc_i2c.c | 267 ++++++++++++++++------------------------ drivers/sbus/char/bbc_i2c.h | 75 ++++++++++- 3 files changed, 214 insertions(+), 249 deletions(-) (limited to 'drivers/sbus') diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c index 0bde26989a2..abe4d50de21 100644 --- a/drivers/sbus/char/bbc_envctrl.c +++ b/drivers/sbus/char/bbc_envctrl.c @@ -1,15 +1,15 @@ -/* $Id: bbc_envctrl.c,v 1.4 2001/04/06 16:48:08 davem Exp $ - * bbc_envctrl.c: UltraSPARC-III environment control driver. +/* bbc_envctrl.c: UltraSPARC-III environment control driver. * - * Copyright (C) 2001 David S. Miller (davem@redhat.com) + * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net) */ #include #include #include #include +#include +#include #include -#include #include "bbc_i2c.h" #include "max1617.h" @@ -75,43 +75,8 @@ static struct temp_limits amb_temp_limits[2] = { { 65, 55, 40, 5, -5, -10 }, }; -enum fan_action { FAN_SLOWER, FAN_SAME, FAN_FASTER, FAN_FULLBLAST, FAN_STATE_MAX }; - -struct bbc_cpu_temperature { - struct bbc_cpu_temperature *next; - - struct bbc_i2c_client *client; - int index; - - /* Current readings, and history. */ - s8 curr_cpu_temp; - s8 curr_amb_temp; - s8 prev_cpu_temp; - s8 prev_amb_temp; - s8 avg_cpu_temp; - s8 avg_amb_temp; - - int sample_tick; - - enum fan_action fan_todo[2]; -#define FAN_AMBIENT 0 -#define FAN_CPU 1 -}; - -struct bbc_cpu_temperature *all_bbc_temps; - -struct bbc_fan_control { - struct bbc_fan_control *next; - - struct bbc_i2c_client *client; - int index; - - int psupply_fan_on; - int cpu_fan_speed; - int system_fan_speed; -}; - -struct bbc_fan_control *all_bbc_fans; +static LIST_HEAD(all_temps); +static LIST_HEAD(all_fans); #define CPU_FAN_REG 0xf0 #define SYS_FAN_REG 0xf2 @@ -330,7 +295,7 @@ static enum fan_action prioritize_fan_action(int which_fan) * recommend we do, and perform that action on all the * fans. */ - for (tp = all_bbc_temps; tp; tp = tp->next) { + list_for_each_entry(tp, &all_temps, glob_list) { if (tp->fan_todo[which_fan] == FAN_FULLBLAST) { decision = FAN_FULLBLAST; break; @@ -439,7 +404,7 @@ static void fans_full_blast(void) /* Since we will not be monitoring things anymore, put * the fans on full blast. */ - for (fp = all_bbc_fans; fp; fp = fp->next) { + list_for_each_entry(fp, &all_fans, glob_list) { fp->cpu_fan_speed = FAN_SPEED_MAX; fp->system_fan_speed = FAN_SPEED_MAX; fp->psupply_fan_on = 1; @@ -463,11 +428,11 @@ static int kenvctrld(void *__unused) if (kthread_should_stop()) break; - for (tp = all_bbc_temps; tp; tp = tp->next) { + list_for_each_entry(tp, &all_temps, glob_list) { get_current_temps(tp); analyze_temps(tp, &last_warning_jiffies); } - for (fp = all_bbc_fans; fp; fp = fp->next) + list_for_each_entry(fp, &all_fans, glob_list) maybe_new_fan_speeds(fp); } printk(KERN_INFO "bbc_envctrl: kenvctrld exiting...\n"); @@ -477,7 +442,8 @@ static int kenvctrld(void *__unused) return 0; } -static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx) +static void attach_one_temp(struct bbc_i2c_bus *bp, struct of_device *op, + int temp_idx) { struct bbc_cpu_temperature *tp; @@ -485,20 +451,17 @@ static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx) if (!tp) return; - tp->client = bbc_i2c_attach(echild); + tp->client = bbc_i2c_attach(op); if (!tp->client) { kfree(tp); return; } + tp->index = temp_idx; - { - struct bbc_cpu_temperature **tpp = &all_bbc_temps; - while (*tpp) - tpp = &((*tpp)->next); - tp->next = NULL; - *tpp = tp; - } + + list_add(&tp->glob_list, &all_temps); + list_add(&tp->bp_list, &bp->temps); /* Tell it to convert once every 5 seconds, clear all cfg * bits. @@ -524,7 +487,8 @@ static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx) tp->fan_todo[FAN_CPU] = FAN_SAME; } -static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx) +static void attach_one_fan(struct bbc_i2c_bus *bp, struct of_device *op, + int fan_idx) { struct bbc_fan_control *fp; @@ -532,7 +496,7 @@ static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx) if (!fp) return; - fp->client = bbc_i2c_attach(echild); + fp->client = bbc_i2c_attach(op); if (!fp->client) { kfree(fp); return; @@ -540,13 +504,8 @@ static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx) fp->index = fan_idx; - { - struct bbc_fan_control **fpp = &all_bbc_fans; - while (*fpp) - fpp = &((*fpp)->next); - fp->next = NULL; - *fpp = fp; - } + list_add(&fp->glob_list, &all_fans); + list_add(&fp->bp_list, &bp->fans); /* The i2c device controlling the fans is write-only. * So the only way to keep track of the current power @@ -563,18 +522,18 @@ static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx) set_fan_speeds(fp); } -int bbc_envctrl_init(void) +int bbc_envctrl_init(struct bbc_i2c_bus *bp) { - struct linux_ebus_child *echild; + struct of_device *op; int temp_index = 0; int fan_index = 0; int devidx = 0; - while ((echild = bbc_i2c_getdev(devidx++)) != NULL) { - if (!strcmp(echild->prom_node->name, "temperature")) - attach_one_temp(echild, temp_index++); - if (!strcmp(echild->prom_node->name, "fan-control")) - attach_one_fan(echild, fan_index++); + while ((op = bbc_i2c_getdev(devidx++)) != NULL) { + if (!strcmp(op->node->name, "temperature")) + attach_one_temp(bp, op, temp_index++); + if (!strcmp(op->node->name, "fan-control")) + attach_one_fan(bp, op, fan_index++); } if (temp_index != 0 && fan_index != 0) { kenvctrld_task = kthread_run(kenvctrld, NULL, "kenvctrld"); @@ -597,26 +556,22 @@ static void destroy_one_fan(struct bbc_fan_control *fp) kfree(fp); } -void bbc_envctrl_cleanup(void) +void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp) { - struct bbc_cpu_temperature *tp; - struct bbc_fan_control *fp; + struct bbc_cpu_temperature *tp, *tpos; + struct bbc_fan_control *fp, *fpos; kthread_stop(kenvctrld_task); - tp = all_bbc_temps; - while (tp != NULL) { - struct bbc_cpu_temperature *next = tp->next; + list_for_each_entry_safe(tp, tpos, &bp->temps, bp_list) { + list_del(&tp->bp_list); + list_del(&tp->glob_list); destroy_one_temp(tp); - tp = next; } - all_bbc_temps = NULL; - fp = all_bbc_fans; - while (fp != NULL) { - struct bbc_fan_control *next = fp->next; + list_for_each_entry_safe(fp, fpos, &bp->fans, bp_list) { + list_del(&fp->bp_list); + list_del(&fp->glob_list); destroy_one_fan(fp); - fp = next; } - all_bbc_fans = NULL; } diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c index ac8ef2ce07f..af7f4af6c5f 100644 --- a/drivers/sbus/char/bbc_i2c.c +++ b/drivers/sbus/char/bbc_i2c.c @@ -1,8 +1,7 @@ -/* $Id: bbc_i2c.c,v 1.2 2001/04/02 09:59:08 davem Exp $ - * bbc_i2c.c: I2C low-level driver for BBC device on UltraSPARC-III +/* bbc_i2c.c: I2C low-level driver for BBC device on UltraSPARC-III * platforms. * - * Copyright (C) 2001 David S. Miller (davem@redhat.com) + * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net) */ #include @@ -14,9 +13,8 @@ #include #include #include -#include -#include -#include +#include +#include #include #include @@ -53,54 +51,12 @@ * The second controller also connects to the smartcard reader, if present. */ -#define NUM_CHILDREN 8 -struct bbc_i2c_bus { - struct bbc_i2c_bus *next; - int index; - spinlock_t lock; - void __iomem *i2c_bussel_reg; - void __iomem *i2c_control_regs; - unsigned char own, clock; - - wait_queue_head_t wq; - volatile int waiting; - - struct linux_ebus_device *bus_edev; - struct { - struct linux_ebus_child *device; - int client_claimed; - } devs[NUM_CHILDREN]; -}; - -static struct bbc_i2c_bus *all_bbc_i2c; - -struct bbc_i2c_client { - struct bbc_i2c_bus *bp; - struct linux_ebus_child *echild; - int bus; - int address; -}; - -static int find_device(struct bbc_i2c_bus *bp, struct linux_ebus_child *echild) +static void set_device_claimage(struct bbc_i2c_bus *bp, struct of_device *op, int val) { int i; for (i = 0; i < NUM_CHILDREN; i++) { - if (bp->devs[i].device == echild) { - if (bp->devs[i].client_claimed) - return 0; - return 1; - } - } - return 0; -} - -static void set_device_claimage(struct bbc_i2c_bus *bp, struct linux_ebus_child *echild, int val) -{ - int i; - - for (i = 0; i < NUM_CHILDREN; i++) { - if (bp->devs[i].device == echild) { + if (bp->devs[i].device == op) { bp->devs[i].client_claimed = val; return; } @@ -110,61 +66,47 @@ static void set_device_claimage(struct bbc_i2c_bus *bp, struct linux_ebus_child #define claim_device(BP,ECHILD) set_device_claimage(BP,ECHILD,1) #define release_device(BP,ECHILD) set_device_claimage(BP,ECHILD,0) -static struct bbc_i2c_bus *find_bus_for_device(struct linux_ebus_child *echild) +struct of_device *bbc_i2c_getdev(struct bbc_i2c_bus *bp, int index) { - struct bbc_i2c_bus *bp = all_bbc_i2c; + struct of_device *op = NULL; + int curidx = 0, i; - while (bp != NULL) { - if (find_device(bp, echild) != 0) + for (i = 0; i < NUM_CHILDREN; i++) { + if (!(op = bp->devs[i].device)) break; - bp = bp->next; + if (curidx == index) + goto out; + op = NULL; + curidx++; } - return bp; -} - -struct linux_ebus_child *bbc_i2c_getdev(int index) -{ - struct bbc_i2c_bus *bp = all_bbc_i2c; - struct linux_ebus_child *echild = NULL; - int curidx = 0; - - while (bp != NULL) { - struct bbc_i2c_bus *next = bp->next; - int i; - - for (i = 0; i < NUM_CHILDREN; i++) { - if (!(echild = bp->devs[i].device)) - break; - if (curidx == index) - goto out; - echild = NULL; - curidx++; - } - bp = next; - } out: if (curidx == index) - return echild; + return op; return NULL; } -struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *echild) +struct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct of_device *op) { - struct bbc_i2c_bus *bp = find_bus_for_device(echild); struct bbc_i2c_client *client; + const u32 *reg; - if (!bp) - return NULL; client = kzalloc(sizeof(*client), GFP_KERNEL); if (!client) return NULL; client->bp = bp; - client->echild = echild; - client->bus = echild->resource[0].start; - client->address = echild->resource[1].start; + client->op = op; + + reg = of_get_property(op->node, "reg", NULL); + if (!reg) { + kfree(client); + return NULL; + } - claim_device(bp, echild); + client->bus = reg[0]; + client->address = reg[1]; + + claim_device(bp, op); return client; } @@ -172,9 +114,9 @@ struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *echild) void bbc_i2c_detach(struct bbc_i2c_client *client) { struct bbc_i2c_bus *bp = client->bp; - struct linux_ebus_child *echild = client->echild; + struct of_device *op = client->op; - release_device(bp, echild); + release_device(bp, op); kfree(client); } @@ -355,44 +297,43 @@ static void __init reset_one_i2c(struct bbc_i2c_bus *bp) writeb(I2C_PCF_IDLE, bp->i2c_control_regs + 0x0); } -static int __init attach_one_i2c(struct linux_ebus_device *edev, int index) +static struct bbc_i2c_bus * __init attach_one_i2c(struct of_device *op, int index) { struct bbc_i2c_bus *bp; - struct linux_ebus_child *echild; + struct device_node *dp; int entry; bp = kzalloc(sizeof(*bp), GFP_KERNEL); if (!bp) - return -ENOMEM; + return NULL; - bp->i2c_control_regs = ioremap(edev->resource[0].start, 0x2); + bp->i2c_control_regs = of_ioremap(&op->resource[0], 0, 0x2, "bbc_i2c_regs"); if (!bp->i2c_control_regs) goto fail; - if (edev->num_addrs == 2) { - bp->i2c_bussel_reg = ioremap(edev->resource[1].start, 0x1); - if (!bp->i2c_bussel_reg) - goto fail; - } + bp->i2c_bussel_reg = of_ioremap(&op->resource[1], 0, 0x1, "bbc_i2c_bussel"); + if (!bp->i2c_bussel_reg) + goto fail; bp->waiting = 0; init_waitqueue_head(&bp->wq); - if (request_irq(edev->irqs[0], bbc_i2c_interrupt, + if (request_irq(op->irqs[0], bbc_i2c_interrupt, IRQF_SHARED, "bbc_i2c", bp)) goto fail; bp->index = index; - bp->bus_edev = edev; + bp->op = op; spin_lock_init(&bp->lock); - bp->next = all_bbc_i2c; - all_bbc_i2c = bp; entry = 0; - for (echild = edev->children; - echild && entry < 8; - echild = echild->next, entry++) { - bp->devs[entry].device = echild; + for (dp = op->node->child; + dp && entry < 8; + dp = dp->sibling, entry++) { + struct of_device *child_op; + + child_op = of_find_device_by_node(dp); + bp->devs[entry].device = child_op; bp->devs[entry].client_claimed = 0; } @@ -406,86 +347,90 @@ static int __init attach_one_i2c(struct linux_ebus_device *edev, int index) reset_one_i2c(bp); - return 0; + return bp; fail: if (bp->i2c_bussel_reg) - iounmap(bp->i2c_bussel_reg); + of_iounmap(&op->resource[1], bp->i2c_bussel_reg, 1); if (bp->i2c_control_regs) - iounmap(bp->i2c_control_regs); + of_iounmap(&op->resource[0], bp->i2c_control_regs, 2); kfree(bp); - return -EINVAL; -} - -static int __init bbc_present(void) -{ - struct linux_ebus *ebus = NULL; - struct linux_ebus_device *edev = NULL; - - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_node->name, "bbc")) - return 1; - } - } - return 0; + return NULL; } -extern int bbc_envctrl_init(void); -extern void bbc_envctrl_cleanup(void); -static void bbc_i2c_cleanup(void); +extern int bbc_envctrl_init(struct bbc_i2c_bus *bp); +extern void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp); -static int __init bbc_i2c_init(void) +static int __devinit bbc_i2c_probe(struct of_device *op, + const struct of_device_id *match) { - struct linux_ebus *ebus = NULL; - struct linux_ebus_device *edev = NULL; + struct bbc_i2c_bus *bp; int err, index = 0; - if ((tlb_type != cheetah && tlb_type != cheetah_plus) || - !bbc_present()) - return -ENODEV; + bp = attach_one_i2c(op, index); + if (!bp) + return -EINVAL; - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_node->name, "i2c")) { - if (!attach_one_i2c(edev, index)) - index++; - } - } + err = bbc_envctrl_init(bp); + if (err) { + free_irq(op->irqs[0], bp); + if (bp->i2c_bussel_reg) + of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1); + if (bp->i2c_control_regs) + of_iounmap(&op->resource[1], bp->i2c_control_regs, 2); + kfree(bp); + } else { + dev_set_drvdata(&op->dev, bp); } - if (!index) - return -ENODEV; - - err = bbc_envctrl_init(); - if (err) - bbc_i2c_cleanup(); return err; } -static void bbc_i2c_cleanup(void) +static int __devexit bbc_i2c_remove(struct of_device *op) { - struct bbc_i2c_bus *bp = all_bbc_i2c; + struct bbc_i2c_bus *bp = dev_get_drvdata(&op->dev); + + bbc_envctrl_cleanup(bp); + + free_irq(op->irqs[0], bp); - bbc_envctrl_cleanup(); + if (bp->i2c_bussel_reg) + of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1); + if (bp->i2c_control_regs) + of_iounmap(&op->resource[1], bp->i2c_control_regs, 2); - while (bp != NULL) { - struct bbc_i2c_bus *next = bp->next; + kfree(bp); - free_irq(bp->bus_edev->irqs[0], bp); + return 0; +} - if (bp->i2c_bussel_reg) - iounmap(bp->i2c_bussel_reg); - if (bp->i2c_control_regs) - iounmap(bp->i2c_control_regs); +static struct of_device_id bbc_i2c_match[] = { + { + .name = "i2c", + .compatible = "SUNW,bbc-i2c", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, bbc_i2c_match); - kfree(bp); +static struct of_platform_driver bbc_i2c_driver = { + .name = "bbc_i2c", + .match_table = bbc_i2c_match, + .probe = bbc_i2c_probe, + .remove = __devexit_p(bbc_i2c_remove), +}; - bp = next; - } - all_bbc_i2c = NULL; +static int __init bbc_i2c_init(void) +{ + return of_register_driver(&bbc_i2c_driver, &of_bus_type); +} + +static void __exit bbc_i2c_exit(void) +{ + of_unregister_driver(&bbc_i2c_driver); } module_init(bbc_i2c_init); -module_exit(bbc_i2c_cleanup); +module_exit(bbc_i2c_exit); + MODULE_LICENSE("GPL"); diff --git a/drivers/sbus/char/bbc_i2c.h b/drivers/sbus/char/bbc_i2c.h index fb01bd17704..83c4811b7b5 100644 --- a/drivers/sbus/char/bbc_i2c.h +++ b/drivers/sbus/char/bbc_i2c.h @@ -1,14 +1,79 @@ -/* $Id: bbc_i2c.h,v 1.2 2001/04/02 09:59:25 davem Exp $ */ #ifndef _BBC_I2C_H #define _BBC_I2C_H -#include +#include +#include +#include -struct bbc_i2c_client; +struct bbc_i2c_client { + struct bbc_i2c_bus *bp; + struct of_device *op; + int bus; + int address; +}; + +enum fan_action { FAN_SLOWER, FAN_SAME, FAN_FASTER, FAN_FULLBLAST, FAN_STATE_MAX }; + +struct bbc_cpu_temperature { + struct list_head bp_list; + struct list_head glob_list; + + struct bbc_i2c_client *client; + int index; + + /* Current readings, and history. */ + s8 curr_cpu_temp; + s8 curr_amb_temp; + s8 prev_cpu_temp; + s8 prev_amb_temp; + s8 avg_cpu_temp; + s8 avg_amb_temp; + + int sample_tick; + + enum fan_action fan_todo[2]; +#define FAN_AMBIENT 0 +#define FAN_CPU 1 +}; + +struct bbc_fan_control { + struct list_head bp_list; + struct list_head glob_list; + + struct bbc_i2c_client *client; + int index; + + int psupply_fan_on; + int cpu_fan_speed; + int system_fan_speed; +}; + +#define NUM_CHILDREN 8 + +struct bbc_i2c_bus { + struct bbc_i2c_bus *next; + int index; + spinlock_t lock; + void __iomem *i2c_bussel_reg; + void __iomem *i2c_control_regs; + unsigned char own, clock; + + wait_queue_head_t wq; + volatile int waiting; + + struct list_head temps; + struct list_head fans; + + struct of_device *op; + struct { + struct of_device *device; + int client_claimed; + } devs[NUM_CHILDREN]; +}; /* Probing and attachment. */ -extern struct linux_ebus_child *bbc_i2c_getdev(int); -extern struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *); +extern struct of_device *bbc_i2c_getdev(struct bbc_i2c_bus *, int); +extern struct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct of_device *); extern void bbc_i2c_detach(struct bbc_i2c_client *); /* Register read/write. NOTE: Blocking! */ -- cgit v1.2.3 From 39890072b320e7731b105b459cee1320957adbc7 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 29 Aug 2008 22:55:14 -0700 Subject: bbc_envctrl: Fix build errors from bbc_i2c OF conversion. Signed-off-by: David S. Miller --- drivers/sbus/char/bbc_envctrl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/sbus') diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c index abe4d50de21..15dab96d05e 100644 --- a/drivers/sbus/char/bbc_envctrl.c +++ b/drivers/sbus/char/bbc_envctrl.c @@ -451,7 +451,7 @@ static void attach_one_temp(struct bbc_i2c_bus *bp, struct of_device *op, if (!tp) return; - tp->client = bbc_i2c_attach(op); + tp->client = bbc_i2c_attach(bp, op); if (!tp->client) { kfree(tp); return; @@ -496,7 +496,7 @@ static void attach_one_fan(struct bbc_i2c_bus *bp, struct of_device *op, if (!fp) return; - fp->client = bbc_i2c_attach(op); + fp->client = bbc_i2c_attach(bp, op); if (!fp->client) { kfree(fp); return; @@ -529,7 +529,7 @@ int bbc_envctrl_init(struct bbc_i2c_bus *bp) int fan_index = 0; int devidx = 0; - while ((op = bbc_i2c_getdev(devidx++)) != NULL) { + while ((op = bbc_i2c_getdev(bp, devidx++)) != NULL) { if (!strcmp(op->node->name, "temperature")) attach_one_temp(bp, op, temp_index++); if (!strcmp(op->node->name, "fan-control")) -- cgit v1.2.3 From fd098316ef533e8441576f020ead4beab93154ce Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 31 Aug 2008 01:23:17 -0700 Subject: sparc: Annotate of_device_id arrays with const or __initdata. As suggested by Stephen Rothwell. Signed-off-by: David S. Miller --- drivers/sbus/char/bbc_i2c.c | 2 +- drivers/sbus/char/display7seg.c | 2 +- drivers/sbus/char/envctrl.c | 2 +- drivers/sbus/char/flash.c | 2 +- drivers/sbus/char/uctrl.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/sbus') diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c index af7f4af6c5f..f08e169ba1b 100644 --- a/drivers/sbus/char/bbc_i2c.c +++ b/drivers/sbus/char/bbc_i2c.c @@ -404,7 +404,7 @@ static int __devexit bbc_i2c_remove(struct of_device *op) return 0; } -static struct of_device_id bbc_i2c_match[] = { +static const struct of_device_id bbc_i2c_match[] = { { .name = "i2c", .compatible = "SUNW,bbc-i2c", diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c index 2f16d78e92d..2550af4ae43 100644 --- a/drivers/sbus/char/display7seg.c +++ b/drivers/sbus/char/display7seg.c @@ -256,7 +256,7 @@ static int __devexit d7s_remove(struct of_device *op) return 0; } -static struct of_device_id d7s_match[] = { +static const struct of_device_id d7s_match[] = { { .name = "display7seg", }, diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index ea8c35cbffd..58e583b61e6 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -1120,7 +1120,7 @@ static int __devexit envctrl_remove(struct of_device *op) return 0; } -static struct of_device_id envctrl_match[] = { +static const struct of_device_id envctrl_match[] = { { .name = "i2c", .compatible = "i2cpcf,8584", diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c index 715996f5c53..41083472ff4 100644 --- a/drivers/sbus/char/flash.c +++ b/drivers/sbus/char/flash.c @@ -199,7 +199,7 @@ static int __devexit flash_remove(struct of_device *op) return 0; } -static struct of_device_id flash_match[] = { +static const struct of_device_id flash_match[] = { { .name = "flashprom", }, diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c index 6cff9777bbc..27993c37775 100644 --- a/drivers/sbus/char/uctrl.c +++ b/drivers/sbus/char/uctrl.c @@ -417,7 +417,7 @@ static int __devexit uctrl_remove(struct of_device *op) return 0; } -static struct of_device_id uctrl_match[] = { +static const struct of_device_id uctrl_match[] = { { .name = "uctrl", }, -- cgit v1.2.3 From eed795bf1fd2a012beddd6017fd7baf8ddf43ca1 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 3 Sep 2008 15:55:32 -0700 Subject: sparc: Kill sbus mostek RTC driver. No longer used. Signed-off-by: David S. Miller --- drivers/sbus/char/Kconfig | 10 -- drivers/sbus/char/Makefile | 1 - drivers/sbus/char/rtc.c | 275 --------------------------------------------- 3 files changed, 286 deletions(-) delete mode 100644 drivers/sbus/char/rtc.c (limited to 'drivers/sbus') diff --git a/drivers/sbus/char/Kconfig b/drivers/sbus/char/Kconfig index 1d5d1b4580c..73cde85d04d 100644 --- a/drivers/sbus/char/Kconfig +++ b/drivers/sbus/char/Kconfig @@ -13,16 +13,6 @@ config SUN_OPENPROMIO If unsure, say Y. -config SUN_MOSTEK_RTC - tristate "Mostek real time clock support" - depends on SPARC32 - help - The Mostek RTC chip is used on all known Sun computers except - some JavaStations. For a JavaStation you need to say Y both here - and to "Enhanced Real Time Clock Support". - - Say Y here unless you are building a special purpose kernel. - config OBP_FLASH tristate "OBP Flash Device support" depends on SPARC64 diff --git a/drivers/sbus/char/Makefile b/drivers/sbus/char/Makefile index d83212ec541..78b6183c986 100644 --- a/drivers/sbus/char/Makefile +++ b/drivers/sbus/char/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_ENVCTRL) += envctrl.o obj-$(CONFIG_DISPLAY7SEG) += display7seg.o obj-$(CONFIG_OBP_FLASH) += flash.o obj-$(CONFIG_SUN_OPENPROMIO) += openprom.o -obj-$(CONFIG_SUN_MOSTEK_RTC) += rtc.o obj-$(CONFIG_TADPOLE_TS102_UCTRL) += uctrl.o obj-$(CONFIG_SUN_JSFLASH) += jsflash.o obj-$(CONFIG_BBC_I2C) += bbc.o diff --git a/drivers/sbus/char/rtc.c b/drivers/sbus/char/rtc.c deleted file mode 100644 index b0429917154..00000000000 --- a/drivers/sbus/char/rtc.c +++ /dev/null @@ -1,275 +0,0 @@ -/* $Id: rtc.c,v 1.28 2001/10/08 22:19:51 davem Exp $ - * - * Linux/SPARC Real Time Clock Driver - * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) - * - * This is a little driver that lets a user-level program access - * the SPARC Mostek real time clock chip. It is no use unless you - * use the modified clock utility. - * - * Get the modified clock utility from: - * ftp://vger.kernel.org/pub/linux/Sparc/userland/clock.c - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int rtc_busy = 0; - -/* This is the structure layout used by drivers/char/rtc.c, we - * support that driver's ioctls so that things are less messy in - * userspace. - */ -struct rtc_time_generic { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; -}; -#define RTC_AIE_ON _IO('p', 0x01) /* Alarm int. enable on */ -#define RTC_AIE_OFF _IO('p', 0x02) /* ... off */ -#define RTC_UIE_ON _IO('p', 0x03) /* Update int. enable on */ -#define RTC_UIE_OFF _IO('p', 0x04) /* ... off */ -#define RTC_PIE_ON _IO('p', 0x05) /* Periodic int. enable on */ -#define RTC_PIE_OFF _IO('p', 0x06) /* ... off */ -#define RTC_WIE_ON _IO('p', 0x0f) /* Watchdog int. enable on */ -#define RTC_WIE_OFF _IO('p', 0x10) /* ... off */ -#define RTC_RD_TIME _IOR('p', 0x09, struct rtc_time_generic) /* Read RTC time */ -#define RTC_SET_TIME _IOW('p', 0x0a, struct rtc_time_generic) /* Set RTC time */ -#define RTC_ALM_SET _IOW('p', 0x07, struct rtc_time) /* Set alarm time */ -#define RTC_ALM_READ _IOR('p', 0x08, struct rtc_time) /* Read alarm time */ -#define RTC_IRQP_READ _IOR('p', 0x0b, unsigned long) /* Read IRQ rate */ -#define RTC_IRQP_SET _IOW('p', 0x0c, unsigned long) /* Set IRQ rate */ -#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */ -#define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */ -#define RTC_WKALM_SET _IOW('p', 0x0f, struct rtc_wkalrm)/* Set wakeup alarm*/ -#define RTC_WKALM_RD _IOR('p', 0x10, struct rtc_wkalrm)/* Get wakeup alarm*/ -#define RTC_PLL_GET _IOR('p', 0x11, struct rtc_pll_info) /* Get PLL correction */ -#define RTC_PLL_SET _IOW('p', 0x12, struct rtc_pll_info) /* Set PLL correction */ - -/* Retrieve the current date and time from the real time clock. */ -static void get_rtc_time(struct rtc_time *t) -{ - void __iomem *regs = mstk48t02_regs; - u8 tmp; - - spin_lock_irq(&mostek_lock); - - tmp = mostek_read(regs + MOSTEK_CREG); - tmp |= MSTK_CREG_READ; - mostek_write(regs + MOSTEK_CREG, tmp); - - t->sec = MSTK_REG_SEC(regs); - t->min = MSTK_REG_MIN(regs); - t->hour = MSTK_REG_HOUR(regs); - t->dow = MSTK_REG_DOW(regs); - t->dom = MSTK_REG_DOM(regs); - t->month = MSTK_REG_MONTH(regs); - t->year = MSTK_CVT_YEAR( MSTK_REG_YEAR(regs) ); - - tmp = mostek_read(regs + MOSTEK_CREG); - tmp &= ~MSTK_CREG_READ; - mostek_write(regs + MOSTEK_CREG, tmp); - - spin_unlock_irq(&mostek_lock); -} - -/* Set the current date and time inthe real time clock. */ -void set_rtc_time(struct rtc_time *t) -{ - void __iomem *regs = mstk48t02_regs; - u8 tmp; - - spin_lock_irq(&mostek_lock); - - tmp = mostek_read(regs + MOSTEK_CREG); - tmp |= MSTK_CREG_WRITE; - mostek_write(regs + MOSTEK_CREG, tmp); - - MSTK_SET_REG_SEC(regs,t->sec); - MSTK_SET_REG_MIN(regs,t->min); - MSTK_SET_REG_HOUR(regs,t->hour); - MSTK_SET_REG_DOW(regs,t->dow); - MSTK_SET_REG_DOM(regs,t->dom); - MSTK_SET_REG_MONTH(regs,t->month); - MSTK_SET_REG_YEAR(regs,t->year - MSTK_YEAR_ZERO); - - tmp = mostek_read(regs + MOSTEK_CREG); - tmp &= ~MSTK_CREG_WRITE; - mostek_write(regs + MOSTEK_CREG, tmp); - - spin_unlock_irq(&mostek_lock); -} - -static int put_rtc_time_generic(void __user *argp, struct rtc_time *tm) -{ - struct rtc_time_generic __user *utm = argp; - - if (__put_user(tm->sec, &utm->tm_sec) || - __put_user(tm->min, &utm->tm_min) || - __put_user(tm->hour, &utm->tm_hour) || - __put_user(tm->dom, &utm->tm_mday) || - __put_user(tm->month, &utm->tm_mon) || - __put_user(tm->year, &utm->tm_year) || - __put_user(tm->dow, &utm->tm_wday) || - __put_user(0, &utm->tm_yday) || - __put_user(0, &utm->tm_isdst)) - return -EFAULT; - - return 0; -} - -static int get_rtc_time_generic(struct rtc_time *tm, void __user *argp) -{ - struct rtc_time_generic __user *utm = argp; - - if (__get_user(tm->sec, &utm->tm_sec) || - __get_user(tm->min, &utm->tm_min) || - __get_user(tm->hour, &utm->tm_hour) || - __get_user(tm->dom, &utm->tm_mday) || - __get_user(tm->month, &utm->tm_mon) || - __get_user(tm->year, &utm->tm_year) || - __get_user(tm->dow, &utm->tm_wday)) - return -EFAULT; - - return 0; -} - -static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct rtc_time rtc_tm; - void __user *argp = (void __user *)arg; - - switch (cmd) { - /* No interrupt support, return an error - * compatible with drivers/char/rtc.c - */ - case RTC_AIE_OFF: - case RTC_AIE_ON: - case RTC_PIE_OFF: - case RTC_PIE_ON: - case RTC_UIE_OFF: - case RTC_UIE_ON: - case RTC_IRQP_READ: - case RTC_IRQP_SET: - case RTC_EPOCH_SET: - case RTC_EPOCH_READ: - return -EINVAL; - - case RTCGET: - case RTC_RD_TIME: - memset(&rtc_tm, 0, sizeof(struct rtc_time)); - get_rtc_time(&rtc_tm); - - if (cmd == RTCGET) { - if (copy_to_user(argp, &rtc_tm, - sizeof(struct rtc_time))) - return -EFAULT; - } else if (put_rtc_time_generic(argp, &rtc_tm)) - return -EFAULT; - - return 0; - - - case RTCSET: - case RTC_SET_TIME: - if (!capable(CAP_SYS_TIME)) - return -EPERM; - - if (cmd == RTCSET) { - if (copy_from_user(&rtc_tm, argp, - sizeof(struct rtc_time))) - return -EFAULT; - } else if (get_rtc_time_generic(&rtc_tm, argp)) - return -EFAULT; - - set_rtc_time(&rtc_tm); - - return 0; - - default: - return -EINVAL; - } -} - -static int rtc_open(struct inode *inode, struct file *file) -{ - int ret; - - lock_kernel(); - spin_lock_irq(&mostek_lock); - if (rtc_busy) { - ret = -EBUSY; - } else { - rtc_busy = 1; - ret = 0; - } - spin_unlock_irq(&mostek_lock); - unlock_kernel(); - - return ret; -} - -static int rtc_release(struct inode *inode, struct file *file) -{ - rtc_busy = 0; - - return 0; -} - -static const struct file_operations rtc_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = rtc_ioctl, - .open = rtc_open, - .release = rtc_release, -}; - -static struct miscdevice rtc_dev = { RTC_MINOR, "rtc", &rtc_fops }; - -static int __init rtc_sun_init(void) -{ - int error; - - /* It is possible we are being driven by some other RTC chip - * and thus another RTC driver is handling things. - */ - if (!mstk48t02_regs) - return -ENODEV; - - error = misc_register(&rtc_dev); - if (error) { - printk(KERN_ERR "rtc: unable to get misc minor for Mostek\n"); - return error; - } - printk("rtc_sun_init: Registered Mostek RTC driver.\n"); - - return 0; -} - -static void __exit rtc_sun_cleanup(void) -{ - misc_deregister(&rtc_dev); -} - -module_init(rtc_sun_init); -module_exit(rtc_sun_cleanup); -MODULE_LICENSE("GPL"); -- cgit v1.2.3