xref: /openbmc/linux/drivers/soundwire/master.c (revision 7e8eebef)
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 device_register_err:
158 	return ret;
159 }
160 
161 /**
162  * sdw_master_device_del() - delete a Linux Master Device representation.
163  * @bus: bus handle
164  *
165  * This function is the dual of sdw_master_device_add()
166  */
167 int sdw_master_device_del(struct sdw_bus *bus)
168 {
169 	device_unregister(bus->dev);
170 
171 	return 0;
172 }
173