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