1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright(c) 2019-2020 Intel Corporation.
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>
12 * The sysfs for properties reflects the MIPI description as given
13 * in the MIPI DisCo spec
18 * |---- clk_stop_modes
28 #define sdw_master_attr(field, format_string) \
29 static ssize_t field##_show(struct device *dev, \
30 struct device_attribute *attr, \
33 struct sdw_master_device *md = dev_to_sdw_master_device(dev); \
34 return sprintf(buf, format_string, md->bus->prop.field); \
36 static DEVICE_ATTR_RO(field)
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");
47 static ssize_t
clock_frequencies_show(struct device
*dev
,
48 struct device_attribute
*attr
, char *buf
)
50 struct sdw_master_device
*md
= dev_to_sdw_master_device(dev
);
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");
61 static DEVICE_ATTR_RO(clock_frequencies
);
63 static ssize_t
clock_gears_show(struct device
*dev
,
64 struct device_attribute
*attr
, char *buf
)
66 struct sdw_master_device
*md
= dev_to_sdw_master_device(dev
);
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");
77 static DEVICE_ATTR_RO(clock_gears
);
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
,
92 ATTRIBUTE_GROUPS(master_node
);
94 static void sdw_master_device_release(struct device
*dev
)
96 struct sdw_master_device
*md
= dev_to_sdw_master_device(dev
);
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
)
106 struct device_type sdw_master_type
= {
107 .name
= "soundwire_master",
108 .release
= sdw_master_device_release
,
109 .pm
= &master_dev_pm
,
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
118 int sdw_master_device_add(struct sdw_bus
*bus
, struct device
*parent
,
119 struct fwnode_handle
*fwnode
)
121 struct sdw_master_device
*md
;
127 md
= kzalloc(sizeof(*md
), GFP_KERNEL
);
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
;
139 dev_set_name(&md
->dev
, "sdw-master-%d", bus
->id
);
141 ret
= device_register(&md
->dev
);
143 dev_err(parent
, "Failed to add master: ret %d\n", ret
);
145 * On err, don't free but drop ref as this will be freed
146 * when release method is invoked.
148 put_device(&md
->dev
);
149 goto device_register_err
;
152 /* add shortcuts to improve code readability/compactness */
162 * sdw_master_device_del() - delete a Linux Master Device representation.
165 * This function is the dual of sdw_master_device_add()
167 int sdw_master_device_del(struct sdw_bus
*bus
)
169 device_unregister(bus
->dev
);