0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/delay.h>
0013 #include <linux/slab.h>
0014 #include <sound/hda_register.h>
0015 #include <sound/hdaudio_ext.h>
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027 void snd_hdac_ext_bus_ppcap_enable(struct hdac_bus *bus, bool enable)
0028 {
0029
0030 if (!bus->ppcap) {
0031 dev_err(bus->dev, "Address of PP capability is NULL");
0032 return;
0033 }
0034
0035 if (enable)
0036 snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL,
0037 AZX_PPCTL_GPROCEN, AZX_PPCTL_GPROCEN);
0038 else
0039 snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL,
0040 AZX_PPCTL_GPROCEN, 0);
0041 }
0042 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_enable);
0043
0044
0045
0046
0047
0048
0049 void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_bus *bus, bool enable)
0050 {
0051
0052 if (!bus->ppcap) {
0053 dev_err(bus->dev, "Address of PP capability is NULL\n");
0054 return;
0055 }
0056
0057 if (enable)
0058 snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL,
0059 AZX_PPCTL_PIE, AZX_PPCTL_PIE);
0060 else
0061 snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL,
0062 AZX_PPCTL_PIE, 0);
0063 }
0064 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_int_enable);
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079 int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus)
0080 {
0081 int idx;
0082 u32 link_count;
0083 struct hdac_ext_link *hlink;
0084
0085 link_count = readl(bus->mlcap + AZX_REG_ML_MLCD) + 1;
0086
0087 dev_dbg(bus->dev, "In %s Link count: %d\n", __func__, link_count);
0088
0089 for (idx = 0; idx < link_count; idx++) {
0090 hlink = kzalloc(sizeof(*hlink), GFP_KERNEL);
0091 if (!hlink)
0092 return -ENOMEM;
0093 hlink->index = idx;
0094 hlink->bus = bus;
0095 hlink->ml_addr = bus->mlcap + AZX_ML_BASE +
0096 (AZX_ML_INTERVAL * idx);
0097 hlink->lcaps = readl(hlink->ml_addr + AZX_REG_ML_LCAP);
0098 hlink->lsdiid = readw(hlink->ml_addr + AZX_REG_ML_LSDIID);
0099
0100
0101 hlink->ref_count = 1;
0102
0103 list_add_tail(&hlink->list, &bus->hlink_list);
0104 }
0105
0106 return 0;
0107 }
0108 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_ml_capabilities);
0109
0110
0111
0112
0113
0114
0115
0116 void snd_hdac_link_free_all(struct hdac_bus *bus)
0117 {
0118 struct hdac_ext_link *l;
0119
0120 while (!list_empty(&bus->hlink_list)) {
0121 l = list_first_entry(&bus->hlink_list, struct hdac_ext_link, list);
0122 list_del(&l->list);
0123 kfree(l);
0124 }
0125 }
0126 EXPORT_SYMBOL_GPL(snd_hdac_link_free_all);
0127
0128
0129
0130
0131
0132
0133
0134
0135 struct hdac_ext_link *snd_hdac_ext_bus_link_at(struct hdac_bus *bus, int addr)
0136 {
0137 struct hdac_ext_link *hlink;
0138 int i;
0139
0140 list_for_each_entry(hlink, &bus->hlink_list, list)
0141 for (i = 0; i < HDA_MAX_CODECS; i++)
0142 if (hlink->lsdiid & (0x1 << addr))
0143 return hlink;
0144 return NULL;
0145 }
0146 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_at);
0147
0148
0149
0150
0151
0152
0153 struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_bus *bus,
0154 const char *codec_name)
0155 {
0156 int bus_idx, addr;
0157
0158 if (sscanf(codec_name, "ehdaudio%dD%d", &bus_idx, &addr) != 2)
0159 return NULL;
0160 if (bus->idx != bus_idx)
0161 return NULL;
0162 if (addr < 0 || addr > 31)
0163 return NULL;
0164
0165 return snd_hdac_ext_bus_link_at(bus, addr);
0166 }
0167 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_link);
0168
0169 static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable)
0170 {
0171 int timeout;
0172 u32 val;
0173 int mask = (1 << AZX_MLCTL_CPA_SHIFT);
0174
0175 udelay(3);
0176 timeout = 150;
0177
0178 do {
0179 val = readl(link->ml_addr + AZX_REG_ML_LCTL);
0180 if (enable) {
0181 if (((val & mask) >> AZX_MLCTL_CPA_SHIFT))
0182 return 0;
0183 } else {
0184 if (!((val & mask) >> AZX_MLCTL_CPA_SHIFT))
0185 return 0;
0186 }
0187 udelay(3);
0188 } while (--timeout);
0189
0190 return -EIO;
0191 }
0192
0193
0194
0195
0196
0197 int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link)
0198 {
0199 snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL,
0200 AZX_MLCTL_SPA, AZX_MLCTL_SPA);
0201
0202 return check_hdac_link_power_active(link, true);
0203 }
0204 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_up);
0205
0206
0207
0208
0209
0210 int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link)
0211 {
0212 snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL, AZX_MLCTL_SPA, 0);
0213
0214 return check_hdac_link_power_active(link, false);
0215 }
0216 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down);
0217
0218
0219
0220
0221
0222 int snd_hdac_ext_bus_link_power_up_all(struct hdac_bus *bus)
0223 {
0224 struct hdac_ext_link *hlink = NULL;
0225 int ret;
0226
0227 list_for_each_entry(hlink, &bus->hlink_list, list) {
0228 snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL,
0229 AZX_MLCTL_SPA, AZX_MLCTL_SPA);
0230 ret = check_hdac_link_power_active(hlink, true);
0231 if (ret < 0)
0232 return ret;
0233 }
0234
0235 return 0;
0236 }
0237 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_up_all);
0238
0239
0240
0241
0242
0243 int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus)
0244 {
0245 struct hdac_ext_link *hlink = NULL;
0246 int ret;
0247
0248 list_for_each_entry(hlink, &bus->hlink_list, list) {
0249 snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL,
0250 AZX_MLCTL_SPA, 0);
0251 ret = check_hdac_link_power_active(hlink, false);
0252 if (ret < 0)
0253 return ret;
0254 }
0255
0256 return 0;
0257 }
0258 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down_all);
0259
0260 int snd_hdac_ext_bus_link_get(struct hdac_bus *bus,
0261 struct hdac_ext_link *link)
0262 {
0263 unsigned long codec_mask;
0264 int ret = 0;
0265
0266 mutex_lock(&bus->lock);
0267
0268
0269
0270
0271
0272 if (++link->ref_count == 1) {
0273 if (!bus->cmd_dma_state) {
0274 snd_hdac_bus_init_cmd_io(bus);
0275 bus->cmd_dma_state = true;
0276 }
0277
0278 ret = snd_hdac_ext_bus_link_power_up(link);
0279
0280
0281
0282
0283 snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV,
0284 ML_LOSIDV_STREAM_MASK, 0);
0285
0286
0287
0288
0289 udelay(521);
0290 codec_mask = snd_hdac_chip_readw(bus, STATESTS);
0291 dev_dbg(bus->dev, "codec_mask = 0x%lx\n", codec_mask);
0292 snd_hdac_chip_writew(bus, STATESTS, codec_mask);
0293 if (!bus->codec_mask)
0294 bus->codec_mask = codec_mask;
0295 }
0296
0297 mutex_unlock(&bus->lock);
0298 return ret;
0299 }
0300 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_get);
0301
0302 int snd_hdac_ext_bus_link_put(struct hdac_bus *bus,
0303 struct hdac_ext_link *link)
0304 {
0305 int ret = 0;
0306 struct hdac_ext_link *hlink;
0307 bool link_up = false;
0308
0309 mutex_lock(&bus->lock);
0310
0311
0312
0313
0314
0315 if (--link->ref_count == 0) {
0316 ret = snd_hdac_ext_bus_link_power_down(link);
0317
0318
0319
0320
0321
0322 list_for_each_entry(hlink, &bus->hlink_list, list) {
0323 if (hlink->ref_count) {
0324 link_up = true;
0325 break;
0326 }
0327 }
0328
0329 if (!link_up) {
0330 snd_hdac_bus_stop_cmd_io(bus);
0331 bus->cmd_dma_state = false;
0332 }
0333 }
0334
0335 mutex_unlock(&bus->lock);
0336 return ret;
0337 }
0338 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_put);
0339
0340 static void hdac_ext_codec_link_up(struct hdac_device *codec)
0341 {
0342 const char *devname = dev_name(&codec->dev);
0343 struct hdac_ext_link *hlink =
0344 snd_hdac_ext_bus_get_link(codec->bus, devname);
0345
0346 if (hlink)
0347 snd_hdac_ext_bus_link_get(codec->bus, hlink);
0348 }
0349
0350 static void hdac_ext_codec_link_down(struct hdac_device *codec)
0351 {
0352 const char *devname = dev_name(&codec->dev);
0353 struct hdac_ext_link *hlink =
0354 snd_hdac_ext_bus_get_link(codec->bus, devname);
0355
0356 if (hlink)
0357 snd_hdac_ext_bus_link_put(codec->bus, hlink);
0358 }
0359
0360 void snd_hdac_ext_bus_link_power(struct hdac_device *codec, bool enable)
0361 {
0362 struct hdac_bus *bus = codec->bus;
0363 bool oldstate = test_bit(codec->addr, &bus->codec_powered);
0364
0365 if (enable == oldstate)
0366 return;
0367
0368 snd_hdac_bus_link_power(codec, enable);
0369
0370 if (enable)
0371 hdac_ext_codec_link_up(codec);
0372 else
0373 hdac_ext_codec_link_down(codec);
0374 }
0375 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power);