mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 11:11:45 -04:00
Merge master.kernel.org:/pub/scm/linux/kernel/git/paulus/powerpc
* master.kernel.org:/pub/scm/linux/kernel/git/paulus/powerpc: (194 commits) [POWERPC] Add missing EXPORTS for mpc52xx support [POWERPC] Remove obsolete PPC_52xx and update CLASSIC32 comment [POWERPC] ps3: add a default zImage target [POWERPC] Add of_platform_bus support to mpc52xx psc uart driver [POWERPC] typo fix and whitespace cleanup on mpc52xx-uart driver [POWERPC] Fix debug printks for 32-bit resources in the PCI code [POWERPC] Replace kmalloc+memset with kzalloc [POWERPC] Linkstation / kurobox support [POWERPC] Add the e300c3 core to the CPU table. [POWERPC] ppc: m48t35 add missing bracket [POWERPC] iSeries: don't build head_64.o unnecessarily [POWERPC] iSeries: stop dt_mod.o being rebuilt unnecessarily [POWERPC] Fix cputable.h for combined build [POWERPC] Allow CONFIG_BOOTX_TEXT on iSeries [POWERPC] Allow xmon to build on legacy iSeries [POWERPC] Change ppc64_defconfig to use AUTOFS_V4 not V3 [POWERPC] Tell firmware we can handle POWER6 compatible mode [POWERPC] Clean images in arch/powerpc/boot [POWERPC] Fix OF pci flags parsing [POWERPC] defconfig for lite5200 board ...
This commit is contained in:
commit
15a4cb9c25
298 changed files with 25464 additions and 5051 deletions
|
|
@ -77,3 +77,4 @@ obj-$(CONFIG_CRYPTO) += crypto/
|
|||
obj-$(CONFIG_SUPERH) += sh/
|
||||
obj-$(CONFIG_GENERIC_TIME) += clocksource/
|
||||
obj-$(CONFIG_DMA_ENGINE) += dma/
|
||||
obj-$(CONFIG_PPC_PS3) += ps3/
|
||||
|
|
|
|||
|
|
@ -759,6 +759,8 @@ static struct vio_driver viodasd_driver = {
|
|||
}
|
||||
};
|
||||
|
||||
static int need_delete_probe;
|
||||
|
||||
/*
|
||||
* Initialize the whole device driver. Handle module and non-module
|
||||
* versions
|
||||
|
|
@ -773,46 +775,67 @@ static int __init viodasd_init(void)
|
|||
|
||||
if (viopath_hostLp == HvLpIndexInvalid) {
|
||||
printk(VIOD_KERN_WARNING "invalid hosting partition\n");
|
||||
return -EIO;
|
||||
rc = -EIO;
|
||||
goto early_fail;
|
||||
}
|
||||
|
||||
printk(VIOD_KERN_INFO "vers " VIOD_VERS ", hosting partition %d\n",
|
||||
viopath_hostLp);
|
||||
|
||||
/* register the block device */
|
||||
if (register_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME)) {
|
||||
rc = register_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME);
|
||||
if (rc) {
|
||||
printk(VIOD_KERN_WARNING
|
||||
"Unable to get major number %d for %s\n",
|
||||
VIODASD_MAJOR, VIOD_GENHD_NAME);
|
||||
return -EIO;
|
||||
goto early_fail;
|
||||
}
|
||||
/* Actually open the path to the hosting partition */
|
||||
if (viopath_open(viopath_hostLp, viomajorsubtype_blockio,
|
||||
VIOMAXREQ + 2)) {
|
||||
rc = viopath_open(viopath_hostLp, viomajorsubtype_blockio,
|
||||
VIOMAXREQ + 2);
|
||||
if (rc) {
|
||||
printk(VIOD_KERN_WARNING
|
||||
"error opening path to host partition %d\n",
|
||||
viopath_hostLp);
|
||||
unregister_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME);
|
||||
return -EIO;
|
||||
goto unregister_blk;
|
||||
}
|
||||
|
||||
/* Initialize our request handler */
|
||||
vio_setHandler(viomajorsubtype_blockio, handle_block_event);
|
||||
|
||||
rc = vio_register_driver(&viodasd_driver);
|
||||
if (rc == 0)
|
||||
driver_create_file(&viodasd_driver.driver, &driver_attr_probe);
|
||||
if (rc) {
|
||||
printk(VIOD_KERN_WARNING "vio_register_driver failed\n");
|
||||
goto unset_handler;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this call fails, it just means that we cannot dynamically
|
||||
* add virtual disks, but the driver will still work fine for
|
||||
* all existing disk, so ignore the failure.
|
||||
*/
|
||||
if (!driver_create_file(&viodasd_driver.driver, &driver_attr_probe))
|
||||
need_delete_probe = 1;
|
||||
|
||||
return 0;
|
||||
|
||||
unset_handler:
|
||||
vio_clearHandler(viomajorsubtype_blockio);
|
||||
viopath_close(viopath_hostLp, viomajorsubtype_blockio, VIOMAXREQ + 2);
|
||||
unregister_blk:
|
||||
unregister_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME);
|
||||
early_fail:
|
||||
return rc;
|
||||
}
|
||||
module_init(viodasd_init);
|
||||
|
||||
void viodasd_exit(void)
|
||||
void __exit viodasd_exit(void)
|
||||
{
|
||||
driver_remove_file(&viodasd_driver.driver, &driver_attr_probe);
|
||||
if (need_delete_probe)
|
||||
driver_remove_file(&viodasd_driver.driver, &driver_attr_probe);
|
||||
vio_unregister_driver(&viodasd_driver);
|
||||
vio_clearHandler(viomajorsubtype_blockio);
|
||||
unregister_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME);
|
||||
viopath_close(viopath_hostLp, viomajorsubtype_blockio, VIOMAXREQ + 2);
|
||||
unregister_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME);
|
||||
}
|
||||
|
||||
module_exit(viodasd_exit);
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
#include <linux/ide.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#ifdef CONFIG_PPC_MULTIPLATFORM
|
||||
#ifdef CONFIG_PPC_CHRP
|
||||
#include <asm/processor.h>
|
||||
#endif
|
||||
|
||||
|
|
@ -442,7 +442,7 @@ static void __devinit init_hwif_via82cxxx(ide_hwif_t *hwif)
|
|||
hwif->speedproc = &via_set_drive;
|
||||
|
||||
|
||||
#if defined(CONFIG_PPC_CHRP) && defined(CONFIG_PPC32)
|
||||
#ifdef CONFIG_PPC_CHRP
|
||||
if(machine_is(chrp) && _chrp_type == _CHRP_Pegasos) {
|
||||
hwif->irq = hwif->channel ? 15 : 14;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -228,4 +228,11 @@ config ANSLCD
|
|||
tristate "Support for ANS LCD display"
|
||||
depends on ADB_CUDA && PPC_PMAC
|
||||
|
||||
config PMAC_RACKMETER
|
||||
tristate "Support for Apple XServe front panel LEDs"
|
||||
depends on PPC_PMAC
|
||||
help
|
||||
This driver procides some support to control the front panel
|
||||
blue LEDs "vu-meter" of the XServer macs.
|
||||
|
||||
endmenu
|
||||
|
|
|
|||
|
|
@ -42,3 +42,4 @@ obj-$(CONFIG_WINDFARM_PM112) += windfarm_pm112.o windfarm_smu_sat.o \
|
|||
windfarm_smu_sensors.o \
|
||||
windfarm_max6690_sensor.o \
|
||||
windfarm_lm75_sensor.o windfarm_pid.o
|
||||
obj-$(CONFIG_PMAC_RACKMETER) += rack-meter.o
|
||||
|
|
|
|||
612
drivers/macintosh/rack-meter.c
Normal file
612
drivers/macintosh/rack-meter.c
Normal file
|
|
@ -0,0 +1,612 @@
|
|||
/*
|
||||
* RackMac vu-meter driver
|
||||
*
|
||||
* (c) Copyright 2006 Benjamin Herrenschmidt, IBM Corp.
|
||||
* <benh@kernel.crashing.org>
|
||||
*
|
||||
* Released under the term of the GNU GPL v2.
|
||||
*
|
||||
* Support the CPU-meter LEDs of the Xserve G5
|
||||
*
|
||||
* TODO: Implement PWM to do variable intensity and provide userland
|
||||
* interface for fun. Also, the CPU-meter could be made nicer by being
|
||||
* a bit less "immediate" but giving instead a more average load over
|
||||
* time. Patches welcome :-)
|
||||
*
|
||||
*/
|
||||
#undef DEBUG
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/machdep.h>
|
||||
#include <asm/pmac_feature.h>
|
||||
#include <asm/dbdma.h>
|
||||
#include <asm/dbdma.h>
|
||||
#include <asm/macio.h>
|
||||
#include <asm/keylargo.h>
|
||||
|
||||
/* Number of samples in a sample buffer */
|
||||
#define SAMPLE_COUNT 256
|
||||
|
||||
/* CPU meter sampling rate in ms */
|
||||
#define CPU_SAMPLING_RATE 250
|
||||
|
||||
struct rackmeter_dma {
|
||||
struct dbdma_cmd cmd[4] ____cacheline_aligned;
|
||||
u32 mark ____cacheline_aligned;
|
||||
u32 buf1[SAMPLE_COUNT] ____cacheline_aligned;
|
||||
u32 buf2[SAMPLE_COUNT] ____cacheline_aligned;
|
||||
} ____cacheline_aligned;
|
||||
|
||||
struct rackmeter_cpu {
|
||||
struct work_struct sniffer;
|
||||
cputime64_t prev_wall;
|
||||
cputime64_t prev_idle;
|
||||
int zero;
|
||||
} ____cacheline_aligned;
|
||||
|
||||
struct rackmeter {
|
||||
struct macio_dev *mdev;
|
||||
unsigned int irq;
|
||||
struct device_node *i2s;
|
||||
u8 *ubuf;
|
||||
struct dbdma_regs __iomem *dma_regs;
|
||||
void __iomem *i2s_regs;
|
||||
dma_addr_t dma_buf_p;
|
||||
struct rackmeter_dma *dma_buf_v;
|
||||
int stale_irq;
|
||||
struct rackmeter_cpu cpu[2];
|
||||
int paused;
|
||||
struct mutex sem;
|
||||
};
|
||||
|
||||
/* To be set as a tunable */
|
||||
static int rackmeter_ignore_nice;
|
||||
|
||||
/* This GPIO is whacked by the OS X driver when initializing */
|
||||
#define RACKMETER_MAGIC_GPIO 0x78
|
||||
|
||||
/* This is copied from cpufreq_ondemand, maybe we should put it in
|
||||
* a common header somewhere
|
||||
*/
|
||||
static inline cputime64_t get_cpu_idle_time(unsigned int cpu)
|
||||
{
|
||||
cputime64_t retval;
|
||||
|
||||
retval = cputime64_add(kstat_cpu(cpu).cpustat.idle,
|
||||
kstat_cpu(cpu).cpustat.iowait);
|
||||
|
||||
if (rackmeter_ignore_nice)
|
||||
retval = cputime64_add(retval, kstat_cpu(cpu).cpustat.nice);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void rackmeter_setup_i2s(struct rackmeter *rm)
|
||||
{
|
||||
struct macio_chip *macio = rm->mdev->bus->chip;
|
||||
|
||||
/* First whack magic GPIO */
|
||||
pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, RACKMETER_MAGIC_GPIO, 5);
|
||||
|
||||
|
||||
/* Call feature code to enable the sound channel and the proper
|
||||
* clock sources
|
||||
*/
|
||||
pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, rm->i2s, 0, 1);
|
||||
|
||||
/* Power i2s and stop i2s clock. We whack MacIO FCRs directly for now.
|
||||
* This is a bit racy, thus we should add new platform functions to
|
||||
* handle that. snd-aoa needs that too
|
||||
*/
|
||||
MACIO_BIS(KEYLARGO_FCR1, KL1_I2S0_ENABLE);
|
||||
MACIO_BIC(KEYLARGO_FCR1, KL1_I2S0_CLK_ENABLE_BIT);
|
||||
(void)MACIO_IN32(KEYLARGO_FCR1);
|
||||
udelay(10);
|
||||
|
||||
/* Then setup i2s. For now, we use the same magic value that
|
||||
* the OS X driver seems to use. We might want to play around
|
||||
* with the clock divisors later
|
||||
*/
|
||||
out_le32(rm->i2s_regs + 0x10, 0x01fa0000);
|
||||
(void)in_le32(rm->i2s_regs + 0x10);
|
||||
udelay(10);
|
||||
|
||||
/* Fully restart i2s*/
|
||||
MACIO_BIS(KEYLARGO_FCR1, KL1_I2S0_CELL_ENABLE |
|
||||
KL1_I2S0_CLK_ENABLE_BIT);
|
||||
(void)MACIO_IN32(KEYLARGO_FCR1);
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
static void rackmeter_set_default_pattern(struct rackmeter *rm)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (i < 8)
|
||||
rm->ubuf[i] = (i & 1) * 255;
|
||||
else
|
||||
rm->ubuf[i] = ((~i) & 1) * 255;
|
||||
}
|
||||
}
|
||||
|
||||
static void rackmeter_do_pause(struct rackmeter *rm, int pause)
|
||||
{
|
||||
struct rackmeter_dma *rdma = rm->dma_buf_v;
|
||||
|
||||
pr_debug("rackmeter: %s\n", pause ? "paused" : "started");
|
||||
|
||||
rm->paused = pause;
|
||||
if (pause) {
|
||||
DBDMA_DO_STOP(rm->dma_regs);
|
||||
return;
|
||||
}
|
||||
memset(rdma->buf1, 0, SAMPLE_COUNT & sizeof(u32));
|
||||
memset(rdma->buf2, 0, SAMPLE_COUNT & sizeof(u32));
|
||||
|
||||
rm->dma_buf_v->mark = 0;
|
||||
|
||||
mb();
|
||||
out_le32(&rm->dma_regs->cmdptr_hi, 0);
|
||||
out_le32(&rm->dma_regs->cmdptr, rm->dma_buf_p);
|
||||
out_le32(&rm->dma_regs->control, (RUN << 16) | RUN);
|
||||
}
|
||||
|
||||
static void rackmeter_setup_dbdma(struct rackmeter *rm)
|
||||
{
|
||||
struct rackmeter_dma *db = rm->dma_buf_v;
|
||||
struct dbdma_cmd *cmd = db->cmd;
|
||||
|
||||
/* Make sure dbdma is reset */
|
||||
DBDMA_DO_RESET(rm->dma_regs);
|
||||
|
||||
pr_debug("rackmeter: mark offset=0x%lx\n",
|
||||
offsetof(struct rackmeter_dma, mark));
|
||||
pr_debug("rackmeter: buf1 offset=0x%lx\n",
|
||||
offsetof(struct rackmeter_dma, buf1));
|
||||
pr_debug("rackmeter: buf2 offset=0x%lx\n",
|
||||
offsetof(struct rackmeter_dma, buf2));
|
||||
|
||||
/* Prepare 4 dbdma commands for the 2 buffers */
|
||||
memset(cmd, 0, 4 * sizeof(struct dbdma_cmd));
|
||||
st_le16(&cmd->req_count, 4);
|
||||
st_le16(&cmd->command, STORE_WORD | INTR_ALWAYS | KEY_SYSTEM);
|
||||
st_le32(&cmd->phy_addr, rm->dma_buf_p +
|
||||
offsetof(struct rackmeter_dma, mark));
|
||||
st_le32(&cmd->cmd_dep, 0x02000000);
|
||||
cmd++;
|
||||
|
||||
st_le16(&cmd->req_count, SAMPLE_COUNT * 4);
|
||||
st_le16(&cmd->command, OUTPUT_MORE);
|
||||
st_le32(&cmd->phy_addr, rm->dma_buf_p +
|
||||
offsetof(struct rackmeter_dma, buf1));
|
||||
cmd++;
|
||||
|
||||
st_le16(&cmd->req_count, 4);
|
||||
st_le16(&cmd->command, STORE_WORD | INTR_ALWAYS | KEY_SYSTEM);
|
||||
st_le32(&cmd->phy_addr, rm->dma_buf_p +
|
||||
offsetof(struct rackmeter_dma, mark));
|
||||
st_le32(&cmd->cmd_dep, 0x01000000);
|
||||
cmd++;
|
||||
|
||||
st_le16(&cmd->req_count, SAMPLE_COUNT * 4);
|
||||
st_le16(&cmd->command, OUTPUT_MORE | BR_ALWAYS);
|
||||
st_le32(&cmd->phy_addr, rm->dma_buf_p +
|
||||
offsetof(struct rackmeter_dma, buf2));
|
||||
st_le32(&cmd->cmd_dep, rm->dma_buf_p);
|
||||
|
||||
rackmeter_do_pause(rm, 0);
|
||||
}
|
||||
|
||||
static void rackmeter_do_timer(void *data)
|
||||
{
|
||||
struct rackmeter *rm = data;
|
||||
unsigned int cpu = smp_processor_id();
|
||||
struct rackmeter_cpu *rcpu = &rm->cpu[cpu];
|
||||
cputime64_t cur_jiffies, total_idle_ticks;
|
||||
unsigned int total_ticks, idle_ticks;
|
||||
int i, offset, load, cumm, pause;
|
||||
|
||||
cur_jiffies = jiffies64_to_cputime64(get_jiffies_64());
|
||||
total_ticks = (unsigned int)cputime64_sub(cur_jiffies,
|
||||
rcpu->prev_wall);
|
||||
rcpu->prev_wall = cur_jiffies;
|
||||
|
||||
total_idle_ticks = get_cpu_idle_time(cpu);
|
||||
idle_ticks = (unsigned int) cputime64_sub(total_idle_ticks,
|
||||
rcpu->prev_idle);
|
||||
rcpu->prev_idle = total_idle_ticks;
|
||||
|
||||
/* We do a very dumb calculation to update the LEDs for now,
|
||||
* we'll do better once we have actual PWM implemented
|
||||
*/
|
||||
load = (9 * (total_ticks - idle_ticks)) / total_ticks;
|
||||
|
||||
offset = cpu << 3;
|
||||
cumm = 0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
u8 ub = (load > i) ? 0xff : 0;
|
||||
rm->ubuf[i + offset] = ub;
|
||||
cumm |= ub;
|
||||
}
|
||||
rcpu->zero = (cumm == 0);
|
||||
|
||||
/* Now check if LEDs are all 0, we can stop DMA */
|
||||
pause = (rm->cpu[0].zero && rm->cpu[1].zero);
|
||||
if (pause != rm->paused) {
|
||||
mutex_lock(&rm->sem);
|
||||
pause = (rm->cpu[0].zero && rm->cpu[1].zero);
|
||||
rackmeter_do_pause(rm, pause);
|
||||
mutex_unlock(&rm->sem);
|
||||
}
|
||||
schedule_delayed_work_on(cpu, &rcpu->sniffer,
|
||||
msecs_to_jiffies(CPU_SAMPLING_RATE));
|
||||
}
|
||||
|
||||
static void __devinit rackmeter_init_cpu_sniffer(struct rackmeter *rm)
|
||||
{
|
||||
unsigned int cpu;
|
||||
|
||||
/* This driver works only with 1 or 2 CPUs numbered 0 and 1,
|
||||
* but that's really all we have on Apple Xserve. It doesn't
|
||||
* play very nice with CPU hotplug neither but we don't do that
|
||||
* on those machines yet
|
||||
*/
|
||||
|
||||
INIT_WORK(&rm->cpu[0].sniffer, rackmeter_do_timer, rm);
|
||||
INIT_WORK(&rm->cpu[1].sniffer, rackmeter_do_timer, rm);
|
||||
|
||||
for_each_online_cpu(cpu) {
|
||||
struct rackmeter_cpu *rcpu;
|
||||
|
||||
if (cpu > 1)
|
||||
continue;
|
||||
rcpu = &rm->cpu[cpu];;
|
||||
rcpu->prev_idle = get_cpu_idle_time(cpu);
|
||||
rcpu->prev_wall = jiffies64_to_cputime64(get_jiffies_64());
|
||||
schedule_delayed_work_on(cpu, &rm->cpu[cpu].sniffer,
|
||||
msecs_to_jiffies(CPU_SAMPLING_RATE));
|
||||
}
|
||||
}
|
||||
|
||||
static void __devexit rackmeter_stop_cpu_sniffer(struct rackmeter *rm)
|
||||
{
|
||||
cancel_rearming_delayed_work(&rm->cpu[0].sniffer);
|
||||
cancel_rearming_delayed_work(&rm->cpu[1].sniffer);
|
||||
}
|
||||
|
||||
static int rackmeter_setup(struct rackmeter *rm)
|
||||
{
|
||||
pr_debug("rackmeter: setting up i2s..\n");
|
||||
rackmeter_setup_i2s(rm);
|
||||
|
||||
pr_debug("rackmeter: setting up default pattern..\n");
|
||||
rackmeter_set_default_pattern(rm);
|
||||
|
||||
pr_debug("rackmeter: setting up dbdma..\n");
|
||||
rackmeter_setup_dbdma(rm);
|
||||
|
||||
pr_debug("rackmeter: start CPU measurements..\n");
|
||||
rackmeter_init_cpu_sniffer(rm);
|
||||
|
||||
printk(KERN_INFO "RackMeter initialized\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* XXX FIXME: No PWM yet, this is 0/1 */
|
||||
static u32 rackmeter_calc_sample(struct rackmeter *rm, unsigned int index)
|
||||
{
|
||||
int led;
|
||||
u32 sample = 0;
|
||||
|
||||
for (led = 0; led < 16; led++) {
|
||||
sample >>= 1;
|
||||
sample |= ((rm->ubuf[led] >= 0x80) << 15);
|
||||
}
|
||||
return (sample << 17) | (sample >> 15);
|
||||
}
|
||||
|
||||
static irqreturn_t rackmeter_irq(int irq, void *arg)
|
||||
{
|
||||
struct rackmeter *rm = arg;
|
||||
struct rackmeter_dma *db = rm->dma_buf_v;
|
||||
unsigned int mark, i;
|
||||
u32 *buf;
|
||||
|
||||
/* Flush PCI buffers with an MMIO read. Maybe we could actually
|
||||
* check the status one day ... in case things go wrong, though
|
||||
* this never happened to me
|
||||
*/
|
||||
(void)in_le32(&rm->dma_regs->status);
|
||||
|
||||
/* Make sure the CPU gets us in order */
|
||||
rmb();
|
||||
|
||||
/* Read mark */
|
||||
mark = db->mark;
|
||||
if (mark != 1 && mark != 2) {
|
||||
printk(KERN_WARNING "rackmeter: Incorrect DMA mark 0x%08x\n",
|
||||
mark);
|
||||
/* We allow for 3 errors like that (stale DBDMA irqs) */
|
||||
if (++rm->stale_irq > 3) {
|
||||
printk(KERN_ERR "rackmeter: Too many errors,"
|
||||
" stopping DMA\n");
|
||||
DBDMA_DO_RESET(rm->dma_regs);
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* Next buffer we need to fill is mark value */
|
||||
buf = mark == 1 ? db->buf1 : db->buf2;
|
||||
|
||||
/* Fill it now. This routine converts the 8 bits depth sample array
|
||||
* into the PWM bitmap for each LED.
|
||||
*/
|
||||
for (i = 0; i < SAMPLE_COUNT; i++)
|
||||
buf[i] = rackmeter_calc_sample(rm, i);
|
||||
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __devinit rackmeter_probe(struct macio_dev* mdev,
|
||||
const struct of_device_id *match)
|
||||
{
|
||||
struct device_node *i2s = NULL, *np = NULL;
|
||||
struct rackmeter *rm = NULL;
|
||||
struct resource ri2s, rdma;
|
||||
int rc = -ENODEV;
|
||||
|
||||
pr_debug("rackmeter_probe()\n");
|
||||
|
||||
/* Get i2s-a node */
|
||||
while ((i2s = of_get_next_child(mdev->ofdev.node, i2s)) != NULL)
|
||||
if (strcmp(i2s->name, "i2s-a") == 0)
|
||||
break;
|
||||
if (i2s == NULL) {
|
||||
pr_debug(" i2s-a child not found\n");
|
||||
goto bail;
|
||||
}
|
||||
/* Get lightshow or virtual sound */
|
||||
while ((np = of_get_next_child(i2s, np)) != NULL) {
|
||||
if (strcmp(np->name, "lightshow") == 0)
|
||||
break;
|
||||
if ((strcmp(np->name, "sound") == 0) &&
|
||||
get_property(np, "virtual", NULL) != NULL)
|
||||
break;
|
||||
}
|
||||
if (np == NULL) {
|
||||
pr_debug(" lightshow or sound+virtual child not found\n");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* Create and initialize our instance data */
|
||||
rm = kzalloc(sizeof(struct rackmeter), GFP_KERNEL);
|
||||
if (rm == NULL) {
|
||||
printk(KERN_ERR "rackmeter: failed to allocate memory !\n");
|
||||
rc = -ENOMEM;
|
||||
goto bail_release;
|
||||
}
|
||||
rm->mdev = mdev;
|
||||
rm->i2s = i2s;
|
||||
mutex_init(&rm->sem);
|
||||
dev_set_drvdata(&mdev->ofdev.dev, rm);
|
||||
/* Check resources availability. We need at least resource 0 and 1 */
|
||||
#if 0 /* Use that when i2s-a is finally an mdev per-se */
|
||||
if (macio_resource_count(mdev) < 2 || macio_irq_count(mdev) < 2) {
|
||||
printk(KERN_ERR
|
||||
"rackmeter: found match but lacks resources: %s"
|
||||
" (%d resources, %d interrupts)\n",
|
||||
mdev->ofdev.node->full_name);
|
||||
rc = -ENXIO;
|
||||
goto bail_free;
|
||||
}
|
||||
if (macio_request_resources(mdev, "rackmeter")) {
|
||||
printk(KERN_ERR
|
||||
"rackmeter: failed to request resources: %s\n",
|
||||
mdev->ofdev.node->full_name);
|
||||
rc = -EBUSY;
|
||||
goto bail_free;
|
||||
}
|
||||
rm->irq = macio_irq(mdev, 1);
|
||||
#else
|
||||
rm->irq = irq_of_parse_and_map(i2s, 1);
|
||||
if (rm->irq == NO_IRQ ||
|
||||
of_address_to_resource(i2s, 0, &ri2s) ||
|
||||
of_address_to_resource(i2s, 1, &rdma)) {
|
||||
printk(KERN_ERR
|
||||
"rackmeter: found match but lacks resources: %s",
|
||||
mdev->ofdev.node->full_name);
|
||||
rc = -ENXIO;
|
||||
goto bail_free;
|
||||
}
|
||||
#endif
|
||||
|
||||
pr_debug(" i2s @0x%08x\n", (unsigned int)ri2s.start);
|
||||
pr_debug(" dma @0x%08x\n", (unsigned int)rdma.start);
|
||||
pr_debug(" irq %d\n", rm->irq);
|
||||
|
||||
rm->ubuf = (u8 *)__get_free_page(GFP_KERNEL);
|
||||
if (rm->ubuf == NULL) {
|
||||
printk(KERN_ERR
|
||||
"rackmeter: failed to allocate samples page !\n");
|
||||
rc = -ENOMEM;
|
||||
goto bail_release;
|
||||
}
|
||||
|
||||
rm->dma_buf_v = dma_alloc_coherent(&macio_get_pci_dev(mdev)->dev,
|
||||
sizeof(struct rackmeter_dma),
|
||||
&rm->dma_buf_p, GFP_KERNEL);
|
||||
if (rm->dma_buf_v == NULL) {
|
||||
printk(KERN_ERR
|
||||
"rackmeter: failed to allocate dma buffer !\n");
|
||||
rc = -ENOMEM;
|
||||
goto bail_free_samples;
|
||||
}
|
||||
#if 0
|
||||
rm->i2s_regs = ioremap(macio_resource_start(mdev, 0), 0x1000);
|
||||
#else
|
||||
rm->i2s_regs = ioremap(ri2s.start, 0x1000);
|
||||
#endif
|
||||
if (rm->i2s_regs == NULL) {
|
||||
printk(KERN_ERR
|
||||
"rackmeter: failed to map i2s registers !\n");
|
||||
rc = -ENXIO;
|
||||
goto bail_free_dma;
|
||||
}
|
||||
#if 0
|
||||
rm->dma_regs = ioremap(macio_resource_start(mdev, 1), 0x100);
|
||||
#else
|
||||
rm->dma_regs = ioremap(rdma.start, 0x100);
|
||||
#endif
|
||||
if (rm->dma_regs == NULL) {
|
||||
printk(KERN_ERR
|
||||
"rackmeter: failed to map dma registers !\n");
|
||||
rc = -ENXIO;
|
||||
goto bail_unmap_i2s;
|
||||
}
|
||||
|
||||
rc = rackmeter_setup(rm);
|
||||
if (rc) {
|
||||
printk(KERN_ERR
|
||||
"rackmeter: failed to initialize !\n");
|
||||
rc = -ENXIO;
|
||||
goto bail_unmap_dma;
|
||||
}
|
||||
|
||||
rc = request_irq(rm->irq, rackmeter_irq, 0, "rackmeter", rm);
|
||||
if (rc != 0) {
|
||||
printk(KERN_ERR
|
||||
"rackmeter: failed to request interrupt !\n");
|
||||
goto bail_stop_dma;
|
||||
}
|
||||
of_node_put(np);
|
||||
return 0;
|
||||
|
||||
bail_stop_dma:
|
||||
DBDMA_DO_RESET(rm->dma_regs);
|
||||
bail_unmap_dma:
|
||||
iounmap(rm->dma_regs);
|
||||
bail_unmap_i2s:
|
||||
iounmap(rm->i2s_regs);
|
||||
bail_free_dma:
|
||||
dma_free_coherent(&macio_get_pci_dev(mdev)->dev,
|
||||
sizeof(struct rackmeter_dma),
|
||||
rm->dma_buf_v, rm->dma_buf_p);
|
||||
bail_free_samples:
|
||||
free_page((unsigned long)rm->ubuf);
|
||||
bail_release:
|
||||
#if 0
|
||||
macio_release_resources(mdev);
|
||||
#endif
|
||||
bail_free:
|
||||
kfree(rm);
|
||||
bail:
|
||||
of_node_put(i2s);
|
||||
of_node_put(np);
|
||||
dev_set_drvdata(&mdev->ofdev.dev, NULL);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __devexit rackmeter_remove(struct macio_dev* mdev)
|
||||
{
|
||||
struct rackmeter *rm = dev_get_drvdata(&mdev->ofdev.dev);
|
||||
|
||||
/* Stop CPU sniffer timer & work queues */
|
||||
rackmeter_stop_cpu_sniffer(rm);
|
||||
|
||||
/* Clear reference to private data */
|
||||
dev_set_drvdata(&mdev->ofdev.dev, NULL);
|
||||
|
||||
/* Stop/reset dbdma */
|
||||
DBDMA_DO_RESET(rm->dma_regs);
|
||||
|
||||
/* Release the IRQ */
|
||||
free_irq(rm->irq, rm);
|
||||
|
||||
/* Unmap registers */
|
||||
iounmap(rm->dma_regs);
|
||||
iounmap(rm->i2s_regs);
|
||||
|
||||
/* Free DMA */
|
||||
dma_free_coherent(&macio_get_pci_dev(mdev)->dev,
|
||||
sizeof(struct rackmeter_dma),
|
||||
rm->dma_buf_v, rm->dma_buf_p);
|
||||
|
||||
/* Free samples */
|
||||
free_page((unsigned long)rm->ubuf);
|
||||
|
||||
#if 0
|
||||
/* Release resources */
|
||||
macio_release_resources(mdev);
|
||||
#endif
|
||||
|
||||
/* Get rid of me */
|
||||
kfree(rm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rackmeter_shutdown(struct macio_dev* mdev)
|
||||
{
|
||||
struct rackmeter *rm = dev_get_drvdata(&mdev->ofdev.dev);
|
||||
|
||||
if (rm == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
/* Stop CPU sniffer timer & work queues */
|
||||
rackmeter_stop_cpu_sniffer(rm);
|
||||
|
||||
/* Stop/reset dbdma */
|
||||
DBDMA_DO_RESET(rm->dma_regs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id rackmeter_match[] = {
|
||||
{ .name = "i2s" },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct macio_driver rackmeter_drv = {
|
||||
.name = "rackmeter",
|
||||
.owner = THIS_MODULE,
|
||||
.match_table = rackmeter_match,
|
||||
.probe = rackmeter_probe,
|
||||
.remove = rackmeter_remove,
|
||||
.shutdown = rackmeter_shutdown,
|
||||
};
|
||||
|
||||
|
||||
static int __init rackmeter_init(void)
|
||||
{
|
||||
pr_debug("rackmeter_init()\n");
|
||||
|
||||
return macio_register_driver(&rackmeter_drv);
|
||||
}
|
||||
|
||||
static void __exit rackmeter_exit(void)
|
||||
{
|
||||
pr_debug("rackmeter_exit()\n");
|
||||
|
||||
macio_unregister_driver(&rackmeter_drv);
|
||||
}
|
||||
|
||||
module_init(rackmeter_init);
|
||||
module_exit(rackmeter_exit);
|
||||
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Benjamin Herrenschmidt <[email protected]>");
|
||||
MODULE_DESCRIPTION("RackMeter: Support vu-meter on XServe front panel");
|
||||
|
|
@ -46,6 +46,7 @@
|
|||
#include <asm/abs_addr.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/of_device.h>
|
||||
#include <asm/of_platform.h>
|
||||
|
||||
#define VERSION "0.7"
|
||||
#define AUTHOR "(c) 2005 Benjamin Herrenschmidt, IBM Corp."
|
||||
|
|
@ -653,7 +654,7 @@ static int __init smu_init_sysfs(void)
|
|||
* I'm a bit too far from figuring out how that works with those
|
||||
* new chipsets, but that will come back and bite us
|
||||
*/
|
||||
of_register_driver(&smu_of_platform_driver);
|
||||
of_register_platform_driver(&smu_of_platform_driver);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
#include <asm/io.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/of_device.h>
|
||||
#include <asm/of_platform.h>
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@
|
|||
#include <asm/sections.h>
|
||||
#include <asm/of_device.h>
|
||||
#include <asm/macio.h>
|
||||
#include <asm/of_platform.h>
|
||||
|
||||
#include "therm_pm72.h"
|
||||
|
||||
|
|
@ -2236,14 +2237,14 @@ static int __init therm_pm72_init(void)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
of_register_driver(&fcu_of_platform_driver);
|
||||
of_register_platform_driver(&fcu_of_platform_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit therm_pm72_exit(void)
|
||||
{
|
||||
of_unregister_driver(&fcu_of_platform_driver);
|
||||
of_unregister_platform_driver(&fcu_of_platform_driver);
|
||||
|
||||
if (of_dev)
|
||||
of_device_unregister(of_dev);
|
||||
|
|
|
|||
|
|
@ -36,12 +36,13 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <asm/prom.h>
|
||||
#include <asm/machdep.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/of_device.h>
|
||||
#include <asm/of_platform.h>
|
||||
#include <asm/macio.h>
|
||||
|
||||
#define LOG_TEMP 0 /* continously log temperature */
|
||||
|
|
@ -511,14 +512,14 @@ g4fan_init( void )
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
of_register_driver( &therm_of_driver );
|
||||
of_register_platform_driver( &therm_of_driver );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit
|
||||
g4fan_exit( void )
|
||||
{
|
||||
of_unregister_driver( &therm_of_driver );
|
||||
of_unregister_platform_driver( &therm_of_driver );
|
||||
|
||||
if( x.of_dev )
|
||||
of_device_unregister( x.of_dev );
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/netdevice.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/dcr.h>
|
||||
|
||||
/*
|
||||
* These MAL "versions" probably aren't the real versions IBM uses for these
|
||||
|
|
@ -191,6 +192,7 @@ struct mal_commac {
|
|||
|
||||
struct ibm_ocp_mal {
|
||||
int dcrbase;
|
||||
dcr_host_t dcrhost;
|
||||
|
||||
struct list_head poll_list;
|
||||
struct net_device poll_dev;
|
||||
|
|
@ -207,12 +209,12 @@ struct ibm_ocp_mal {
|
|||
|
||||
static inline u32 get_mal_dcrn(struct ibm_ocp_mal *mal, int reg)
|
||||
{
|
||||
return mfdcr(mal->dcrbase + reg);
|
||||
return dcr_read(mal->dcrhost, mal->dcrbase + reg);
|
||||
}
|
||||
|
||||
static inline void set_mal_dcrn(struct ibm_ocp_mal *mal, int reg, u32 val)
|
||||
{
|
||||
mtdcr(mal->dcrbase + reg, val);
|
||||
dcr_write(mal->dcrhost, mal->dcrbase + reg, val);
|
||||
}
|
||||
|
||||
/* Register MAL devices */
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@
|
|||
#include <asm/semaphore.h>
|
||||
#include <asm/hvcall.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/iommu.h>
|
||||
#include <asm/vio.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
|
@ -1000,8 +999,6 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
|
|||
adapter->mac_addr = 0;
|
||||
memcpy(&adapter->mac_addr, mac_addr_p, 6);
|
||||
|
||||
adapter->liobn = dev->iommu_table->it_index;
|
||||
|
||||
netdev->irq = dev->irq;
|
||||
netdev->open = ibmveth_open;
|
||||
netdev->poll = ibmveth_poll;
|
||||
|
|
@ -1115,7 +1112,6 @@ static int ibmveth_seq_show(struct seq_file *seq, void *v)
|
|||
seq_printf(seq, "%s %s\n\n", ibmveth_driver_string, ibmveth_driver_version);
|
||||
|
||||
seq_printf(seq, "Unit Address: 0x%x\n", adapter->vdev->unit_address);
|
||||
seq_printf(seq, "LIOBN: 0x%lx\n", adapter->liobn);
|
||||
seq_printf(seq, "Current MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
|
||||
current_mac[0], current_mac[1], current_mac[2],
|
||||
current_mac[3], current_mac[4], current_mac[5]);
|
||||
|
|
|
|||
|
|
@ -118,7 +118,6 @@ struct ibmveth_adapter {
|
|||
struct net_device_stats stats;
|
||||
unsigned int mcastFilterSize;
|
||||
unsigned long mac_addr;
|
||||
unsigned long liobn;
|
||||
void * buffer_list_addr;
|
||||
void * filter_list_addr;
|
||||
dma_addr_t buffer_list_dma;
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@ static int fixed_mdio_register_device(int number, int speed, int duplex)
|
|||
goto device_create_fail;
|
||||
}
|
||||
|
||||
phydev->irq = -1;
|
||||
phydev->irq = PHY_IGNORE_INTERRUPT;
|
||||
phydev->dev.bus = &mdio_bus_type;
|
||||
|
||||
if(number)
|
||||
|
|
|
|||
|
|
@ -88,12 +88,11 @@ MODULE_DEVICE_TABLE(pci, spider_net_pci_tbl);
|
|||
static inline u32
|
||||
spider_net_read_reg(struct spider_net_card *card, u32 reg)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = readl(card->regs + reg);
|
||||
value = le32_to_cpu(value);
|
||||
|
||||
return value;
|
||||
/* We use the powerpc specific variants instead of readl_be() because
|
||||
* we know spidernet is not a real PCI device and we can thus avoid the
|
||||
* performance hit caused by the PCI workarounds.
|
||||
*/
|
||||
return in_be32(card->regs + reg);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -105,8 +104,11 @@ spider_net_read_reg(struct spider_net_card *card, u32 reg)
|
|||
static inline void
|
||||
spider_net_write_reg(struct spider_net_card *card, u32 reg, u32 value)
|
||||
{
|
||||
value = cpu_to_le32(value);
|
||||
writel(value, card->regs + reg);
|
||||
/* We use the powerpc specific variants instead of writel_be() because
|
||||
* we know spidernet is not a real PCI device and we can thus avoid the
|
||||
* performance hit caused by the PCI workarounds.
|
||||
*/
|
||||
out_be32(card->regs + reg, value);
|
||||
}
|
||||
|
||||
/** spider_net_write_phy - write to phy register
|
||||
|
|
|
|||
|
|
@ -473,9 +473,9 @@
|
|||
#include <asm/byteorder.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <asm/uaccess.h>
|
||||
#ifdef CONFIG_PPC_MULTIPLATFORM
|
||||
#ifdef CONFIG_PPC_PMAC
|
||||
#include <asm/machdep.h>
|
||||
#endif /* CONFIG_PPC_MULTIPLATFORM */
|
||||
#endif /* CONFIG_PPC_PMAC */
|
||||
|
||||
#include "de4x5.h"
|
||||
|
||||
|
|
@ -4151,7 +4151,7 @@ get_hw_addr(struct net_device *dev)
|
|||
/* If possible, try to fix a broken card - SMC only so far */
|
||||
srom_repair(dev, broken);
|
||||
|
||||
#ifdef CONFIG_PPC_MULTIPLATFORM
|
||||
#ifdef CONFIG_PPC_PMAC
|
||||
/*
|
||||
** If the address starts with 00 a0, we have to bit-reverse
|
||||
** each byte of the address.
|
||||
|
|
@ -4168,7 +4168,7 @@ get_hw_addr(struct net_device *dev)
|
|||
dev->dev_addr[i] = ((x & 0x55) << 1) + ((x & 0xaa) >> 1);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_PPC_MULTIPLATFORM */
|
||||
#endif /* CONFIG_PPC_PMAC */
|
||||
|
||||
/* Test for a bad enet address */
|
||||
status = test_bad_enet(dev, status);
|
||||
|
|
|
|||
1
drivers/ps3/Makefile
Normal file
1
drivers/ps3/Makefile
Normal file
|
|
@ -0,0 +1 @@
|
|||
obj-y += system-bus.o
|
||||
362
drivers/ps3/system-bus.c
Normal file
362
drivers/ps3/system-bus.c
Normal file
|
|
@ -0,0 +1,362 @@
|
|||
/*
|
||||
* PS3 system bus driver.
|
||||
*
|
||||
* Copyright (C) 2006 Sony Computer Entertainment Inc.
|
||||
* Copyright 2006 Sony Corp.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <asm/udbg.h>
|
||||
#include <asm/ps3.h>
|
||||
#include <asm/lv1call.h>
|
||||
#include <asm/firmware.h>
|
||||
|
||||
#define dump_mmio_region(_a) _dump_mmio_region(_a, __func__, __LINE__)
|
||||
static void _dump_mmio_region(const struct ps3_mmio_region* r,
|
||||
const char* func, int line)
|
||||
{
|
||||
pr_debug("%s:%d: dev %u:%u\n", func, line, r->did.bus_id,
|
||||
r->did.dev_id);
|
||||
pr_debug("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr);
|
||||
pr_debug("%s:%d: len %lxh\n", func, line, r->len);
|
||||
pr_debug("%s:%d: lpar_addr %lxh\n", func, line, r->lpar_addr);
|
||||
}
|
||||
|
||||
int ps3_mmio_region_create(struct ps3_mmio_region *r)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = lv1_map_device_mmio_region(r->did.bus_id, r->did.dev_id,
|
||||
r->bus_addr, r->len, r->page_size, &r->lpar_addr);
|
||||
|
||||
if (result) {
|
||||
pr_debug("%s:%d: lv1_map_device_mmio_region failed: %s\n",
|
||||
__func__, __LINE__, ps3_result(result));
|
||||
r->lpar_addr = r->len = r->bus_addr = 0;
|
||||
}
|
||||
|
||||
dump_mmio_region(r);
|
||||
return result;
|
||||
}
|
||||
|
||||
int ps3_free_mmio_region(struct ps3_mmio_region *r)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = lv1_unmap_device_mmio_region(r->did.bus_id, r->did.dev_id,
|
||||
r->bus_addr);
|
||||
|
||||
if (result)
|
||||
pr_debug("%s:%d: lv1_unmap_device_mmio_region failed: %s\n",
|
||||
__func__, __LINE__, ps3_result(result));
|
||||
|
||||
r->lpar_addr = r->len = r->bus_addr = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
static int ps3_system_bus_match(struct device *_dev,
|
||||
struct device_driver *_drv)
|
||||
{
|
||||
int result;
|
||||
struct ps3_system_bus_driver *drv = to_ps3_system_bus_driver(_drv);
|
||||
struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
|
||||
|
||||
result = dev->match_id == drv->match_id;
|
||||
|
||||
pr_info("%s:%d: dev=%u(%s), drv=%u(%s): %s\n", __func__, __LINE__,
|
||||
dev->match_id, dev->core.bus_id, drv->match_id, drv->core.name,
|
||||
(result ? "match" : "miss"));
|
||||
return result;
|
||||
}
|
||||
|
||||
static int ps3_system_bus_probe(struct device *_dev)
|
||||
{
|
||||
int result;
|
||||
struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
|
||||
struct ps3_system_bus_driver *drv =
|
||||
to_ps3_system_bus_driver(_dev->driver);
|
||||
|
||||
result = lv1_open_device(dev->did.bus_id, dev->did.dev_id, 0);
|
||||
|
||||
if (result) {
|
||||
pr_debug("%s:%d: lv1_open_device failed (%d)\n",
|
||||
__func__, __LINE__, result);
|
||||
result = -EACCES;
|
||||
goto clean_none;
|
||||
}
|
||||
|
||||
if (dev->d_region->did.bus_id) {
|
||||
result = ps3_dma_region_create(dev->d_region);
|
||||
|
||||
if (result) {
|
||||
pr_debug("%s:%d: ps3_dma_region_create failed (%d)\n",
|
||||
__func__, __LINE__, result);
|
||||
BUG_ON("check region type");
|
||||
result = -EINVAL;
|
||||
goto clean_device;
|
||||
}
|
||||
}
|
||||
|
||||
BUG_ON(!drv);
|
||||
|
||||
if (drv->probe)
|
||||
result = drv->probe(dev);
|
||||
else
|
||||
pr_info("%s:%d: %s no probe method\n", __func__, __LINE__,
|
||||
dev->core.bus_id);
|
||||
|
||||
if (result) {
|
||||
pr_debug("%s:%d: drv->probe failed\n", __func__, __LINE__);
|
||||
goto clean_dma;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
clean_dma:
|
||||
ps3_dma_region_free(dev->d_region);
|
||||
clean_device:
|
||||
lv1_close_device(dev->did.bus_id, dev->did.dev_id);
|
||||
clean_none:
|
||||
return result;
|
||||
}
|
||||
|
||||
static int ps3_system_bus_remove(struct device *_dev)
|
||||
{
|
||||
struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
|
||||
struct ps3_system_bus_driver *drv =
|
||||
to_ps3_system_bus_driver(_dev->driver);
|
||||
|
||||
if (drv->remove)
|
||||
drv->remove(dev);
|
||||
else
|
||||
pr_info("%s:%d: %s no remove method\n", __func__, __LINE__,
|
||||
dev->core.bus_id);
|
||||
|
||||
ps3_dma_region_free(dev->d_region);
|
||||
ps3_free_mmio_region(dev->m_region);
|
||||
lv1_close_device(dev->did.bus_id, dev->did.dev_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct bus_type ps3_system_bus_type = {
|
||||
.name = "ps3_system_bus",
|
||||
.match = ps3_system_bus_match,
|
||||
.probe = ps3_system_bus_probe,
|
||||
.remove = ps3_system_bus_remove,
|
||||
};
|
||||
|
||||
int __init ps3_system_bus_init(void)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
|
||||
return 0;
|
||||
|
||||
result = bus_register(&ps3_system_bus_type);
|
||||
BUG_ON(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
core_initcall(ps3_system_bus_init);
|
||||
|
||||
/* Allocates a contiguous real buffer and creates mappings over it.
|
||||
* Returns the virtual address of the buffer and sets dma_handle
|
||||
* to the dma address (mapping) of the first page.
|
||||
*/
|
||||
|
||||
static void * ps3_alloc_coherent(struct device *_dev, size_t size,
|
||||
dma_addr_t *dma_handle, gfp_t flag)
|
||||
{
|
||||
int result;
|
||||
struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
|
||||
unsigned long virt_addr;
|
||||
|
||||
BUG_ON(!dev->d_region->bus_addr);
|
||||
|
||||
flag &= ~(__GFP_DMA | __GFP_HIGHMEM);
|
||||
flag |= __GFP_ZERO;
|
||||
|
||||
virt_addr = __get_free_pages(flag, get_order(size));
|
||||
|
||||
if (!virt_addr) {
|
||||
pr_debug("%s:%d: get_free_pages failed\n", __func__, __LINE__);
|
||||
goto clean_none;
|
||||
}
|
||||
|
||||
result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle);
|
||||
|
||||
if (result) {
|
||||
pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
|
||||
__func__, __LINE__, result);
|
||||
BUG_ON("check region type");
|
||||
goto clean_alloc;
|
||||
}
|
||||
|
||||
return (void*)virt_addr;
|
||||
|
||||
clean_alloc:
|
||||
free_pages(virt_addr, get_order(size));
|
||||
clean_none:
|
||||
dma_handle = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr,
|
||||
dma_addr_t dma_handle)
|
||||
{
|
||||
struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
|
||||
|
||||
ps3_dma_unmap(dev->d_region, dma_handle, size);
|
||||
free_pages((unsigned long)vaddr, get_order(size));
|
||||
}
|
||||
|
||||
/* Creates TCEs for a user provided buffer. The user buffer must be
|
||||
* contiguous real kernel storage (not vmalloc). The address of the buffer
|
||||
* passed here is the kernel (virtual) address of the buffer. The buffer
|
||||
* need not be page aligned, the dma_addr_t returned will point to the same
|
||||
* byte within the page as vaddr.
|
||||
*/
|
||||
|
||||
static dma_addr_t ps3_map_single(struct device *_dev, void *ptr, size_t size,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
|
||||
int result;
|
||||
unsigned long bus_addr;
|
||||
|
||||
result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size,
|
||||
&bus_addr);
|
||||
|
||||
if (result) {
|
||||
pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
|
||||
__func__, __LINE__, result);
|
||||
}
|
||||
|
||||
return bus_addr;
|
||||
}
|
||||
|
||||
static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr,
|
||||
size_t size, enum dma_data_direction direction)
|
||||
{
|
||||
struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
|
||||
int result;
|
||||
|
||||
result = ps3_dma_unmap(dev->d_region, dma_addr, size);
|
||||
|
||||
if (result) {
|
||||
pr_debug("%s:%d: ps3_dma_unmap failed (%d)\n",
|
||||
__func__, __LINE__, result);
|
||||
}
|
||||
}
|
||||
|
||||
static int ps3_map_sg(struct device *_dev, struct scatterlist *sg, int nents,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
#if defined(CONFIG_PS3_DYNAMIC_DMA)
|
||||
BUG_ON("do");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ps3_unmap_sg(struct device *_dev, struct scatterlist *sg,
|
||||
int nents, enum dma_data_direction direction)
|
||||
{
|
||||
#if defined(CONFIG_PS3_DYNAMIC_DMA)
|
||||
BUG_ON("do");
|
||||
#endif
|
||||
}
|
||||
|
||||
static int ps3_dma_supported(struct device *_dev, u64 mask)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct dma_mapping_ops ps3_dma_ops = {
|
||||
.alloc_coherent = ps3_alloc_coherent,
|
||||
.free_coherent = ps3_free_coherent,
|
||||
.map_single = ps3_map_single,
|
||||
.unmap_single = ps3_unmap_single,
|
||||
.map_sg = ps3_map_sg,
|
||||
.unmap_sg = ps3_unmap_sg,
|
||||
.dma_supported = ps3_dma_supported
|
||||
};
|
||||
|
||||
/**
|
||||
* ps3_system_bus_release_device - remove a device from the system bus
|
||||
*/
|
||||
|
||||
static void ps3_system_bus_release_device(struct device *_dev)
|
||||
{
|
||||
struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* ps3_system_bus_device_register - add a device to the system bus
|
||||
*
|
||||
* ps3_system_bus_device_register() expects the dev object to be allocated
|
||||
* dynamically by the caller. The system bus takes ownership of the dev
|
||||
* object and frees the object in ps3_system_bus_release_device().
|
||||
*/
|
||||
|
||||
int ps3_system_bus_device_register(struct ps3_system_bus_device *dev)
|
||||
{
|
||||
int result;
|
||||
static unsigned int dev_count = 1;
|
||||
|
||||
dev->core.parent = NULL;
|
||||
dev->core.bus = &ps3_system_bus_type;
|
||||
dev->core.release = ps3_system_bus_release_device;
|
||||
|
||||
dev->core.archdata.of_node = NULL;
|
||||
dev->core.archdata.dma_ops = &ps3_dma_ops;
|
||||
dev->core.archdata.numa_node = 0;
|
||||
|
||||
snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "sb_%02x",
|
||||
dev_count++);
|
||||
|
||||
pr_debug("%s:%d add %s\n", __func__, __LINE__, dev->core.bus_id);
|
||||
|
||||
result = device_register(&dev->core);
|
||||
return result;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(ps3_system_bus_device_register);
|
||||
|
||||
int ps3_system_bus_driver_register(struct ps3_system_bus_driver *drv)
|
||||
{
|
||||
int result;
|
||||
|
||||
drv->core.bus = &ps3_system_bus_type;
|
||||
|
||||
result = driver_register(&drv->core);
|
||||
return result;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(ps3_system_bus_driver_register);
|
||||
|
||||
void ps3_system_bus_driver_unregister(struct ps3_system_bus_driver *drv)
|
||||
{
|
||||
driver_unregister(&drv->core);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(ps3_system_bus_driver_unregister);
|
||||
|
|
@ -282,7 +282,7 @@ void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
|
|||
}
|
||||
|
||||
/* Setup any dynamic params in the uart desc */
|
||||
int cpm_uart_init_portdesc(void)
|
||||
int __init cpm_uart_init_portdesc(void)
|
||||
{
|
||||
#if defined(CONFIG_SERIAL_CPM_SMC1) || defined(CONFIG_SERIAL_CPM_SMC2)
|
||||
u32 addr;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
/*
|
||||
* drivers/serial/mpc52xx_uart.c
|
||||
*
|
||||
* Driver for the PSC of the Freescale MPC52xx PSCs configured as UARTs.
|
||||
*
|
||||
* FIXME According to the usermanual the status bits in the status register
|
||||
|
|
@ -14,18 +12,20 @@
|
|||
*
|
||||
*
|
||||
* Maintainer : Sylvain Munaut <tnt@246tNt.com>
|
||||
*
|
||||
*
|
||||
* Some of the code has been inspired/copied from the 2.4 code written
|
||||
* by Dale Farnsworth <dfarnsworth@mvista.com>.
|
||||
*
|
||||
* Copyright (C) 2004-2005 Sylvain Munaut <tnt@246tNt.com>
|
||||
*
|
||||
* Copyright (C) 2006 Secret Lab Technologies Ltd.
|
||||
* Grant Likely <grant.likely@secretlab.ca>
|
||||
* Copyright (C) 2004-2006 Sylvain Munaut <tnt@246tNt.com>
|
||||
* Copyright (C) 2003 MontaVista, Software, Inc.
|
||||
*
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program is licensed "as is" without any warranty of any
|
||||
* kind, whether express or implied.
|
||||
*/
|
||||
|
||||
|
||||
/* Platform device Usage :
|
||||
*
|
||||
* Since PSCs can have multiple function, the correct driver for each one
|
||||
|
|
@ -44,7 +44,24 @@
|
|||
* will be mapped to.
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
/* OF Platform device Usage :
|
||||
*
|
||||
* This driver is only used for PSCs configured in uart mode. The device
|
||||
* tree will have a node for each PSC in uart mode w/ device_type = "serial"
|
||||
* and "mpc52xx-psc-uart" in the compatible string
|
||||
*
|
||||
* By default, PSC devices are enumerated in the order they are found. However
|
||||
* a particular PSC number can be forces by adding 'device_no = <port#>'
|
||||
* to the device node.
|
||||
*
|
||||
* The driver init all necessary registers to place the PSC in uart mode without
|
||||
* DCD. However, the pin multiplexing aren't changed and should be set either
|
||||
* by the bootloader or in the platform init code.
|
||||
*/
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/serial.h>
|
||||
|
|
@ -54,6 +71,12 @@
|
|||
#include <asm/delay.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#if defined(CONFIG_PPC_MERGE)
|
||||
#include <asm/of_platform.h>
|
||||
#else
|
||||
#include <linux/platform_device.h>
|
||||
#endif
|
||||
|
||||
#include <asm/mpc52xx.h>
|
||||
#include <asm/mpc52xx_psc.h>
|
||||
|
||||
|
|
@ -80,6 +103,12 @@ static struct uart_port mpc52xx_uart_ports[MPC52xx_PSC_MAXNUM];
|
|||
* it's cleared, then a memset(...,0,...) should be added to
|
||||
* the console_init
|
||||
*/
|
||||
#if defined(CONFIG_PPC_MERGE)
|
||||
/* lookup table for matching device nodes to index numbers */
|
||||
static struct device_node *mpc52xx_uart_nodes[MPC52xx_PSC_MAXNUM];
|
||||
|
||||
static void mpc52xx_uart_of_enumerate(void);
|
||||
#endif
|
||||
|
||||
#define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase))
|
||||
|
||||
|
|
@ -96,32 +125,40 @@ static irqreturn_t mpc52xx_uart_int(int irq,void *dev_id);
|
|||
#define uart_console(port) (0)
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PPC_MERGE)
|
||||
static struct of_device_id mpc52xx_uart_of_match[] = {
|
||||
{ .type = "serial", .compatible = "mpc52xx-psc-uart", },
|
||||
{ .type = "serial", .compatible = "mpc5200-psc", }, /* Efika only! */
|
||||
{},
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
/* UART operations */
|
||||
/* ======================================================================== */
|
||||
|
||||
static unsigned int
|
||||
static unsigned int
|
||||
mpc52xx_uart_tx_empty(struct uart_port *port)
|
||||
{
|
||||
int status = in_be16(&PSC(port)->mpc52xx_psc_status);
|
||||
return (status & MPC52xx_PSC_SR_TXEMP) ? TIOCSER_TEMT : 0;
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
mpc52xx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
/* Not implemented */
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
static unsigned int
|
||||
mpc52xx_uart_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
/* Not implemented */
|
||||
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
mpc52xx_uart_stop_tx(struct uart_port *port)
|
||||
{
|
||||
/* port->lock taken by caller */
|
||||
|
|
@ -129,7 +166,7 @@ mpc52xx_uart_stop_tx(struct uart_port *port)
|
|||
out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
mpc52xx_uart_start_tx(struct uart_port *port)
|
||||
{
|
||||
/* port->lock taken by caller */
|
||||
|
|
@ -137,12 +174,12 @@ mpc52xx_uart_start_tx(struct uart_port *port)
|
|||
out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
mpc52xx_uart_send_xchar(struct uart_port *port, char ch)
|
||||
{
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
|
||||
port->x_char = ch;
|
||||
if (ch) {
|
||||
/* Make sure tx interrupts are on */
|
||||
|
|
@ -150,7 +187,7 @@ mpc52xx_uart_send_xchar(struct uart_port *port, char ch)
|
|||
port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
|
||||
out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);
|
||||
}
|
||||
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
|
|
@ -178,7 +215,7 @@ mpc52xx_uart_break_ctl(struct uart_port *port, int ctl)
|
|||
out_8(&PSC(port)->command,MPC52xx_PSC_START_BRK);
|
||||
else
|
||||
out_8(&PSC(port)->command,MPC52xx_PSC_STOP_BRK);
|
||||
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
|
|
@ -197,11 +234,11 @@ mpc52xx_uart_startup(struct uart_port *port)
|
|||
/* Reset/activate the port, clear and enable interrupts */
|
||||
out_8(&psc->command,MPC52xx_PSC_RST_RX);
|
||||
out_8(&psc->command,MPC52xx_PSC_RST_TX);
|
||||
|
||||
|
||||
out_be32(&psc->sicr,0); /* UART mode DCD ignored */
|
||||
|
||||
out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); /* /16 prescaler on */
|
||||
|
||||
|
||||
out_8(&psc->rfcntl, 0x00);
|
||||
out_be16(&psc->rfalarm, 0x1ff);
|
||||
out_8(&psc->tfcntl, 0x07);
|
||||
|
|
@ -209,10 +246,10 @@ mpc52xx_uart_startup(struct uart_port *port)
|
|||
|
||||
port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY;
|
||||
out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask);
|
||||
|
||||
|
||||
out_8(&psc->command,MPC52xx_PSC_TX_ENABLE);
|
||||
out_8(&psc->command,MPC52xx_PSC_RX_ENABLE);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -220,19 +257,19 @@ static void
|
|||
mpc52xx_uart_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct mpc52xx_psc __iomem *psc = PSC(port);
|
||||
|
||||
|
||||
/* Shut down the port, interrupt and all */
|
||||
out_8(&psc->command,MPC52xx_PSC_RST_RX);
|
||||
out_8(&psc->command,MPC52xx_PSC_RST_TX);
|
||||
|
||||
port->read_status_mask = 0;
|
||||
|
||||
port->read_status_mask = 0;
|
||||
out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask);
|
||||
|
||||
/* Release interrupt */
|
||||
free_irq(port->irq, port);
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
mpc52xx_uart_set_termios(struct uart_port *port, struct termios *new,
|
||||
struct termios *old)
|
||||
{
|
||||
|
|
@ -241,10 +278,10 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct termios *new,
|
|||
unsigned char mr1, mr2;
|
||||
unsigned short ctr;
|
||||
unsigned int j, baud, quot;
|
||||
|
||||
|
||||
/* Prepare what we're gonna write */
|
||||
mr1 = 0;
|
||||
|
||||
|
||||
switch (new->c_cflag & CSIZE) {
|
||||
case CS5: mr1 |= MPC52xx_PSC_MODE_5_BITS;
|
||||
break;
|
||||
|
|
@ -261,8 +298,8 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct termios *new,
|
|||
MPC52xx_PSC_MODE_PARODD : MPC52xx_PSC_MODE_PAREVEN;
|
||||
} else
|
||||
mr1 |= MPC52xx_PSC_MODE_PARNONE;
|
||||
|
||||
|
||||
|
||||
|
||||
mr2 = 0;
|
||||
|
||||
if (new->c_cflag & CSTOPB)
|
||||
|
|
@ -276,7 +313,7 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct termios *new,
|
|||
baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
|
||||
quot = uart_get_divisor(port, baud);
|
||||
ctr = quot & 0xffff;
|
||||
|
||||
|
||||
/* Get the lock */
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
|
|
@ -290,14 +327,14 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct termios *new,
|
|||
* boot for the console, all stuff is not yet ready to receive at that
|
||||
* time and that just makes the kernel oops */
|
||||
/* while (j-- && mpc52xx_uart_int_rx_chars(port)); */
|
||||
while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) &&
|
||||
while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) &&
|
||||
--j)
|
||||
udelay(1);
|
||||
|
||||
if (!j)
|
||||
printk( KERN_ERR "mpc52xx_uart.c: "
|
||||
"Unable to flush RX & TX fifos in-time in set_termios."
|
||||
"Some chars may have been lost.\n" );
|
||||
"Some chars may have been lost.\n" );
|
||||
|
||||
/* Reset the TX & RX */
|
||||
out_8(&psc->command,MPC52xx_PSC_RST_RX);
|
||||
|
|
@ -309,7 +346,7 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct termios *new,
|
|||
out_8(&psc->mode,mr2);
|
||||
out_8(&psc->ctur,ctr >> 8);
|
||||
out_8(&psc->ctlr,ctr & 0xff);
|
||||
|
||||
|
||||
/* Reenable TX & RX */
|
||||
out_8(&psc->command,MPC52xx_PSC_TX_ENABLE);
|
||||
out_8(&psc->command,MPC52xx_PSC_RX_ENABLE);
|
||||
|
|
@ -332,7 +369,7 @@ mpc52xx_uart_release_port(struct uart_port *port)
|
|||
port->membase = NULL;
|
||||
}
|
||||
|
||||
release_mem_region(port->mapbase, MPC52xx_PSC_SIZE);
|
||||
release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc));
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -341,12 +378,13 @@ mpc52xx_uart_request_port(struct uart_port *port)
|
|||
int err;
|
||||
|
||||
if (port->flags & UPF_IOREMAP) /* Need to remap ? */
|
||||
port->membase = ioremap(port->mapbase, MPC52xx_PSC_SIZE);
|
||||
port->membase = ioremap(port->mapbase,
|
||||
sizeof(struct mpc52xx_psc));
|
||||
|
||||
if (!port->membase)
|
||||
return -EINVAL;
|
||||
|
||||
err = request_mem_region(port->mapbase, MPC52xx_PSC_SIZE,
|
||||
err = request_mem_region(port->mapbase, sizeof(struct mpc52xx_psc),
|
||||
"mpc52xx_psc_uart") != NULL ? 0 : -EBUSY;
|
||||
|
||||
if (err && (port->flags & UPF_IOREMAP)) {
|
||||
|
|
@ -373,7 +411,7 @@ mpc52xx_uart_verify_port(struct uart_port *port, struct serial_struct *ser)
|
|||
|
||||
if ( (ser->irq != port->irq) ||
|
||||
(ser->io_type != SERIAL_IO_MEM) ||
|
||||
(ser->baud_base != port->uartclk) ||
|
||||
(ser->baud_base != port->uartclk) ||
|
||||
(ser->iomem_base != (void*)port->mapbase) ||
|
||||
(ser->hub6 != 0 ) )
|
||||
return -EINVAL;
|
||||
|
|
@ -404,11 +442,11 @@ static struct uart_ops mpc52xx_uart_ops = {
|
|||
.verify_port = mpc52xx_uart_verify_port
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
/* Interrupt handling */
|
||||
/* ======================================================================== */
|
||||
|
||||
|
||||
static inline int
|
||||
mpc52xx_uart_int_rx_chars(struct uart_port *port)
|
||||
{
|
||||
|
|
@ -435,11 +473,11 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
|
|||
|
||||
flag = TTY_NORMAL;
|
||||
port->icount.rx++;
|
||||
|
||||
|
||||
if ( status & (MPC52xx_PSC_SR_PE |
|
||||
MPC52xx_PSC_SR_FE |
|
||||
MPC52xx_PSC_SR_RB) ) {
|
||||
|
||||
|
||||
if (status & MPC52xx_PSC_SR_RB) {
|
||||
flag = TTY_BREAK;
|
||||
uart_handle_break(port);
|
||||
|
|
@ -464,7 +502,7 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
|
|||
}
|
||||
|
||||
tty_flip_buffer_push(tty);
|
||||
|
||||
|
||||
return in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_RXRDY;
|
||||
}
|
||||
|
||||
|
|
@ -509,25 +547,25 @@ mpc52xx_uart_int_tx_chars(struct uart_port *port)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static irqreturn_t
|
||||
static irqreturn_t
|
||||
mpc52xx_uart_int(int irq, void *dev_id)
|
||||
{
|
||||
struct uart_port *port = dev_id;
|
||||
unsigned long pass = ISR_PASS_LIMIT;
|
||||
unsigned int keepgoing;
|
||||
unsigned short status;
|
||||
|
||||
|
||||
spin_lock(&port->lock);
|
||||
|
||||
|
||||
/* While we have stuff to do, we continue */
|
||||
do {
|
||||
/* If we don't find anything to do, we stop */
|
||||
keepgoing = 0;
|
||||
|
||||
keepgoing = 0;
|
||||
|
||||
/* Read status */
|
||||
status = in_be16(&PSC(port)->mpc52xx_psc_isr);
|
||||
status &= port->read_status_mask;
|
||||
|
||||
|
||||
/* Do we need to receive chars ? */
|
||||
/* For this RX interrupts must be on and some chars waiting */
|
||||
if ( status & MPC52xx_PSC_IMR_RXRDY )
|
||||
|
|
@ -537,15 +575,15 @@ mpc52xx_uart_int(int irq, void *dev_id)
|
|||
/* For this, TX must be ready and TX interrupt enabled */
|
||||
if ( status & MPC52xx_PSC_IMR_TXRDY )
|
||||
keepgoing |= mpc52xx_uart_int_tx_chars(port);
|
||||
|
||||
|
||||
/* Limit number of iteration */
|
||||
if ( !(--pass) )
|
||||
keepgoing = 0;
|
||||
|
||||
} while (keepgoing);
|
||||
|
||||
|
||||
spin_unlock(&port->lock);
|
||||
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
|
@ -563,13 +601,18 @@ mpc52xx_console_get_options(struct uart_port *port,
|
|||
struct mpc52xx_psc __iomem *psc = PSC(port);
|
||||
unsigned char mr1;
|
||||
|
||||
pr_debug("mpc52xx_console_get_options(port=%p)\n", port);
|
||||
|
||||
/* Read the mode registers */
|
||||
out_8(&psc->command,MPC52xx_PSC_SEL_MODE_REG_1);
|
||||
mr1 = in_8(&psc->mode);
|
||||
|
||||
|
||||
/* CT{U,L}R are write-only ! */
|
||||
*baud = __res.bi_baudrate ?
|
||||
__res.bi_baudrate : CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
|
||||
*baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
|
||||
#if !defined(CONFIG_PPC_MERGE)
|
||||
if (__res.bi_baudrate)
|
||||
*baud = __res.bi_baudrate;
|
||||
#endif
|
||||
|
||||
/* Parse them */
|
||||
switch (mr1 & MPC52xx_PSC_MODE_BITS_MASK) {
|
||||
|
|
@ -579,26 +622,26 @@ mpc52xx_console_get_options(struct uart_port *port,
|
|||
case MPC52xx_PSC_MODE_8_BITS:
|
||||
default: *bits = 8;
|
||||
}
|
||||
|
||||
|
||||
if (mr1 & MPC52xx_PSC_MODE_PARNONE)
|
||||
*parity = 'n';
|
||||
else
|
||||
*parity = mr1 & MPC52xx_PSC_MODE_PARODD ? 'o' : 'e';
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
mpc52xx_console_write(struct console *co, const char *s, unsigned int count)
|
||||
{
|
||||
struct uart_port *port = &mpc52xx_uart_ports[co->index];
|
||||
struct mpc52xx_psc __iomem *psc = PSC(port);
|
||||
unsigned int i, j;
|
||||
|
||||
|
||||
/* Disable interrupts */
|
||||
out_be16(&psc->mpc52xx_psc_imr, 0);
|
||||
|
||||
/* Wait the TX buffer to be empty */
|
||||
j = 5000000; /* Maximum wait */
|
||||
while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) &&
|
||||
j = 5000000; /* Maximum wait */
|
||||
while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) &&
|
||||
--j)
|
||||
udelay(1);
|
||||
|
||||
|
|
@ -607,13 +650,13 @@ mpc52xx_console_write(struct console *co, const char *s, unsigned int count)
|
|||
/* Line return handling */
|
||||
if (*s == '\n')
|
||||
out_8(&psc->mpc52xx_psc_buffer_8, '\r');
|
||||
|
||||
|
||||
/* Send the char */
|
||||
out_8(&psc->mpc52xx_psc_buffer_8, *s);
|
||||
|
||||
/* Wait the TX buffer to be empty */
|
||||
j = 20000; /* Maximum wait */
|
||||
while (!(in_be16(&psc->mpc52xx_psc_status) &
|
||||
j = 20000; /* Maximum wait */
|
||||
while (!(in_be16(&psc->mpc52xx_psc_status) &
|
||||
MPC52xx_PSC_SR_TXEMP) && --j)
|
||||
udelay(1);
|
||||
}
|
||||
|
|
@ -622,6 +665,7 @@ mpc52xx_console_write(struct console *co, const char *s, unsigned int count)
|
|||
out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_PPC_MERGE)
|
||||
static int __init
|
||||
mpc52xx_console_setup(struct console *co, char *options)
|
||||
{
|
||||
|
|
@ -634,7 +678,7 @@ mpc52xx_console_setup(struct console *co, char *options)
|
|||
|
||||
if (co->index < 0 || co->index >= MPC52xx_PSC_MAXNUM)
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
/* Basic port init. Needed since we use some uart_??? func before
|
||||
* real init for early access */
|
||||
spin_lock_init(&port->lock);
|
||||
|
|
@ -656,6 +700,78 @@ mpc52xx_console_setup(struct console *co, char *options)
|
|||
return uart_set_options(port, co, baud, parity, bits, flow);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int __init
|
||||
mpc52xx_console_setup(struct console *co, char *options)
|
||||
{
|
||||
struct uart_port *port = &mpc52xx_uart_ports[co->index];
|
||||
struct device_node *np = mpc52xx_uart_nodes[co->index];
|
||||
unsigned int ipb_freq;
|
||||
struct resource res;
|
||||
int ret;
|
||||
|
||||
int baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
|
||||
int bits = 8;
|
||||
int parity = 'n';
|
||||
int flow = 'n';
|
||||
|
||||
pr_debug("mpc52xx_console_setup co=%p, co->index=%i, options=%s\n",
|
||||
co, co->index, options);
|
||||
|
||||
if ((co->index < 0) || (co->index > MPC52xx_PSC_MAXNUM)) {
|
||||
pr_debug("PSC%x out of range\n", co->index);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!np) {
|
||||
pr_debug("PSC%x not found in device tree\n", co->index);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pr_debug("Console on ttyPSC%x is %s\n",
|
||||
co->index, mpc52xx_uart_nodes[co->index]->full_name);
|
||||
|
||||
/* Fetch register locations */
|
||||
if ((ret = of_address_to_resource(np, 0, &res)) != 0) {
|
||||
pr_debug("Could not get resources for PSC%x\n", co->index);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Search for bus-frequency property in this node or a parent */
|
||||
if ((ipb_freq = mpc52xx_find_ipb_freq(np)) == 0) {
|
||||
pr_debug("Could not find IPB bus frequency!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Basic port init. Needed since we use some uart_??? func before
|
||||
* real init for early access */
|
||||
spin_lock_init(&port->lock);
|
||||
port->uartclk = ipb_freq / 2;
|
||||
port->ops = &mpc52xx_uart_ops;
|
||||
port->mapbase = res.start;
|
||||
port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc));
|
||||
port->irq = irq_of_parse_and_map(np, 0);
|
||||
|
||||
if (port->membase == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
pr_debug("mpc52xx-psc uart at %lx, mapped to %p, irq=%x, freq=%i\n",
|
||||
port->mapbase, port->membase, port->irq, port->uartclk);
|
||||
|
||||
/* Setup the port parameters accoding to options */
|
||||
if (options)
|
||||
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
||||
else
|
||||
mpc52xx_console_get_options(port, &baud, &parity, &bits, &flow);
|
||||
|
||||
pr_debug("Setting console parameters: %i %i%c1 flow=%c\n",
|
||||
baud, bits, parity, flow);
|
||||
|
||||
return uart_set_options(port, co, baud, parity, bits, flow);
|
||||
}
|
||||
#endif /* defined(CONFIG_PPC_MERGE) */
|
||||
|
||||
|
||||
static struct uart_driver mpc52xx_uart_driver;
|
||||
|
||||
|
|
@ -669,10 +785,11 @@ static struct console mpc52xx_console = {
|
|||
.data = &mpc52xx_uart_driver,
|
||||
};
|
||||
|
||||
|
||||
static int __init
|
||||
|
||||
static int __init
|
||||
mpc52xx_console_init(void)
|
||||
{
|
||||
mpc52xx_uart_of_enumerate();
|
||||
register_console(&mpc52xx_console);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -700,6 +817,7 @@ static struct uart_driver mpc52xx_uart_driver = {
|
|||
};
|
||||
|
||||
|
||||
#if !defined(CONFIG_PPC_MERGE)
|
||||
/* ======================================================================== */
|
||||
/* Platform Driver */
|
||||
/* ======================================================================== */
|
||||
|
|
@ -723,8 +841,6 @@ mpc52xx_uart_probe(struct platform_device *dev)
|
|||
/* Init the port structure */
|
||||
port = &mpc52xx_uart_ports[idx];
|
||||
|
||||
memset(port, 0x00, sizeof(struct uart_port));
|
||||
|
||||
spin_lock_init(&port->lock);
|
||||
port->uartclk = __res.bi_ipbfreq / 2; /* Look at CTLR doc */
|
||||
port->fifosize = 512;
|
||||
|
|
@ -733,6 +849,7 @@ mpc52xx_uart_probe(struct platform_device *dev)
|
|||
( uart_console(port) ? 0 : UPF_IOREMAP );
|
||||
port->line = idx;
|
||||
port->ops = &mpc52xx_uart_ops;
|
||||
port->dev = &dev->dev;
|
||||
|
||||
/* Search for IRQ and mapbase */
|
||||
for (i=0 ; i<dev->num_resources ; i++, res++) {
|
||||
|
|
@ -771,7 +888,7 @@ mpc52xx_uart_suspend(struct platform_device *dev, pm_message_t state)
|
|||
{
|
||||
struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev);
|
||||
|
||||
if (sport)
|
||||
if (port)
|
||||
uart_suspend_port(&mpc52xx_uart_driver, port);
|
||||
|
||||
return 0;
|
||||
|
|
@ -789,6 +906,7 @@ mpc52xx_uart_resume(struct platform_device *dev)
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
static struct platform_driver mpc52xx_uart_platform_driver = {
|
||||
.probe = mpc52xx_uart_probe,
|
||||
.remove = mpc52xx_uart_remove,
|
||||
|
|
@ -800,6 +918,184 @@ static struct platform_driver mpc52xx_uart_platform_driver = {
|
|||
.name = "mpc52xx-psc",
|
||||
},
|
||||
};
|
||||
#endif /* !defined(CONFIG_PPC_MERGE) */
|
||||
|
||||
|
||||
#if defined(CONFIG_PPC_MERGE)
|
||||
/* ======================================================================== */
|
||||
/* OF Platform Driver */
|
||||
/* ======================================================================== */
|
||||
|
||||
static int __devinit
|
||||
mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
|
||||
{
|
||||
int idx = -1;
|
||||
unsigned int ipb_freq;
|
||||
struct uart_port *port = NULL;
|
||||
struct resource res;
|
||||
int ret;
|
||||
|
||||
dev_dbg(&op->dev, "mpc52xx_uart_probe(op=%p, match=%p)\n", op, match);
|
||||
|
||||
/* Check validity & presence */
|
||||
for (idx = 0; idx < MPC52xx_PSC_MAXNUM; idx++)
|
||||
if (mpc52xx_uart_nodes[idx] == op->node)
|
||||
break;
|
||||
if (idx >= MPC52xx_PSC_MAXNUM)
|
||||
return -EINVAL;
|
||||
pr_debug("Found %s assigned to ttyPSC%x\n",
|
||||
mpc52xx_uart_nodes[idx]->full_name, idx);
|
||||
|
||||
/* Search for bus-frequency property in this node or a parent */
|
||||
if ((ipb_freq = mpc52xx_find_ipb_freq(op->node)) == 0) {
|
||||
dev_dbg(&op->dev, "Could not find IPB bus frequency!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Init the port structure */
|
||||
port = &mpc52xx_uart_ports[idx];
|
||||
|
||||
spin_lock_init(&port->lock);
|
||||
port->uartclk = ipb_freq / 2;
|
||||
port->fifosize = 512;
|
||||
port->iotype = UPIO_MEM;
|
||||
port->flags = UPF_BOOT_AUTOCONF |
|
||||
( uart_console(port) ? 0 : UPF_IOREMAP );
|
||||
port->line = idx;
|
||||
port->ops = &mpc52xx_uart_ops;
|
||||
port->dev = &op->dev;
|
||||
|
||||
/* Search for IRQ and mapbase */
|
||||
if ((ret = of_address_to_resource(op->node, 0, &res)) != 0)
|
||||
return ret;
|
||||
|
||||
port->mapbase = res.start;
|
||||
port->irq = irq_of_parse_and_map(op->node, 0);
|
||||
|
||||
dev_dbg(&op->dev, "mpc52xx-psc uart at %lx, irq=%x, freq=%i\n",
|
||||
port->mapbase, port->irq, port->uartclk);
|
||||
|
||||
if ((port->irq==NO_IRQ) || !port->mapbase) {
|
||||
printk(KERN_ERR "Could not allocate resources for PSC\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Add the port to the uart sub-system */
|
||||
ret = uart_add_one_port(&mpc52xx_uart_driver, port);
|
||||
if (!ret)
|
||||
dev_set_drvdata(&op->dev, (void*)port);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
mpc52xx_uart_of_remove(struct of_device *op)
|
||||
{
|
||||
struct uart_port *port = dev_get_drvdata(&op->dev);
|
||||
dev_set_drvdata(&op->dev, NULL);
|
||||
|
||||
if (port)
|
||||
uart_remove_one_port(&mpc52xx_uart_driver, port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int
|
||||
mpc52xx_uart_of_suspend(struct of_device *op, pm_message_t state)
|
||||
{
|
||||
struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev);
|
||||
|
||||
if (port)
|
||||
uart_suspend_port(&mpc52xx_uart_driver, port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mpc52xx_uart_of_resume(struct of_device *op)
|
||||
{
|
||||
struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev);
|
||||
|
||||
if (port)
|
||||
uart_resume_port(&mpc52xx_uart_driver, port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
mpc52xx_uart_of_assign(struct device_node *np, int idx)
|
||||
{
|
||||
int free_idx = -1;
|
||||
int i;
|
||||
|
||||
/* Find the first free node */
|
||||
for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) {
|
||||
if (mpc52xx_uart_nodes[i] == NULL) {
|
||||
free_idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((idx < 0) || (idx >= MPC52xx_PSC_MAXNUM))
|
||||
idx = free_idx;
|
||||
|
||||
if (idx < 0)
|
||||
return; /* No free slot; abort */
|
||||
|
||||
/* If the slot is already occupied, then swap slots */
|
||||
if (mpc52xx_uart_nodes[idx] && (free_idx != -1))
|
||||
mpc52xx_uart_nodes[free_idx] = mpc52xx_uart_nodes[idx];
|
||||
mpc52xx_uart_nodes[i] = np;
|
||||
}
|
||||
|
||||
static void
|
||||
mpc52xx_uart_of_enumerate(void)
|
||||
{
|
||||
static int enum_done = 0;
|
||||
struct device_node *np;
|
||||
const unsigned int *devno;
|
||||
int i;
|
||||
|
||||
if (enum_done)
|
||||
return;
|
||||
|
||||
for_each_node_by_type(np, "serial") {
|
||||
if (!of_match_node(mpc52xx_uart_of_match, np))
|
||||
continue;
|
||||
|
||||
/* Is a particular device number requested? */
|
||||
devno = get_property(np, "device_no", NULL);
|
||||
mpc52xx_uart_of_assign(of_node_get(np), devno ? *devno : -1);
|
||||
}
|
||||
|
||||
enum_done = 1;
|
||||
|
||||
for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) {
|
||||
if (mpc52xx_uart_nodes[i])
|
||||
pr_debug("%s assigned to ttyPSC%x\n",
|
||||
mpc52xx_uart_nodes[i]->full_name, i);
|
||||
}
|
||||
}
|
||||
|
||||
MODULE_DEVICE_TABLE(of, mpc52xx_uart_of_match);
|
||||
|
||||
static struct of_platform_driver mpc52xx_uart_of_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "mpc52xx-psc-uart",
|
||||
.match_table = mpc52xx_uart_of_match,
|
||||
.probe = mpc52xx_uart_of_probe,
|
||||
.remove = mpc52xx_uart_of_remove,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = mpc52xx_uart_of_suspend,
|
||||
.resume = mpc52xx_uart_of_resume,
|
||||
#endif
|
||||
.driver = {
|
||||
.name = "mpc52xx-psc-uart",
|
||||
},
|
||||
};
|
||||
#endif /* defined(CONFIG_PPC_MERGE) */
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
|
|
@ -811,22 +1107,45 @@ mpc52xx_uart_init(void)
|
|||
{
|
||||
int ret;
|
||||
|
||||
printk(KERN_INFO "Serial: MPC52xx PSC driver\n");
|
||||
printk(KERN_INFO "Serial: MPC52xx PSC UART driver\n");
|
||||
|
||||
ret = uart_register_driver(&mpc52xx_uart_driver);
|
||||
if (ret == 0) {
|
||||
ret = platform_driver_register(&mpc52xx_uart_platform_driver);
|
||||
if (ret)
|
||||
uart_unregister_driver(&mpc52xx_uart_driver);
|
||||
if ((ret = uart_register_driver(&mpc52xx_uart_driver)) != 0) {
|
||||
printk(KERN_ERR "%s: uart_register_driver failed (%i)\n",
|
||||
__FILE__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
#if defined(CONFIG_PPC_MERGE)
|
||||
mpc52xx_uart_of_enumerate();
|
||||
|
||||
ret = of_register_platform_driver(&mpc52xx_uart_of_driver);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "%s: of_register_platform_driver failed (%i)\n",
|
||||
__FILE__, ret);
|
||||
uart_unregister_driver(&mpc52xx_uart_driver);
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
ret = platform_driver_register(&mpc52xx_uart_platform_driver);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "%s: platform_driver_register failed (%i)\n",
|
||||
__FILE__, ret);
|
||||
uart_unregister_driver(&mpc52xx_uart_driver);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit
|
||||
mpc52xx_uart_exit(void)
|
||||
{
|
||||
#if defined(CONFIG_PPC_MERGE)
|
||||
of_unregister_platform_driver(&mpc52xx_uart_of_driver);
|
||||
#else
|
||||
platform_driver_unregister(&mpc52xx_uart_platform_driver);
|
||||
#endif
|
||||
uart_unregister_driver(&mpc52xx_uart_driver);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include <asm/prom.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/of_device.h>
|
||||
#include <asm/of_platform.h>
|
||||
|
||||
#include "macmodes.h"
|
||||
#include "platinumfb.h"
|
||||
|
|
@ -682,14 +683,14 @@ static int __init platinumfb_init(void)
|
|||
return -ENODEV;
|
||||
platinumfb_setup(option);
|
||||
#endif
|
||||
of_register_driver(&platinum_driver);
|
||||
of_register_platform_driver(&platinum_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit platinumfb_exit(void)
|
||||
{
|
||||
of_unregister_driver(&platinum_driver);
|
||||
of_unregister_platform_driver(&platinum_driver);
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
Loading…
Reference in a new issue