diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/sparc/amd7930.c | 138 |
1 files changed, 77 insertions, 61 deletions
diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c index dfe9bac7fa32..ba1b2a3443d3 100644 --- a/sound/sparc/amd7930.c +++ b/sound/sparc/amd7930.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <asm/io.h> | 46 | #include <asm/io.h> |
47 | #include <asm/irq.h> | 47 | #include <asm/irq.h> |
48 | #include <asm/sbus.h> | 48 | #include <asm/sbus.h> |
49 | #include <asm/prom.h> | ||
49 | 50 | ||
50 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | 51 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ |
51 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | 52 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ |
@@ -335,7 +336,6 @@ struct snd_amd7930 { | |||
335 | int pgain; | 336 | int pgain; |
336 | int mgain; | 337 | int mgain; |
337 | 338 | ||
338 | struct sbus_dev *sdev; | ||
339 | unsigned int irq; | 339 | unsigned int irq; |
340 | unsigned int regs_size; | 340 | unsigned int regs_size; |
341 | struct snd_amd7930 *next; | 341 | struct snd_amd7930 *next; |
@@ -946,11 +946,9 @@ static struct snd_device_ops snd_amd7930_dev_ops = { | |||
946 | }; | 946 | }; |
947 | 947 | ||
948 | static int __init snd_amd7930_create(struct snd_card *card, | 948 | static int __init snd_amd7930_create(struct snd_card *card, |
949 | struct sbus_dev *sdev, | ||
950 | struct resource *rp, | 949 | struct resource *rp, |
951 | unsigned int reg_size, | 950 | unsigned int reg_size, |
952 | struct linux_prom_irqs *irq_prop, | 951 | int irq, int dev, |
953 | int dev, | ||
954 | struct snd_amd7930 **ramd) | 952 | struct snd_amd7930 **ramd) |
955 | { | 953 | { |
956 | unsigned long flags; | 954 | unsigned long flags; |
@@ -964,7 +962,6 @@ static int __init snd_amd7930_create(struct snd_card *card, | |||
964 | 962 | ||
965 | spin_lock_init(&amd->lock); | 963 | spin_lock_init(&amd->lock); |
966 | amd->card = card; | 964 | amd->card = card; |
967 | amd->sdev = sdev; | ||
968 | amd->regs_size = reg_size; | 965 | amd->regs_size = reg_size; |
969 | 966 | ||
970 | amd->regs = sbus_ioremap(rp, 0, amd->regs_size, "amd7930"); | 967 | amd->regs = sbus_ioremap(rp, 0, amd->regs_size, "amd7930"); |
@@ -975,15 +972,14 @@ static int __init snd_amd7930_create(struct snd_card *card, | |||
975 | 972 | ||
976 | amd7930_idle(amd); | 973 | amd7930_idle(amd); |
977 | 974 | ||
978 | if (request_irq(irq_prop->pri, snd_amd7930_interrupt, | 975 | if (request_irq(irq, snd_amd7930_interrupt, |
979 | SA_INTERRUPT | SA_SHIRQ, "amd7930", amd)) { | 976 | SA_INTERRUPT | SA_SHIRQ, "amd7930", amd)) { |
980 | snd_printk("amd7930-%d: Unable to grab IRQ %d\n", | 977 | snd_printk("amd7930-%d: Unable to grab IRQ %d\n", |
981 | dev, | 978 | dev, irq); |
982 | irq_prop->pri); | ||
983 | snd_amd7930_free(amd); | 979 | snd_amd7930_free(amd); |
984 | return -EBUSY; | 980 | return -EBUSY; |
985 | } | 981 | } |
986 | amd->irq = irq_prop->pri; | 982 | amd->irq = irq; |
987 | 983 | ||
988 | amd7930_enable_ints(amd); | 984 | amd7930_enable_ints(amd); |
989 | 985 | ||
@@ -1017,47 +1013,21 @@ static int __init snd_amd7930_create(struct snd_card *card, | |||
1017 | return 0; | 1013 | return 0; |
1018 | } | 1014 | } |
1019 | 1015 | ||
1020 | static int __init amd7930_attach(int prom_node, struct sbus_dev *sdev) | 1016 | static int __init amd7930_attach_common(struct resource *rp, int irq) |
1021 | { | 1017 | { |
1022 | static int dev; | 1018 | static int dev_num; |
1023 | struct linux_prom_registers reg_prop; | ||
1024 | struct linux_prom_irqs irq_prop; | ||
1025 | struct resource res, *rp; | ||
1026 | struct snd_card *card; | 1019 | struct snd_card *card; |
1027 | struct snd_amd7930 *amd; | 1020 | struct snd_amd7930 *amd; |
1028 | int err; | 1021 | int err; |
1029 | 1022 | ||
1030 | if (dev >= SNDRV_CARDS) | 1023 | if (dev_num >= SNDRV_CARDS) |
1031 | return -ENODEV; | 1024 | return -ENODEV; |
1032 | if (!enable[dev]) { | 1025 | if (!enable[dev_num]) { |
1033 | dev++; | 1026 | dev_num++; |
1034 | return -ENOENT; | 1027 | return -ENOENT; |
1035 | } | 1028 | } |
1036 | 1029 | ||
1037 | err = prom_getproperty(prom_node, "intr", | 1030 | card = snd_card_new(index[dev_num], id[dev_num], THIS_MODULE, 0); |
1038 | (char *) &irq_prop, sizeof(irq_prop)); | ||
1039 | if (err < 0) { | ||
1040 | snd_printk("amd7930-%d: Firmware node lacks IRQ property.\n", dev); | ||
1041 | return -ENODEV; | ||
1042 | } | ||
1043 | |||
1044 | err = prom_getproperty(prom_node, "reg", | ||
1045 | (char *) ®_prop, sizeof(reg_prop)); | ||
1046 | if (err < 0) { | ||
1047 | snd_printk("amd7930-%d: Firmware node lacks register property.\n", dev); | ||
1048 | return -ENODEV; | ||
1049 | } | ||
1050 | |||
1051 | if (sdev) { | ||
1052 | rp = &sdev->resource[0]; | ||
1053 | } else { | ||
1054 | rp = &res; | ||
1055 | rp->start = reg_prop.phys_addr; | ||
1056 | rp->end = rp->start + reg_prop.reg_size - 1; | ||
1057 | rp->flags = IORESOURCE_IO | (reg_prop.which_io & 0xff); | ||
1058 | } | ||
1059 | |||
1060 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); | ||
1061 | if (card == NULL) | 1031 | if (card == NULL) |
1062 | return -ENOMEM; | 1032 | return -ENOMEM; |
1063 | 1033 | ||
@@ -1067,10 +1037,11 @@ static int __init amd7930_attach(int prom_node, struct sbus_dev *sdev) | |||
1067 | card->shortname, | 1037 | card->shortname, |
1068 | rp->flags & 0xffL, | 1038 | rp->flags & 0xffL, |
1069 | rp->start, | 1039 | rp->start, |
1070 | irq_prop.pri); | 1040 | irq); |
1071 | 1041 | ||
1072 | if ((err = snd_amd7930_create(card, sdev, rp, reg_prop.reg_size, | 1042 | if ((err = snd_amd7930_create(card, rp, |
1073 | &irq_prop, dev, &amd)) < 0) | 1043 | (rp->end - rp->start) + 1, |
1044 | irq, dev_num, &amd)) < 0) | ||
1074 | goto out_err; | 1045 | goto out_err; |
1075 | 1046 | ||
1076 | if ((err = snd_amd7930_pcm(amd)) < 0) | 1047 | if ((err = snd_amd7930_pcm(amd)) < 0) |
@@ -1085,7 +1056,8 @@ static int __init amd7930_attach(int prom_node, struct sbus_dev *sdev) | |||
1085 | amd->next = amd7930_list; | 1056 | amd->next = amd7930_list; |
1086 | amd7930_list = amd; | 1057 | amd7930_list = amd; |
1087 | 1058 | ||
1088 | dev++; | 1059 | dev_num++; |
1060 | |||
1089 | return 0; | 1061 | return 0; |
1090 | 1062 | ||
1091 | out_err: | 1063 | out_err: |
@@ -1093,29 +1065,71 @@ out_err: | |||
1093 | return err; | 1065 | return err; |
1094 | } | 1066 | } |
1095 | 1067 | ||
1096 | static int __init amd7930_init(void) | 1068 | static int __init amd7930_obio_attach(struct device_node *dp) |
1069 | { | ||
1070 | struct linux_prom_registers *regs; | ||
1071 | struct linux_prom_irqs *irqp; | ||
1072 | struct resource res, *rp; | ||
1073 | int len; | ||
1074 | |||
1075 | irqp = of_get_property(dp, "intr", &len); | ||
1076 | if (!irqp) { | ||
1077 | snd_printk("%s: Firmware node lacks IRQ property.\n", | ||
1078 | dp->full_name); | ||
1079 | return -ENODEV; | ||
1080 | } | ||
1081 | |||
1082 | regs = of_get_property(dp, "reg", &len); | ||
1083 | if (!regs) { | ||
1084 | snd_printk("%s: Firmware node lacks register property.\n", | ||
1085 | dp->full_name); | ||
1086 | return -ENODEV; | ||
1087 | } | ||
1088 | |||
1089 | rp = &res; | ||
1090 | rp->start = regs->phys_addr; | ||
1091 | rp->end = rp->start + regs->reg_size - 1; | ||
1092 | rp->flags = IORESOURCE_IO | (regs->which_io & 0xff); | ||
1093 | |||
1094 | return amd7930_attach_common(rp, irqp->pri); | ||
1095 | } | ||
1096 | |||
1097 | static int __devinit amd7930_sbus_probe(struct of_device *dev, const struct of_device_id *match) | ||
1097 | { | 1098 | { |
1098 | struct sbus_bus *sbus; | 1099 | struct sbus_dev *sdev = to_sbus_device(&dev->dev); |
1099 | struct sbus_dev *sdev; | ||
1100 | int node, found; | ||
1101 | 1100 | ||
1102 | found = 0; | 1101 | return amd7930_attach_common(&sdev->resource[0], sdev->irqs[0]); |
1102 | } | ||
1103 | |||
1104 | static struct of_device_id amd7930_match[] = { | ||
1105 | { | ||
1106 | .name = "audio", | ||
1107 | }, | ||
1108 | {}, | ||
1109 | }; | ||
1110 | |||
1111 | static struct of_platform_driver amd7930_sbus_driver = { | ||
1112 | .name = "audio", | ||
1113 | .match_table = amd7930_match, | ||
1114 | .probe = amd7930_sbus_probe, | ||
1115 | }; | ||
1116 | |||
1117 | static int __init amd7930_init(void) | ||
1118 | { | ||
1119 | struct device_node *dp; | ||
1103 | 1120 | ||
1104 | /* Try to find the sun4c "audio" node first. */ | 1121 | /* Try to find the sun4c "audio" node first. */ |
1105 | node = prom_getchild(prom_root_node); | 1122 | dp = of_find_node_by_path("/"); |
1106 | node = prom_searchsiblings(node, "audio"); | 1123 | dp = dp->child; |
1107 | if (node && amd7930_attach(node, NULL) == 0) | 1124 | while (dp) { |
1108 | found++; | 1125 | if (!strcmp(dp->name, "audio")) |
1126 | amd7930_obio_attach(dp); | ||
1109 | 1127 | ||
1110 | /* Probe each SBUS for amd7930 chips. */ | 1128 | dp = dp->sibling; |
1111 | for_all_sbusdev(sdev, sbus) { | ||
1112 | if (!strcmp(sdev->prom_name, "audio")) { | ||
1113 | if (amd7930_attach(sdev->prom_node, sdev) == 0) | ||
1114 | found++; | ||
1115 | } | ||
1116 | } | 1129 | } |
1117 | 1130 | ||
1118 | return (found > 0) ? 0 : -EIO; | 1131 | /* Probe each SBUS for amd7930 chips. */ |
1132 | return of_register_driver(&amd7930_sbus_driver, &sbus_bus_type); | ||
1119 | } | 1133 | } |
1120 | 1134 | ||
1121 | static void __exit amd7930_exit(void) | 1135 | static void __exit amd7930_exit(void) |
@@ -1131,6 +1145,8 @@ static void __exit amd7930_exit(void) | |||
1131 | } | 1145 | } |
1132 | 1146 | ||
1133 | amd7930_list = NULL; | 1147 | amd7930_list = NULL; |
1148 | |||
1149 | of_unregister_driver(&amd7930_sbus_driver); | ||
1134 | } | 1150 | } |
1135 | 1151 | ||
1136 | module_init(amd7930_init); | 1152 | module_init(amd7930_init); |