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