xref: /linux/sound/aoa/soundbus/i2sbus/control.c (revision 6fdcba32711044c35c0e1b094cbd8f3f0b4472c9)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * i2sbus driver -- bus control routines
4  *
5  * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
6  */
7 
8 #include <linux/kernel.h>
9 #include <linux/delay.h>
10 #include <linux/slab.h>
11 #include <linux/io.h>
12 
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.dev.of_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