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 3s value for autosuspend will only be used if there are no
13 * devices physically attached on a bus segment. In practice enabling
14 * the bus operation will result in children devices become active and
15 * the master device will only suspend when all its children are no
18 #define SDW_MASTER_SUSPEND_DELAY_MS 3000
21 * The sysfs for properties reflects the MIPI description as given
22 * in the MIPI DisCo spec
27 * |---- clk_stop_modes
37 #define sdw_master_attr(field, format_string) \
38 static ssize_t field##_show(struct device *dev, \
39 struct device_attribute *attr, \
42 struct sdw_master_device *md = dev_to_sdw_master_device(dev); \
43 return sprintf(buf, format_string, md->bus->prop.field); \
45 static DEVICE_ATTR_RO(field)
47 sdw_master_attr(revision
, "0x%x\n");
48 sdw_master_attr(clk_stop_modes
, "0x%x\n");
49 sdw_master_attr(max_clk_freq
, "%d\n");
50 sdw_master_attr(default_row
, "%d\n");
51 sdw_master_attr(default_col
, "%d\n");
52 sdw_master_attr(default_frame_rate
, "%d\n");
53 sdw_master_attr(dynamic_frame
, "%d\n");
54 sdw_master_attr(err_threshold
, "%d\n");
56 static ssize_t
clock_frequencies_show(struct device
*dev
,
57 struct device_attribute
*attr
, char *buf
)
59 struct sdw_master_device
*md
= dev_to_sdw_master_device(dev
);
63 for (i
= 0; i
< md
->bus
->prop
.num_clk_freq
; i
++)
64 size
+= sprintf(buf
+ size
, "%8d ",
65 md
->bus
->prop
.clk_freq
[i
]);
66 size
+= sprintf(buf
+ size
, "\n");
70 static DEVICE_ATTR_RO(clock_frequencies
);
72 static ssize_t
clock_gears_show(struct device
*dev
,
73 struct device_attribute
*attr
, char *buf
)
75 struct sdw_master_device
*md
= dev_to_sdw_master_device(dev
);
79 for (i
= 0; i
< md
->bus
->prop
.num_clk_gears
; i
++)
80 size
+= sprintf(buf
+ size
, "%8d ",
81 md
->bus
->prop
.clk_gears
[i
]);
82 size
+= sprintf(buf
+ size
, "\n");
86 static DEVICE_ATTR_RO(clock_gears
);
88 static struct attribute
*master_node_attrs
[] = {
89 &dev_attr_revision
.attr
,
90 &dev_attr_clk_stop_modes
.attr
,
91 &dev_attr_max_clk_freq
.attr
,
92 &dev_attr_default_row
.attr
,
93 &dev_attr_default_col
.attr
,
94 &dev_attr_default_frame_rate
.attr
,
95 &dev_attr_dynamic_frame
.attr
,
96 &dev_attr_err_threshold
.attr
,
97 &dev_attr_clock_frequencies
.attr
,
98 &dev_attr_clock_gears
.attr
,
101 ATTRIBUTE_GROUPS(master_node
);
103 static void sdw_master_device_release(struct device
*dev
)
105 struct sdw_master_device
*md
= dev_to_sdw_master_device(dev
);
110 static const struct dev_pm_ops master_dev_pm
= {
111 SET_RUNTIME_PM_OPS(pm_generic_runtime_suspend
,
112 pm_generic_runtime_resume
, NULL
)
115 struct device_type sdw_master_type
= {
116 .name
= "soundwire_master",
117 .release
= sdw_master_device_release
,
118 .pm
= &master_dev_pm
,
122 * sdw_master_device_add() - create a Linux Master Device representation.
123 * @bus: SDW bus instance
124 * @parent: parent device
125 * @fwnode: firmware node handle
127 int sdw_master_device_add(struct sdw_bus
*bus
, struct device
*parent
,
128 struct fwnode_handle
*fwnode
)
130 struct sdw_master_device
*md
;
136 md
= kzalloc(sizeof(*md
), GFP_KERNEL
);
140 md
->dev
.bus
= &sdw_bus_type
;
141 md
->dev
.type
= &sdw_master_type
;
142 md
->dev
.parent
= parent
;
143 md
->dev
.groups
= master_node_groups
;
144 md
->dev
.of_node
= parent
->of_node
;
145 md
->dev
.fwnode
= fwnode
;
146 md
->dev
.dma_mask
= parent
->dma_mask
;
148 dev_set_name(&md
->dev
, "sdw-master-%d", bus
->id
);
150 ret
= device_register(&md
->dev
);
152 dev_err(parent
, "Failed to add master: ret %d\n", ret
);
154 * On err, don't free but drop ref as this will be freed
155 * when release method is invoked.
157 put_device(&md
->dev
);
158 goto device_register_err
;
161 /* add shortcuts to improve code readability/compactness */
166 pm_runtime_set_autosuspend_delay(&bus
->md
->dev
, SDW_MASTER_SUSPEND_DELAY_MS
);
167 pm_runtime_use_autosuspend(&bus
->md
->dev
);
168 pm_runtime_mark_last_busy(&bus
->md
->dev
);
169 pm_runtime_set_active(&bus
->md
->dev
);
170 pm_runtime_enable(&bus
->md
->dev
);
171 pm_runtime_idle(&bus
->md
->dev
);
177 * sdw_master_device_del() - delete a Linux Master Device representation.
180 * This function is the dual of sdw_master_device_add()
182 int sdw_master_device_del(struct sdw_bus
*bus
)
184 pm_runtime_disable(&bus
->md
->dev
);
185 device_unregister(bus
->dev
);