Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | /* * i2sbus driver -- bus control routines * * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> * * GPL v2, can be found in COPYING. */ #include <linux/kernel.h> #include <linux/delay.h> #include <linux/slab.h> #include <asm/io.h> #include <asm/prom.h> #include <asm/macio.h> #include <asm/pmac_feature.h> #include <asm/pmac_pfunc.h> #include <asm/keylargo.h> #include "i2sbus.h" int i2sbus_control_init(struct macio_dev* dev, struct i2sbus_control **c) { *c = kzalloc(sizeof(struct i2sbus_control), GFP_KERNEL); if (!*c) return -ENOMEM; INIT_LIST_HEAD(&(*c)->list); (*c)->macio = dev->bus->chip; return 0; } void i2sbus_control_destroy(struct i2sbus_control *c) { kfree(c); } /* this is serialised externally */ int i2sbus_control_add_dev(struct i2sbus_control *c, struct i2sbus_dev *i2sdev) { struct device_node *np; np = i2sdev->sound.ofdev.dev.of_node; i2sdev->enable = pmf_find_function(np, "enable"); i2sdev->cell_enable = pmf_find_function(np, "cell-enable"); i2sdev->clock_enable = pmf_find_function(np, "clock-enable"); i2sdev->cell_disable = pmf_find_function(np, "cell-disable"); i2sdev->clock_disable = pmf_find_function(np, "clock-disable"); /* if the bus number is not 0 or 1 we absolutely need to use * the platform functions -- there's nothing in Darwin that * would allow seeing a system behind what the FCRs are then, * and I don't want to go parsing a bunch of platform functions * by hand to try finding a system... */ if (i2sdev->bus_number != 0 && i2sdev->bus_number != 1 && (!i2sdev->enable || !i2sdev->cell_enable || !i2sdev->clock_enable || !i2sdev->cell_disable || !i2sdev->clock_disable)) { pmf_put_function(i2sdev->enable); pmf_put_function(i2sdev->cell_enable); pmf_put_function(i2sdev->clock_enable); pmf_put_function(i2sdev->cell_disable); pmf_put_function(i2sdev->clock_disable); return -ENODEV; } list_add(&i2sdev->item, &c->list); return 0; } void i2sbus_control_remove_dev(struct i2sbus_control *c, struct i2sbus_dev *i2sdev) { /* this is serialised externally */ list_del(&i2sdev->item); if (list_empty(&c->list)) i2sbus_control_destroy(c); } int i2sbus_control_enable(struct i2sbus_control *c, struct i2sbus_dev *i2sdev) { struct pmf_args args = { .count = 0 }; struct macio_chip *macio = c->macio; if (i2sdev->enable) return pmf_call_one(i2sdev->enable, &args); if (macio == NULL || macio->base == NULL) return -ENODEV; switch (i2sdev->bus_number) { case 0: /* these need to be locked or done through * newly created feature calls! */ MACIO_BIS(KEYLARGO_FCR1, KL1_I2S0_ENABLE); break; case 1: MACIO_BIS(KEYLARGO_FCR1, KL1_I2S1_ENABLE); break; default: return -ENODEV; } return 0; } int i2sbus_control_cell(struct i2sbus_control *c, struct i2sbus_dev *i2sdev, int enable) { struct pmf_args args = { .count = 0 }; struct macio_chip *macio = c->macio; switch (enable) { case 0: if (i2sdev->cell_disable) return pmf_call_one(i2sdev->cell_disable, &args); break; case 1: if (i2sdev->cell_enable) return pmf_call_one(i2sdev->cell_enable, &args); break; default: printk(KERN_ERR "i2sbus: INVALID CELL ENABLE VALUE\n"); return -ENODEV; } if (macio == NULL || macio->base == NULL) return -ENODEV; switch (i2sdev->bus_number) { case 0: if (enable) MACIO_BIS(KEYLARGO_FCR1, KL1_I2S0_CELL_ENABLE); else MACIO_BIC(KEYLARGO_FCR1, KL1_I2S0_CELL_ENABLE); break; case 1: if (enable) MACIO_BIS(KEYLARGO_FCR1, KL1_I2S1_CELL_ENABLE); else MACIO_BIC(KEYLARGO_FCR1, KL1_I2S1_CELL_ENABLE); break; default: return -ENODEV; } return 0; } int i2sbus_control_clock(struct i2sbus_control *c, struct i2sbus_dev *i2sdev, int enable) { struct pmf_args args = { .count = 0 }; struct macio_chip *macio = c->macio; switch (enable) { case 0: if (i2sdev->clock_disable) return pmf_call_one(i2sdev->clock_disable, &args); break; case 1: if (i2sdev->clock_enable) return pmf_call_one(i2sdev->clock_enable, &args); break; default: printk(KERN_ERR "i2sbus: INVALID CLOCK ENABLE VALUE\n"); return -ENODEV; } if (macio == NULL || macio->base == NULL) return -ENODEV; switch (i2sdev->bus_number) { case 0: if (enable) MACIO_BIS(KEYLARGO_FCR1, KL1_I2S0_CLK_ENABLE_BIT); else MACIO_BIC(KEYLARGO_FCR1, KL1_I2S0_CLK_ENABLE_BIT); break; case 1: if (enable) MACIO_BIS(KEYLARGO_FCR1, KL1_I2S1_CLK_ENABLE_BIT); else MACIO_BIC(KEYLARGO_FCR1, KL1_I2S1_CLK_ENABLE_BIT); break; default: return -ENODEV; } return 0; } |