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