diff options
| -rw-r--r-- | include/sound/hdaudio_ext.h | 13 | ||||
| -rw-r--r-- | sound/hda/ext/hdac_ext_bus.c | 3 | ||||
| -rw-r--r-- | sound/hda/ext/hdac_ext_controller.c | 66 |
3 files changed, 82 insertions, 0 deletions
diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h index 07fa59237feb..b9593b201599 100644 --- a/include/sound/hdaudio_ext.h +++ b/include/sound/hdaudio_ext.h | |||
| @@ -14,6 +14,8 @@ | |||
| 14 | * @gtscap: gts capabilities pointer | 14 | * @gtscap: gts capabilities pointer |
| 15 | * @drsmcap: dma resume capabilities pointer | 15 | * @drsmcap: dma resume capabilities pointer |
| 16 | * @hlink_list: link list of HDA links | 16 | * @hlink_list: link list of HDA links |
| 17 | * @lock: lock for link mgmt | ||
| 18 | * @cmd_dma_state: state of cmd DMAs: CORB and RIRB | ||
| 17 | */ | 19 | */ |
| 18 | struct hdac_ext_bus { | 20 | struct hdac_ext_bus { |
| 19 | struct hdac_bus bus; | 21 | struct hdac_bus bus; |
| @@ -27,6 +29,9 @@ struct hdac_ext_bus { | |||
| 27 | void __iomem *drsmcap; | 29 | void __iomem *drsmcap; |
| 28 | 30 | ||
| 29 | struct list_head hlink_list; | 31 | struct list_head hlink_list; |
| 32 | |||
| 33 | struct mutex lock; | ||
| 34 | bool cmd_dma_state; | ||
| 30 | }; | 35 | }; |
| 31 | 36 | ||
| 32 | int snd_hdac_ext_bus_init(struct hdac_ext_bus *sbus, struct device *dev, | 37 | int snd_hdac_ext_bus_init(struct hdac_ext_bus *sbus, struct device *dev, |
| @@ -142,6 +147,9 @@ struct hdac_ext_link { | |||
| 142 | void __iomem *ml_addr; /* link output stream reg pointer */ | 147 | void __iomem *ml_addr; /* link output stream reg pointer */ |
| 143 | u32 lcaps; /* link capablities */ | 148 | u32 lcaps; /* link capablities */ |
| 144 | u16 lsdiid; /* link sdi identifier */ | 149 | u16 lsdiid; /* link sdi identifier */ |
| 150 | |||
| 151 | int ref_count; | ||
| 152 | |||
| 145 | struct list_head list; | 153 | struct list_head list; |
| 146 | }; | 154 | }; |
| 147 | 155 | ||
| @@ -154,6 +162,11 @@ void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link, | |||
| 154 | void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link, | 162 | void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link, |
| 155 | int stream); | 163 | int stream); |
| 156 | 164 | ||
| 165 | int snd_hdac_ext_bus_link_get(struct hdac_ext_bus *ebus, | ||
| 166 | struct hdac_ext_link *link); | ||
| 167 | int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus, | ||
| 168 | struct hdac_ext_link *link); | ||
| 169 | |||
| 157 | /* update register macro */ | 170 | /* update register macro */ |
| 158 | #define snd_hdac_updatel(addr, reg, mask, val) \ | 171 | #define snd_hdac_updatel(addr, reg, mask, val) \ |
| 159 | writel(((readl(addr + reg) & ~(mask)) | (val)), \ | 172 | writel(((readl(addr + reg) & ~(mask)) | (val)), \ |
diff --git a/sound/hda/ext/hdac_ext_bus.c b/sound/hda/ext/hdac_ext_bus.c index 2433f7c81472..3b7ae24900fd 100644 --- a/sound/hda/ext/hdac_ext_bus.c +++ b/sound/hda/ext/hdac_ext_bus.c | |||
| @@ -105,6 +105,9 @@ int snd_hdac_ext_bus_init(struct hdac_ext_bus *ebus, struct device *dev, | |||
| 105 | INIT_LIST_HEAD(&ebus->hlink_list); | 105 | INIT_LIST_HEAD(&ebus->hlink_list); |
| 106 | ebus->idx = idx++; | 106 | ebus->idx = idx++; |
| 107 | 107 | ||
| 108 | mutex_init(&ebus->lock); | ||
| 109 | ebus->cmd_dma_state = true; | ||
| 110 | |||
| 108 | return 0; | 111 | return 0; |
| 109 | } | 112 | } |
| 110 | EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_init); | 113 | EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_init); |
diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c index 548cc1e4114b..860f8cad6602 100644 --- a/sound/hda/ext/hdac_ext_controller.c +++ b/sound/hda/ext/hdac_ext_controller.c | |||
| @@ -186,6 +186,9 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *ebus) | |||
| 186 | hlink->lcaps = readl(hlink->ml_addr + AZX_REG_ML_LCAP); | 186 | hlink->lcaps = readl(hlink->ml_addr + AZX_REG_ML_LCAP); |
| 187 | hlink->lsdiid = readw(hlink->ml_addr + AZX_REG_ML_LSDIID); | 187 | hlink->lsdiid = readw(hlink->ml_addr + AZX_REG_ML_LSDIID); |
| 188 | 188 | ||
| 189 | /* since link in On, update the ref */ | ||
| 190 | hlink->ref_count = 1; | ||
| 191 | |||
| 189 | list_add_tail(&hlink->list, &ebus->hlink_list); | 192 | list_add_tail(&hlink->list, &ebus->hlink_list); |
| 190 | } | 193 | } |
| 191 | 194 | ||
| @@ -327,3 +330,66 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus) | |||
| 327 | return 0; | 330 | return 0; |
| 328 | } | 331 | } |
| 329 | EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down_all); | 332 | EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down_all); |
| 333 | |||
| 334 | int snd_hdac_ext_bus_link_get(struct hdac_ext_bus *ebus, | ||
| 335 | struct hdac_ext_link *link) | ||
| 336 | { | ||
| 337 | int ret = 0; | ||
| 338 | |||
| 339 | mutex_lock(&ebus->lock); | ||
| 340 | |||
| 341 | /* | ||
| 342 | * if we move from 0 to 1, count will be 1 so power up this link | ||
| 343 | * as well, also check the dma status and trigger that | ||
| 344 | */ | ||
| 345 | if (++link->ref_count == 1) { | ||
| 346 | if (!ebus->cmd_dma_state) { | ||
| 347 | snd_hdac_bus_init_cmd_io(&ebus->bus); | ||
| 348 | ebus->cmd_dma_state = true; | ||
| 349 | } | ||
| 350 | |||
| 351 | ret = snd_hdac_ext_bus_link_power_up(link); | ||
| 352 | } | ||
| 353 | |||
| 354 | mutex_unlock(&ebus->lock); | ||
| 355 | return ret; | ||
| 356 | } | ||
| 357 | EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_get); | ||
| 358 | |||
| 359 | int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus, | ||
| 360 | struct hdac_ext_link *link) | ||
| 361 | { | ||
| 362 | int ret = 0; | ||
| 363 | struct hdac_ext_link *hlink; | ||
| 364 | bool link_up = false; | ||
| 365 | |||
| 366 | mutex_lock(&ebus->lock); | ||
| 367 | |||
| 368 | /* | ||
| 369 | * if we move from 1 to 0, count will be 0 | ||
| 370 | * so power down this link as well | ||
| 371 | */ | ||
| 372 | if (--link->ref_count == 0) { | ||
| 373 | ret = snd_hdac_ext_bus_link_power_down(link); | ||
| 374 | |||
| 375 | /* | ||
| 376 | * now check if all links are off, if so turn off | ||
| 377 | * cmd dma as well | ||
| 378 | */ | ||
| 379 | list_for_each_entry(hlink, &ebus->hlink_list, list) { | ||
| 380 | if (hlink->ref_count) { | ||
| 381 | link_up = true; | ||
| 382 | break; | ||
| 383 | } | ||
| 384 | } | ||
| 385 | |||
| 386 | if (!link_up) { | ||
| 387 | snd_hdac_bus_stop_cmd_io(&ebus->bus); | ||
| 388 | ebus->cmd_dma_state = false; | ||
| 389 | } | ||
| 390 | } | ||
| 391 | |||
| 392 | mutex_unlock(&ebus->lock); | ||
| 393 | return ret; | ||
| 394 | } | ||
| 395 | EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_put); | ||
