|
18 | 18 |
|
19 | 19 | #include <linux/init.h>
|
20 | 20 | #include <linux/module.h>
|
| 21 | +#include <linux/pci.h> |
| 22 | +#include <linux/component.h> |
| 23 | +#include <drm/i915_component.h> |
21 | 24 | #include <sound/core.h>
|
22 |
| -#include <drm/i915_powerwell.h> |
23 | 25 | #include "hda_priv.h"
|
24 | 26 | #include "hda_intel.h"
|
25 | 27 |
|
|
31 | 33 | #define AZX_REG_EM4 0x100c
|
32 | 34 | #define AZX_REG_EM5 0x1010
|
33 | 35 |
|
34 |
| -static int (*get_power)(void); |
35 |
| -static int (*put_power)(void); |
36 |
| -static int (*get_cdclk)(void); |
37 |
| - |
38 | 36 | int hda_display_power(struct hda_intel *hda, bool enable)
|
39 | 37 | {
|
40 |
| - if (!get_power || !put_power) |
| 38 | + struct i915_audio_component *acomp = &hda->audio_component; |
| 39 | + |
| 40 | + if (!acomp->ops) |
41 | 41 | return -ENODEV;
|
42 | 42 |
|
43 |
| - pr_debug("HDA display power %s \n", |
44 |
| - enable ? "Enable" : "Disable"); |
| 43 | + dev_dbg(&hda->chip.pci->dev, "display power %s\n", |
| 44 | + enable ? "enable" : "disable"); |
45 | 45 | if (enable)
|
46 |
| - return get_power(); |
| 46 | + acomp->ops->get_power(acomp->dev); |
47 | 47 | else
|
48 |
| - return put_power(); |
| 48 | + acomp->ops->put_power(acomp->dev); |
| 49 | + |
| 50 | + return 0; |
49 | 51 | }
|
50 | 52 |
|
51 | 53 | void haswell_set_bclk(struct hda_intel *hda)
|
52 | 54 | {
|
53 | 55 | int cdclk_freq;
|
54 | 56 | unsigned int bclk_m, bclk_n;
|
| 57 | + struct i915_audio_component *acomp = &hda->audio_component; |
55 | 58 |
|
56 |
| - if (!get_cdclk) |
| 59 | + if (!acomp->ops) |
57 | 60 | return;
|
58 | 61 |
|
59 |
| - cdclk_freq = get_cdclk(); |
| 62 | + cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev); |
60 | 63 | switch (cdclk_freq) {
|
61 | 64 | case 337500:
|
62 | 65 | bclk_m = 16;
|
@@ -84,47 +87,104 @@ void haswell_set_bclk(struct hda_intel *hda)
|
84 | 87 | azx_writew(&hda->chip, EM5, bclk_n);
|
85 | 88 | }
|
86 | 89 |
|
87 |
| - |
88 |
| -int hda_i915_init(struct hda_intel *hda) |
| 90 | +static int hda_component_master_bind(struct device *dev) |
89 | 91 | {
|
90 |
| - int err = 0; |
| 92 | + struct snd_card *card = dev_get_drvdata(dev); |
| 93 | + struct azx *chip = card->private_data; |
| 94 | + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); |
| 95 | + struct i915_audio_component *acomp = &hda->audio_component; |
| 96 | + int ret; |
| 97 | + |
| 98 | + ret = component_bind_all(dev, acomp); |
| 99 | + if (ret < 0) |
| 100 | + return ret; |
| 101 | + |
| 102 | + if (WARN_ON(!(acomp->dev && acomp->ops && acomp->ops->get_power && |
| 103 | + acomp->ops->put_power && acomp->ops->get_cdclk_freq))) { |
| 104 | + ret = -EINVAL; |
| 105 | + goto out_unbind; |
| 106 | + } |
91 | 107 |
|
92 |
| - get_power = symbol_request(i915_request_power_well); |
93 |
| - if (!get_power) { |
94 |
| - pr_warn("hda-i915: get_power symbol get fail\n"); |
95 |
| - return -ENODEV; |
| 108 | + /* |
| 109 | + * Atm, we don't support dynamic unbinding initiated by the child |
| 110 | + * component, so pin its containing module until we unbind. |
| 111 | + */ |
| 112 | + if (!try_module_get(acomp->ops->owner)) { |
| 113 | + ret = -ENODEV; |
| 114 | + goto out_unbind; |
96 | 115 | }
|
97 | 116 |
|
98 |
| - put_power = symbol_request(i915_release_power_well); |
99 |
| - if (!put_power) { |
100 |
| - symbol_put(i915_request_power_well); |
101 |
| - get_power = NULL; |
102 |
| - return -ENODEV; |
| 117 | + return 0; |
| 118 | + |
| 119 | +out_unbind: |
| 120 | + component_unbind_all(dev, acomp); |
| 121 | + |
| 122 | + return ret; |
| 123 | +} |
| 124 | + |
| 125 | +static void hda_component_master_unbind(struct device *dev) |
| 126 | +{ |
| 127 | + struct snd_card *card = dev_get_drvdata(dev); |
| 128 | + struct azx *chip = card->private_data; |
| 129 | + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); |
| 130 | + struct i915_audio_component *acomp = &hda->audio_component; |
| 131 | + |
| 132 | + module_put(acomp->ops->owner); |
| 133 | + component_unbind_all(dev, acomp); |
| 134 | + WARN_ON(acomp->ops || acomp->dev); |
| 135 | +} |
| 136 | + |
| 137 | +static const struct component_master_ops hda_component_master_ops = { |
| 138 | + .bind = hda_component_master_bind, |
| 139 | + .unbind = hda_component_master_unbind, |
| 140 | +}; |
| 141 | + |
| 142 | +static int hda_component_master_match(struct device *dev, void *data) |
| 143 | +{ |
| 144 | + /* i915 is the only supported component */ |
| 145 | + return !strcmp(dev->driver->name, "i915"); |
| 146 | +} |
| 147 | + |
| 148 | +int hda_i915_init(struct hda_intel *hda) |
| 149 | +{ |
| 150 | + struct component_match *match = NULL; |
| 151 | + struct device *dev = &hda->chip.pci->dev; |
| 152 | + struct i915_audio_component *acomp = &hda->audio_component; |
| 153 | + int ret; |
| 154 | + |
| 155 | + component_match_add(dev, &match, hda_component_master_match, hda); |
| 156 | + ret = component_master_add_with_match(dev, &hda_component_master_ops, |
| 157 | + match); |
| 158 | + if (ret < 0) |
| 159 | + goto out_err; |
| 160 | + |
| 161 | + /* |
| 162 | + * Atm, we don't support deferring the component binding, so make sure |
| 163 | + * i915 is loaded and that the binding successfully completes. |
| 164 | + */ |
| 165 | + request_module("i915"); |
| 166 | + |
| 167 | + if (!acomp->ops) { |
| 168 | + ret = -ENODEV; |
| 169 | + goto out_master_del; |
103 | 170 | }
|
104 | 171 |
|
105 |
| - get_cdclk = symbol_request(i915_get_cdclk_freq); |
106 |
| - if (!get_cdclk) /* may have abnormal BCLK and audio playback rate */ |
107 |
| - pr_warn("hda-i915: get_cdclk symbol get fail\n"); |
| 172 | + dev_dbg(dev, "bound to i915 component master\n"); |
108 | 173 |
|
109 |
| - pr_debug("HDA driver get symbol successfully from i915 module\n"); |
| 174 | + return 0; |
| 175 | +out_master_del: |
| 176 | + component_master_del(dev, &hda_component_master_ops); |
| 177 | +out_err: |
| 178 | + dev_err(dev, "failed to add i915 component master (%d)\n", ret); |
110 | 179 |
|
111 |
| - return err; |
| 180 | + return ret; |
112 | 181 | }
|
113 | 182 |
|
114 | 183 | int hda_i915_exit(struct hda_intel *hda)
|
115 | 184 | {
|
116 |
| - if (get_power) { |
117 |
| - symbol_put(i915_request_power_well); |
118 |
| - get_power = NULL; |
119 |
| - } |
120 |
| - if (put_power) { |
121 |
| - symbol_put(i915_release_power_well); |
122 |
| - put_power = NULL; |
123 |
| - } |
124 |
| - if (get_cdclk) { |
125 |
| - symbol_put(i915_get_cdclk_freq); |
126 |
| - get_cdclk = NULL; |
127 |
| - } |
| 185 | + struct device *dev = &hda->chip.pci->dev; |
| 186 | + |
| 187 | + component_master_del(dev, &hda_component_master_ops); |
128 | 188 |
|
129 | 189 | return 0;
|
130 | 190 | }
|
0 commit comments