Blame view
drivers/soundwire/master.c
4.84 KB
7ceaa40b9 soundwire: bus_ty... |
1 2 3 4 5 |
// SPDX-License-Identifier: GPL-2.0-only // Copyright(c) 2019-2020 Intel Corporation. #include <linux/device.h> #include <linux/acpi.h> |
26d970225 soundwire: master... |
6 |
#include <linux/pm_runtime.h> |
7ceaa40b9 soundwire: bus_ty... |
7 8 9 |
#include <linux/soundwire/sdw.h> #include <linux/soundwire/sdw_type.h> #include "bus.h" |
c5778ca49 soundwire: master... |
10 |
/* |
df40cc8c1 soundwire: master... |
11 12 13 14 15 16 17 18 19 |
* The 3s value for autosuspend will only be used if there are no * devices physically attached on a bus segment. In practice enabling * the bus operation will result in children devices become active and * the master device will only suspend when all its children are no * longer active. */ #define SDW_MASTER_SUSPEND_DELAY_MS 3000 /* |
c5778ca49 soundwire: master... |
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
* The sysfs for properties reflects the MIPI description as given * in the MIPI DisCo spec * * Base file is: * sdw-master-N * |---- revision * |---- clk_stop_modes * |---- max_clk_freq * |---- clk_freq * |---- clk_gears * |---- default_row * |---- default_col * |---- dynamic_shape * |---- err_threshold */ #define sdw_master_attr(field, format_string) \ static ssize_t field##_show(struct device *dev, \ struct device_attribute *attr, \ char *buf) \ { \ struct sdw_master_device *md = dev_to_sdw_master_device(dev); \ return sprintf(buf, format_string, md->bus->prop.field); \ } \ static DEVICE_ATTR_RO(field) sdw_master_attr(revision, "0x%x "); sdw_master_attr(clk_stop_modes, "0x%x "); sdw_master_attr(max_clk_freq, "%d "); sdw_master_attr(default_row, "%d "); sdw_master_attr(default_col, "%d "); sdw_master_attr(default_frame_rate, "%d "); sdw_master_attr(dynamic_frame, "%d "); sdw_master_attr(err_threshold, "%d "); static ssize_t clock_frequencies_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sdw_master_device *md = dev_to_sdw_master_device(dev); ssize_t size = 0; int i; for (i = 0; i < md->bus->prop.num_clk_freq; i++) size += sprintf(buf + size, "%8d ", md->bus->prop.clk_freq[i]); size += sprintf(buf + size, " "); return size; } static DEVICE_ATTR_RO(clock_frequencies); static ssize_t clock_gears_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sdw_master_device *md = dev_to_sdw_master_device(dev); ssize_t size = 0; int i; for (i = 0; i < md->bus->prop.num_clk_gears; i++) size += sprintf(buf + size, "%8d ", md->bus->prop.clk_gears[i]); size += sprintf(buf + size, " "); return size; } static DEVICE_ATTR_RO(clock_gears); static struct attribute *master_node_attrs[] = { &dev_attr_revision.attr, &dev_attr_clk_stop_modes.attr, &dev_attr_max_clk_freq.attr, &dev_attr_default_row.attr, &dev_attr_default_col.attr, &dev_attr_default_frame_rate.attr, &dev_attr_dynamic_frame.attr, &dev_attr_err_threshold.attr, &dev_attr_clock_frequencies.attr, &dev_attr_clock_gears.attr, NULL, }; ATTRIBUTE_GROUPS(master_node); |
7ceaa40b9 soundwire: bus_ty... |
111 112 113 114 115 116 |
static void sdw_master_device_release(struct device *dev) { struct sdw_master_device *md = dev_to_sdw_master_device(dev); kfree(md); } |
26d970225 soundwire: master... |
117 118 119 120 |
static const struct dev_pm_ops master_dev_pm = { SET_RUNTIME_PM_OPS(pm_generic_runtime_suspend, pm_generic_runtime_resume, NULL) }; |
7ceaa40b9 soundwire: bus_ty... |
121 122 123 |
struct device_type sdw_master_type = { .name = "soundwire_master", .release = sdw_master_device_release, |
26d970225 soundwire: master... |
124 |
.pm = &master_dev_pm, |
7ceaa40b9 soundwire: bus_ty... |
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
}; /** * sdw_master_device_add() - create a Linux Master Device representation. * @bus: SDW bus instance * @parent: parent device * @fwnode: firmware node handle */ int sdw_master_device_add(struct sdw_bus *bus, struct device *parent, struct fwnode_handle *fwnode) { struct sdw_master_device *md; int ret; if (!parent) return -EINVAL; md = kzalloc(sizeof(*md), GFP_KERNEL); if (!md) return -ENOMEM; md->dev.bus = &sdw_bus_type; md->dev.type = &sdw_master_type; md->dev.parent = parent; |
c5778ca49 soundwire: master... |
149 |
md->dev.groups = master_node_groups; |
7ceaa40b9 soundwire: bus_ty... |
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
md->dev.of_node = parent->of_node; md->dev.fwnode = fwnode; md->dev.dma_mask = parent->dma_mask; dev_set_name(&md->dev, "sdw-master-%d", bus->id); ret = device_register(&md->dev); if (ret) { dev_err(parent, "Failed to add master: ret %d ", ret); /* * On err, don't free but drop ref as this will be freed * when release method is invoked. */ put_device(&md->dev); goto device_register_err; } /* add shortcuts to improve code readability/compactness */ md->bus = bus; bus->dev = &md->dev; bus->md = md; |
df40cc8c1 soundwire: master... |
172 173 174 175 |
pm_runtime_set_autosuspend_delay(&bus->md->dev, SDW_MASTER_SUSPEND_DELAY_MS); pm_runtime_use_autosuspend(&bus->md->dev); pm_runtime_mark_last_busy(&bus->md->dev); pm_runtime_set_active(&bus->md->dev); |
bd84256e8 soundwire: master... |
176 |
pm_runtime_enable(&bus->md->dev); |
df40cc8c1 soundwire: master... |
177 |
pm_runtime_idle(&bus->md->dev); |
7ceaa40b9 soundwire: bus_ty... |
178 179 180 181 182 183 184 185 186 187 188 189 |
device_register_err: return ret; } /** * sdw_master_device_del() - delete a Linux Master Device representation. * @bus: bus handle * * This function is the dual of sdw_master_device_add() */ int sdw_master_device_del(struct sdw_bus *bus) { |
bd84256e8 soundwire: master... |
190 |
pm_runtime_disable(&bus->md->dev); |
7ceaa40b9 soundwire: bus_ty... |
191 192 193 194 |
device_unregister(bus->dev); return 0; } |