dbri: check dma_alloc_coherent errors
[safe/jmp/linux-2.6] / sound / sparc / dbri.c
index bfc3930..23ed6f0 100644 (file)
  * other       DBRI low-level stuff
  */
 
-#include <sound/driver.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/irq.h>
 #include <linux/io.h>
+#include <linux/dma-mapping.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -66,7 +66,8 @@
 #include <sound/control.h>
 #include <sound/initval.h>
 
-#include <asm/sbus.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <asm/atomic.h>
 
 MODULE_AUTHOR("Rudolf Koenig, Brent Baccala and Martin Habets");
@@ -233,12 +234,12 @@ static struct {
 ****************************************************************************/
 
 /* DBRI main registers */
-#define REG0   0x00UL          /* Status and Control */
-#define REG1   0x04UL          /* Mode and Interrupt */
-#define REG2   0x08UL          /* Parallel IO */
-#define REG3   0x0cUL          /* Test */
-#define REG8   0x20UL          /* Command Queue Pointer */
-#define REG9   0x24UL          /* Interrupt Queue Pointer */
+#define REG0   0x00            /* Status and Control */
+#define REG1   0x04            /* Mode and Interrupt */
+#define REG2   0x08            /* Parallel IO */
+#define REG3   0x0c            /* Test */
+#define REG8   0x20            /* Command Queue Pointer */
+#define REG9   0x24            /* Interrupt Queue Pointer */
 
 #define DBRI_NO_CMDS   64
 #define DBRI_INT_BLK   64
@@ -296,10 +297,8 @@ struct dbri_streaminfo {
 
 /* This structure holds the information for both chips (DBRI & CS4215) */
 struct snd_dbri {
-       struct snd_card *card;  /* ALSA card */
-
        int regs_size, irq;     /* Needed for unload */
-       struct sbus_dev *sdev;  /* SBUS device info */
+       struct of_device *op;   /* OF device info */
        spinlock_t lock;
 
        struct dbri_dma *dma;   /* Pointer to our DMA block */
@@ -318,8 +317,6 @@ struct snd_dbri {
        struct cs4215 mm;       /* mmcodec special info */
                                /* per stream (playback/record) info */
        struct dbri_streaminfo stream_info[DBRI_NO_STREAMS];
-
-       struct snd_dbri *next;
 };
 
 #define DBRI_MAX_VOLUME                63      /* Output volume */
@@ -565,14 +562,12 @@ struct snd_dbri {
 /* Translate the ALSA direction into the array index */
 #define DBRI_STREAMNO(substream)                               \
                (substream->stream ==                           \
-                SNDRV_PCM_STREAM_PLAYBACK? DBRI_PLAY: DBRI_REC)
+                SNDRV_PCM_STREAM_PLAYBACK ? DBRI_PLAY: DBRI_REC)
 
 /* Return a pointer to dbri_streaminfo */
 #define DBRI_STREAM(dbri, substream)   \
                &dbri->stream_info[DBRI_STREAMNO(substream)]
 
-static struct snd_dbri *dbri_list;     /* All DBRI devices */
-
 /*
  * Short data pipes transmit LSB first. The CS4215 receives MSB first. Grrr.
  * So we have to reverse the bits. Note: not all bit lengths are supported
@@ -611,8 +606,8 @@ The list is terminated with a WAIT command, which generates a
 CPU interrupt to signal completion.
 
 Since the DBRI can run in parallel with the CPU, several means of
-synchronization present themselves. The method implemented here is only
-use of the dbri_cmdwait() to wait for execution of batch of sent commands.
+synchronization present themselves. The method implemented here uses
+the dbri_cmdwait() to wait for execution of batch of sent commands.
 
 A circular command buffer is used here. A new command is being added
 while another can be executed. The scheme works by adding two WAIT commands
@@ -648,15 +643,14 @@ static void dbri_cmdwait(struct snd_dbri *dbri)
        }
        spin_unlock_irqrestore(&dbri->lock, flags);
 
-       if (maxloops == 0) {
+       if (maxloops == 0)
                printk(KERN_ERR "DBRI: Chip never completed command buffer\n");
-       } else {
+       else
                dprintk(D_CMD, "Chip completed command buffer (%d)\n",
                        MAXLOOPS - maxloops - 1);
-       }
 }
 /*
- * Lock the command queue and returns pointer to a space for len cmd words
+ * Lock the command queue and return pointer to space for len cmd words
  * It locks the cmdlock spinlock.
  */
 static s32 *dbri_cmdlock(struct snd_dbri *dbri, int len)
@@ -749,7 +743,7 @@ static void dbri_reset(struct snd_dbri *dbri)
 }
 
 /* Lock must not be held before calling this */
-static void dbri_initialize(struct snd_dbri *dbri)
+static void __devinit dbri_initialize(struct snd_dbri *dbri)
 {
        s32 *cmd;
        u32 dma_addr;
@@ -804,7 +798,7 @@ list ordering, among other things.  The transmit and receive functions
 here interface closely with the transmit and receive interrupt code.
 
 */
-static int pipe_active(struct snd_dbri *dbri, int pipe)
+static inline int pipe_active(struct snd_dbri *dbri, int pipe)
 {
        return ((pipe >= 0) && (dbri->pipes[pipe].desc != -1));
 }
@@ -1148,6 +1142,7 @@ static int setup_descs(struct snd_dbri *dbri, int streamno, unsigned int period)
                        if (!dbri->dma->desc[desc].ba)
                                break;
                }
+
                if (desc == DBRI_NO_DESCS) {
                        printk(KERN_ERR "DBRI: setup_descs: No descriptors\n");
                        return -1;
@@ -1308,7 +1303,7 @@ to the DBRI via the CHI interface and few of the DBRI's PIO pins.
  * Lock must not be held before calling it.
 
 */
-static void cs4215_setup_pipes(struct snd_dbri *dbri)
+static __devinit void cs4215_setup_pipes(struct snd_dbri *dbri)
 {
        unsigned long flags;
 
@@ -1341,7 +1336,7 @@ static void cs4215_setup_pipes(struct snd_dbri *dbri)
        dbri_cmdwait(dbri);
 }
 
-static int cs4215_init_data(struct cs4215 *mm)
+static __devinit int cs4215_init_data(struct cs4215 *mm)
 {
        /*
         * No action, memory resetting only.
@@ -1633,7 +1628,7 @@ static int cs4215_prepare(struct snd_dbri *dbri, unsigned int rate,
 /*
  *
  */
-static int cs4215_init(struct snd_dbri *dbri)
+static __devinit int cs4215_init(struct snd_dbri *dbri)
 {
        u32 reg2 = sbus_readl(dbri->regs + REG2);
        dprintk(D_MM, "cs4215_init: reg2=0x%x\n", reg2);
@@ -1771,13 +1766,10 @@ static void xmit_descs(struct snd_dbri *dbri)
 
 static void transmission_complete_intr(struct snd_dbri *dbri, int pipe)
 {
-       struct dbri_streaminfo *info;
-       int td;
+       struct dbri_streaminfo *info = &dbri->stream_info[DBRI_PLAY];
+       int td = dbri->pipes[pipe].desc;
        int status;
 
-       info = &dbri->stream_info[DBRI_PLAY];
-
-       td = dbri->pipes[pipe].desc;
        while (td >= 0) {
                if (td >= DBRI_NO_DESCS) {
                        printk(KERN_ERR "DBRI: invalid td on pipe %d\n", pipe);
@@ -1798,12 +1790,9 @@ static void transmission_complete_intr(struct snd_dbri *dbri, int pipe)
        }
 
        /* Notify ALSA */
-       if (spin_is_locked(&dbri->lock)) {
-               spin_unlock(&dbri->lock);
-               snd_pcm_period_elapsed(info->substream);
-               spin_lock(&dbri->lock);
-       } else
-               snd_pcm_period_elapsed(info->substream);
+       spin_unlock(&dbri->lock);
+       snd_pcm_period_elapsed(info->substream);
+       spin_lock(&dbri->lock);
 }
 
 static void reception_complete_intr(struct snd_dbri *dbri, int pipe)
@@ -1830,12 +1819,9 @@ static void reception_complete_intr(struct snd_dbri *dbri, int pipe)
                rd, DBRI_RD_STATUS(status), DBRI_RD_CNT(status));
 
        /* Notify ALSA */
-       if (spin_is_locked(&dbri->lock)) {
-               spin_unlock(&dbri->lock);
-               snd_pcm_period_elapsed(info->substream);
-               spin_lock(&dbri->lock);
-       } else
-               snd_pcm_period_elapsed(info->substream);
+       spin_unlock(&dbri->lock);
+       snd_pcm_period_elapsed(info->substream);
+       spin_lock(&dbri->lock);
 }
 
 static void dbri_process_one_interrupt(struct snd_dbri *dbri, int x)
@@ -1986,10 +1972,10 @@ static irqreturn_t snd_dbri_interrupt(int irq, void *dev_id)
                PCM Interface
 ****************************************************************************/
 static struct snd_pcm_hardware snd_dbri_pcm_hw = {
-       .info           = (SNDRV_PCM_INFO_MMAP |
-                          SNDRV_PCM_INFO_INTERLEAVED |
-                          SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                          SNDRV_PCM_INFO_MMAP_VALID),
+       .info           = SNDRV_PCM_INFO_MMAP |
+                         SNDRV_PCM_INFO_INTERLEAVED |
+                         SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                         SNDRV_PCM_INFO_MMAP_VALID,
        .formats        = SNDRV_PCM_FMTBIT_MU_LAW |
                          SNDRV_PCM_FMTBIT_A_LAW |
                          SNDRV_PCM_FMTBIT_U8 |
@@ -1999,7 +1985,7 @@ static struct snd_pcm_hardware snd_dbri_pcm_hw = {
        .rate_max               = 48000,
        .channels_min           = 1,
        .channels_max           = 2,
-       .buffer_bytes_max       = (64 * 1024),
+       .buffer_bytes_max       = 64 * 1024,
        .period_bytes_min       = 1,
        .period_bytes_max       = DBRI_TD_MAXCNT,
        .periods_min            = 1,
@@ -2108,14 +2094,15 @@ static int snd_dbri_hw_params(struct snd_pcm_substream *substream,
         */
        if (info->dvma_buffer == 0) {
                if (DBRI_STREAMNO(substream) == DBRI_PLAY)
-                       direction = SBUS_DMA_TODEVICE;
+                       direction = DMA_TO_DEVICE;
                else
-                       direction = SBUS_DMA_FROMDEVICE;
+                       direction = DMA_FROM_DEVICE;
 
-               info->dvma_buffer = sbus_map_single(dbri->sdev,
-                                       runtime->dma_area,
-                                       params_buffer_bytes(hw_params),
-                                       direction);
+               info->dvma_buffer =
+                       dma_map_single(&dbri->op->dev,
+                                      runtime->dma_area,
+                                      params_buffer_bytes(hw_params),
+                                      direction);
        }
 
        direction = params_buffer_bytes(hw_params);
@@ -2136,12 +2123,12 @@ static int snd_dbri_hw_free(struct snd_pcm_substream *substream)
         */
        if (info->dvma_buffer) {
                if (DBRI_STREAMNO(substream) == DBRI_PLAY)
-                       direction = SBUS_DMA_TODEVICE;
+                       direction = DMA_TO_DEVICE;
                else
-                       direction = SBUS_DMA_FROMDEVICE;
+                       direction = DMA_FROM_DEVICE;
 
-               sbus_unmap_single(dbri->sdev, info->dvma_buffer,
-                                 substream->runtime->buffer_size, direction);
+               dma_unmap_single(&dbri->op->dev, info->dvma_buffer,
+                                substream->runtime->buffer_size, direction);
                info->dvma_buffer = 0;
        }
        if (info->pipe != -1) {
@@ -2227,25 +2214,24 @@ static struct snd_pcm_ops snd_dbri_ops = {
        .pointer = snd_dbri_pointer,
 };
 
-static int __devinit snd_dbri_pcm(struct snd_dbri *dbri)
+static int __devinit snd_dbri_pcm(struct snd_card *card)
 {
        struct snd_pcm *pcm;
        int err;
 
-       if ((err = snd_pcm_new(dbri->card,
+       if ((err = snd_pcm_new(card,
                               /* ID */             "sun_dbri",
                               /* device */         0,
                               /* playback count */ 1,
                               /* capture count */  1, &pcm)) < 0)
                return err;
-       snd_assert(pcm != NULL, return -EINVAL);
 
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_dbri_ops);
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_dbri_ops);
 
-       pcm->private_data = dbri;
+       pcm->private_data = card->private_data;
        pcm->info_flags = 0;
-       strcpy(pcm->name, dbri->card->shortname);
+       strcpy(pcm->name, card->shortname);
 
        if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm,
                        SNDRV_DMA_TYPE_CONTINUOUS,
@@ -2266,11 +2252,10 @@ static int snd_cs4215_info_volume(struct snd_kcontrol *kcontrol,
        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
        uinfo->count = 2;
        uinfo->value.integer.min = 0;
-       if (kcontrol->private_value == DBRI_PLAY) {
+       if (kcontrol->private_value == DBRI_PLAY)
                uinfo->value.integer.max = DBRI_MAX_VOLUME;
-       } else {
+       else
                uinfo->value.integer.max = DBRI_MAX_GAIN;
-       }
        return 0;
 }
 
@@ -2279,9 +2264,10 @@ static int snd_cs4215_get_volume(struct snd_kcontrol *kcontrol,
 {
        struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol);
        struct dbri_streaminfo *info;
-       snd_assert(dbri != NULL, return -EINVAL);
+
+       if (snd_BUG_ON(!dbri))
+               return -EINVAL;
        info = &dbri->stream_info[kcontrol->private_value];
-       snd_assert(info != NULL, return -EINVAL);
 
        ucontrol->value.integer.value[0] = info->left_gain;
        ucontrol->value.integer.value[1] = info->right_gain;
@@ -2294,17 +2280,28 @@ static int snd_cs4215_put_volume(struct snd_kcontrol *kcontrol,
        struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol);
        struct dbri_streaminfo *info =
                                &dbri->stream_info[kcontrol->private_value];
+       unsigned int vol[2];
        int changed = 0;
 
-       if (info->left_gain != ucontrol->value.integer.value[0]) {
-               info->left_gain = ucontrol->value.integer.value[0];
+       vol[0] = ucontrol->value.integer.value[0];
+       vol[1] = ucontrol->value.integer.value[1];
+       if (kcontrol->private_value == DBRI_PLAY) {
+               if (vol[0] > DBRI_MAX_VOLUME || vol[1] > DBRI_MAX_VOLUME)
+                       return -EINVAL;
+       } else {
+               if (vol[0] > DBRI_MAX_GAIN || vol[1] > DBRI_MAX_GAIN)
+                       return -EINVAL;
+       }
+
+       if (info->left_gain != vol[0]) {
+               info->left_gain = vol[0];
                changed = 1;
        }
-       if (info->right_gain != ucontrol->value.integer.value[1]) {
-               info->right_gain = ucontrol->value.integer.value[1];
+       if (info->right_gain != vol[1]) {
+               info->right_gain = vol[1];
                changed = 1;
        }
-       if (changed == 1) {
+       if (changed) {
                /* First mute outputs, and wait 1/8000 sec (125 us)
                 * to make sure this takes.  This avoids clicking noises.
                 */
@@ -2336,7 +2333,9 @@ static int snd_cs4215_get_single(struct snd_kcontrol *kcontrol,
        int shift = (kcontrol->private_value >> 8) & 0xff;
        int mask = (kcontrol->private_value >> 16) & 0xff;
        int invert = (kcontrol->private_value >> 24) & 1;
-       snd_assert(dbri != NULL, return -EINVAL);
+
+       if (snd_BUG_ON(!dbri))
+               return -EINVAL;
 
        if (elem < 4)
                ucontrol->value.integer.value[0] =
@@ -2361,7 +2360,9 @@ static int snd_cs4215_put_single(struct snd_kcontrol *kcontrol,
        int invert = (kcontrol->private_value >> 24) & 1;
        int changed = 0;
        unsigned short val;
-       snd_assert(dbri != NULL, return -EINVAL);
+
+       if (snd_BUG_ON(!dbri))
+               return -EINVAL;
 
        val = (ucontrol->value.integer.value[0] & mask);
        if (invert == 1)
@@ -2432,19 +2433,21 @@ static struct snd_kcontrol_new dbri_controls[] __devinitdata = {
        CS4215_SINGLE("Mic boost", 4, 4, 1, 1)
 };
 
-static int __init snd_dbri_mixer(struct snd_dbri *dbri)
+static int __devinit snd_dbri_mixer(struct snd_card *card)
 {
-       struct snd_card *card;
        int idx, err;
+       struct snd_dbri *dbri;
 
-       snd_assert(dbri != NULL && dbri->card != NULL, return -EINVAL);
+       if (snd_BUG_ON(!card || !card->private_data))
+               return -EINVAL;
+       dbri = card->private_data;
 
-       card = dbri->card;
        strcpy(card->mixername, card->shortname);
 
        for (idx = 0; idx < ARRAY_SIZE(dbri_controls); idx++) {
-               if ((err = snd_ctl_add(card,
-                               snd_ctl_new1(&dbri_controls[idx], dbri))) < 0)
+               err = snd_ctl_add(card,
+                               snd_ctl_new1(&dbri_controls[idx], dbri));
+               if (err < 0)
                        return err;
        }
 
@@ -2485,8 +2488,8 @@ static void dbri_debug_read(struct snd_info_entry *entry,
                                    "Pipe %d: %s SDP=0x%x desc=%d, "
                                    "len=%d next %d\n",
                                    pipe,
-                                  ((pptr->sdp & D_SDP_TO_SER) ? "output" :
-                                                                "input"),
+                                  (pptr->sdp & D_SDP_TO_SER) ? "output" :
+                                                                "input",
                                    pptr->sdp, pptr->desc,
                                    pptr->length, pptr->nextpipe);
                }
@@ -2494,15 +2497,16 @@ static void dbri_debug_read(struct snd_info_entry *entry,
 }
 #endif
 
-void snd_dbri_proc(struct snd_dbri *dbri)
+static void __devinit snd_dbri_proc(struct snd_card *card)
 {
+       struct snd_dbri *dbri = card->private_data;
        struct snd_info_entry *entry;
 
-       if (!snd_card_proc_new(dbri->card, "regs", &entry))
+       if (!snd_card_proc_new(card, "regs", &entry))
                snd_info_set_text_ops(entry, dbri, dbri_regs_read);
 
 #ifdef DBRI_DEBUG
-       if (! snd_card_proc_new(dbri->card, "debug", &entry)) {
+       if (!snd_card_proc_new(card, "debug", &entry)) {
                snd_info_set_text_ops(entry, dbri, dbri_debug_read);
                entry->mode = S_IFREG | S_IRUGO;        /* Readable only. */
        }
@@ -2516,33 +2520,35 @@ void snd_dbri_proc(struct snd_dbri *dbri)
 */
 static void snd_dbri_free(struct snd_dbri *dbri);
 
-static int __init snd_dbri_create(struct snd_card *card,
-                                 struct sbus_dev *sdev,
-                                 struct linux_prom_irqs *irq, int dev)
+static int __devinit snd_dbri_create(struct snd_card *card,
+                                    struct of_device *op,
+                                    int irq, int dev)
 {
        struct snd_dbri *dbri = card->private_data;
        int err;
 
        spin_lock_init(&dbri->lock);
-       dbri->card = card;
-       dbri->sdev = sdev;
-       dbri->irq = irq->pri;
+       dbri->op = op;
+       dbri->irq = irq;
 
-       dbri->dma = sbus_alloc_consistent(sdev, sizeof(struct dbri_dma),
-                                         &dbri->dma_dvma);
+       dbri->dma = dma_alloc_coherent(&op->dev,
+                                      sizeof(struct dbri_dma),
+                                      &dbri->dma_dvma, GFP_ATOMIC);
+       if (!dbri->dma)
+               return -ENOMEM;
        memset((void *)dbri->dma, 0, sizeof(struct dbri_dma));
 
        dprintk(D_GEN, "DMA Cmd Block 0x%p (0x%08x)\n",
                dbri->dma, dbri->dma_dvma);
 
        /* Map the registers into memory. */
-       dbri->regs_size = sdev->reg_addrs[0].reg_size;
-       dbri->regs = sbus_ioremap(&sdev->resource[0], 0,
-                                 dbri->regs_size, "DBRI Registers");
+       dbri->regs_size = resource_size(&op->resource[0]);
+       dbri->regs = of_ioremap(&op->resource[0], 0,
+                               dbri->regs_size, "DBRI Registers");
        if (!dbri->regs) {
                printk(KERN_ERR "DBRI: could not allocate registers\n");
-               sbus_free_consistent(sdev, sizeof(struct dbri_dma),
-                                    (void *)dbri->dma, dbri->dma_dvma);
+               dma_free_coherent(&op->dev, sizeof(struct dbri_dma),
+                                 (void *)dbri->dma, dbri->dma_dvma);
                return -EIO;
        }
 
@@ -2550,9 +2556,9 @@ static int __init snd_dbri_create(struct snd_card *card,
                          "DBRI audio", dbri);
        if (err) {
                printk(KERN_ERR "DBRI: Can't get irq %d\n", dbri->irq);
-               sbus_iounmap(dbri->regs, dbri->regs_size);
-               sbus_free_consistent(sdev, sizeof(struct dbri_dma),
-                                    (void *)dbri->dma, dbri->dma_dvma);
+               of_iounmap(&op->resource[0], dbri->regs, dbri->regs_size);
+               dma_free_coherent(&op->dev, sizeof(struct dbri_dma),
+                                 (void *)dbri->dma, dbri->dma_dvma);
                return err;
        }
 
@@ -2564,9 +2570,6 @@ static int __init snd_dbri_create(struct snd_card *card,
                return err;
        }
 
-       dbri->next = dbri_list;
-       dbri_list = dbri;
-
        return 0;
 }
 
@@ -2579,28 +2582,23 @@ static void snd_dbri_free(struct snd_dbri *dbri)
                free_irq(dbri->irq, dbri);
 
        if (dbri->regs)
-               sbus_iounmap(dbri->regs, dbri->regs_size);
+               of_iounmap(&dbri->op->resource[0], dbri->regs, dbri->regs_size);
 
        if (dbri->dma)
-               sbus_free_consistent(dbri->sdev, sizeof(struct dbri_dma),
-                                    (void *)dbri->dma, dbri->dma_dvma);
+               dma_free_coherent(&dbri->op->dev,
+                                 sizeof(struct dbri_dma),
+                                 (void *)dbri->dma, dbri->dma_dvma);
 }
 
-static int __init dbri_attach(int prom_node, struct sbus_dev *sdev)
+static int __devinit dbri_probe(struct of_device *op, const struct of_device_id *match)
 {
        struct snd_dbri *dbri;
-       struct linux_prom_irqs irq;
        struct resource *rp;
        struct snd_card *card;
        static int dev = 0;
+       int irq;
        int err;
 
-       if (sdev->prom_name[9] < 'e') {
-               printk(KERN_ERR "DBRI: unsupported chip version %c found.\n",
-                      sdev->prom_name[9]);
-               return -EIO;
-       }
-
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
        if (!enable[dev]) {
@@ -2608,10 +2606,9 @@ static int __init dbri_attach(int prom_node, struct sbus_dev *sdev)
                return -ENOENT;
        }
 
-       err = prom_getproperty(prom_node, "intr", (char *)&irq, sizeof(irq));
-       if (err < 0) {
-               printk(KERN_ERR "DBRI-%d: Firmware node lacks IRQ property.\n",
-                       dev);
+       irq = op->irqs[0];
+       if (irq <= 0) {
+               printk(KERN_ERR "DBRI-%d: No IRQ.\n", dev);
                return -ENODEV;
        }
 
@@ -2622,26 +2619,29 @@ static int __init dbri_attach(int prom_node, struct sbus_dev *sdev)
 
        strcpy(card->driver, "DBRI");
        strcpy(card->shortname, "Sun DBRI");
-       rp = &sdev->resource[0];
+       rp = &op->resource[0];
        sprintf(card->longname, "%s at 0x%02lx:0x%016Lx, irq %d",
                card->shortname,
-               rp->flags & 0xffL, (unsigned long long)rp->start, irq.pri);
+               rp->flags & 0xffL, (unsigned long long)rp->start, irq);
 
-       if ((err = snd_dbri_create(card, sdev, &irq, dev)) < 0) {
+       err = snd_dbri_create(card, op, irq, dev);
+       if (err < 0) {
                snd_card_free(card);
                return err;
        }
 
        dbri = card->private_data;
-       if ((err = snd_dbri_pcm(dbri)) < 0)
+       err = snd_dbri_pcm(card);
+       if (err < 0)
                goto _err;
 
-       if ((err = snd_dbri_mixer(dbri)) < 0)
-       if ((err = snd_dbri_mixer(dbri)) < 0)
+       err = snd_dbri_mixer(card);
+       if (err < 0)
                goto _err;
 
        /* /proc file handling */
-       snd_dbri_proc(dbri);
+       snd_dbri_proc(card);
+       dev_set_drvdata(&op->dev, card);
 
        err = snd_card_register(card);
        if (err < 0)
@@ -2649,7 +2649,7 @@ static int __init dbri_attach(int prom_node, struct sbus_dev *sdev)
 
        printk(KERN_INFO "audio%d at %p (irq %d) is DBRI(%c)+CS4215(%d)\n",
               dev, dbri->regs,
-              dbri->irq, sdev->prom_name[9], dbri->mm.version);
+              dbri->irq, op->node->name[9], dbri->mm.version);
        dev++;
 
        return 0;
@@ -2660,43 +2660,46 @@ _err:
        return err;
 }
 
-/* Probe for the dbri chip and then attach the driver. */
-static int __init dbri_init(void)
+static int __devexit dbri_remove(struct of_device *op)
 {
-       struct sbus_bus *sbus;
-       struct sbus_dev *sdev;
-       int found = 0;
-
-       /* Probe each SBUS for the DBRI chip(s). */
-       for_all_sbusdev(sdev, sbus) {
-               /*
-                * The version is coded in the last character
-                */
-               if (!strncmp(sdev->prom_name, "SUNW,DBRI", 9)) {
-                       dprintk(D_GEN, "DBRI: Found %s in SBUS slot %d\n",
-                               sdev->prom_name, sdev->slot);
+       struct snd_card *card = dev_get_drvdata(&op->dev);
 
-                       if (dbri_attach(sdev->prom_node, sdev) == 0)
-                               found++;
-               }
-       }
+       snd_dbri_free(card->private_data);
+       snd_card_free(card);
+
+       dev_set_drvdata(&op->dev, NULL);
 
-       return (found > 0) ? 0 : -EIO;
+       return 0;
 }
 
-static void __exit dbri_exit(void)
-{
-       struct snd_dbri *this = dbri_list;
+static const struct of_device_id dbri_match[] = {
+       {
+               .name = "SUNW,DBRIe",
+       },
+       {
+               .name = "SUNW,DBRIf",
+       },
+       {},
+};
 
-       while (this != NULL) {
-               struct snd_dbri *next = this->next;
-               struct snd_card *card = this->card;
+MODULE_DEVICE_TABLE(of, dbri_match);
 
-               snd_dbri_free(this);
-               snd_card_free(card);
-               this = next;
-       }
-       dbri_list = NULL;
+static struct of_platform_driver dbri_sbus_driver = {
+       .name           = "dbri",
+       .match_table    = dbri_match,
+       .probe          = dbri_probe,
+       .remove         = __devexit_p(dbri_remove),
+};
+
+/* Probe for the dbri chip and then attach the driver. */
+static int __init dbri_init(void)
+{
+       return of_register_driver(&dbri_sbus_driver, &of_bus_type);
+}
+
+static void __exit dbri_exit(void)
+{
+       of_unregister_driver(&dbri_sbus_driver);
 }
 
 module_init(dbri_init);