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