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