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
22int 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
34void i2sbus_control_destroy(struct i2sbus_control *c)
35{
36	kfree(c);
37}
38
39/* this is serialised externally */
40int 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
74void 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
83int 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
110int 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
153int 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