Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 // Copyright(c) 2019-2020 Intel Corporation.
0003 
0004 #include <linux/device.h>
0005 #include <linux/acpi.h>
0006 #include <linux/pm_runtime.h>
0007 #include <linux/soundwire/sdw.h>
0008 #include <linux/soundwire/sdw_type.h>
0009 #include "bus.h"
0010 
0011 /*
0012  * The 3s value for autosuspend will only be used if there are no
0013  * devices physically attached on a bus segment. In practice enabling
0014  * the bus operation will result in children devices become active and
0015  * the master device will only suspend when all its children are no
0016  * longer active.
0017  */
0018 #define SDW_MASTER_SUSPEND_DELAY_MS 3000
0019 
0020 /*
0021  * The sysfs for properties reflects the MIPI description as given
0022  * in the MIPI DisCo spec
0023  *
0024  * Base file is:
0025  *  sdw-master-N
0026  *      |---- revision
0027  *      |---- clk_stop_modes
0028  *      |---- max_clk_freq
0029  *      |---- clk_freq
0030  *      |---- clk_gears
0031  *      |---- default_row
0032  *      |---- default_col
0033  *      |---- dynamic_shape
0034  *      |---- err_threshold
0035  */
0036 
0037 #define sdw_master_attr(field, format_string)               \
0038 static ssize_t field##_show(struct device *dev,             \
0039                 struct device_attribute *attr,      \
0040                 char *buf)                  \
0041 {                                   \
0042     struct sdw_master_device *md = dev_to_sdw_master_device(dev);   \
0043     return sprintf(buf, format_string, md->bus->prop.field);    \
0044 }                                   \
0045 static DEVICE_ATTR_RO(field)
0046 
0047 sdw_master_attr(revision, "0x%x\n");
0048 sdw_master_attr(clk_stop_modes, "0x%x\n");
0049 sdw_master_attr(max_clk_freq, "%d\n");
0050 sdw_master_attr(default_row, "%d\n");
0051 sdw_master_attr(default_col, "%d\n");
0052 sdw_master_attr(default_frame_rate, "%d\n");
0053 sdw_master_attr(dynamic_frame, "%d\n");
0054 sdw_master_attr(err_threshold, "%d\n");
0055 
0056 static ssize_t clock_frequencies_show(struct device *dev,
0057                       struct device_attribute *attr, char *buf)
0058 {
0059     struct sdw_master_device *md = dev_to_sdw_master_device(dev);
0060     ssize_t size = 0;
0061     int i;
0062 
0063     for (i = 0; i < md->bus->prop.num_clk_freq; i++)
0064         size += sprintf(buf + size, "%8d ",
0065                 md->bus->prop.clk_freq[i]);
0066     size += sprintf(buf + size, "\n");
0067 
0068     return size;
0069 }
0070 static DEVICE_ATTR_RO(clock_frequencies);
0071 
0072 static ssize_t clock_gears_show(struct device *dev,
0073                 struct device_attribute *attr, char *buf)
0074 {
0075     struct sdw_master_device *md = dev_to_sdw_master_device(dev);
0076     ssize_t size = 0;
0077     int i;
0078 
0079     for (i = 0; i < md->bus->prop.num_clk_gears; i++)
0080         size += sprintf(buf + size, "%8d ",
0081                 md->bus->prop.clk_gears[i]);
0082     size += sprintf(buf + size, "\n");
0083 
0084     return size;
0085 }
0086 static DEVICE_ATTR_RO(clock_gears);
0087 
0088 static struct attribute *master_node_attrs[] = {
0089     &dev_attr_revision.attr,
0090     &dev_attr_clk_stop_modes.attr,
0091     &dev_attr_max_clk_freq.attr,
0092     &dev_attr_default_row.attr,
0093     &dev_attr_default_col.attr,
0094     &dev_attr_default_frame_rate.attr,
0095     &dev_attr_dynamic_frame.attr,
0096     &dev_attr_err_threshold.attr,
0097     &dev_attr_clock_frequencies.attr,
0098     &dev_attr_clock_gears.attr,
0099     NULL,
0100 };
0101 ATTRIBUTE_GROUPS(master_node);
0102 
0103 static void sdw_master_device_release(struct device *dev)
0104 {
0105     struct sdw_master_device *md = dev_to_sdw_master_device(dev);
0106 
0107     kfree(md);
0108 }
0109 
0110 static const struct dev_pm_ops master_dev_pm = {
0111     SET_RUNTIME_PM_OPS(pm_generic_runtime_suspend,
0112                pm_generic_runtime_resume, NULL)
0113 };
0114 
0115 struct device_type sdw_master_type = {
0116     .name =     "soundwire_master",
0117     .release =  sdw_master_device_release,
0118     .pm = &master_dev_pm,
0119 };
0120 
0121 /**
0122  * sdw_master_device_add() - create a Linux Master Device representation.
0123  * @bus: SDW bus instance
0124  * @parent: parent device
0125  * @fwnode: firmware node handle
0126  */
0127 int sdw_master_device_add(struct sdw_bus *bus, struct device *parent,
0128               struct fwnode_handle *fwnode)
0129 {
0130     struct sdw_master_device *md;
0131     int ret;
0132 
0133     if (!parent)
0134         return -EINVAL;
0135 
0136     md = kzalloc(sizeof(*md), GFP_KERNEL);
0137     if (!md)
0138         return -ENOMEM;
0139 
0140     md->dev.bus = &sdw_bus_type;
0141     md->dev.type = &sdw_master_type;
0142     md->dev.parent = parent;
0143     md->dev.groups = master_node_groups;
0144     md->dev.of_node = parent->of_node;
0145     md->dev.fwnode = fwnode;
0146     md->dev.dma_mask = parent->dma_mask;
0147 
0148     dev_set_name(&md->dev, "sdw-master-%d", bus->id);
0149 
0150     ret = device_register(&md->dev);
0151     if (ret) {
0152         dev_err(parent, "Failed to add master: ret %d\n", ret);
0153         /*
0154          * On err, don't free but drop ref as this will be freed
0155          * when release method is invoked.
0156          */
0157         put_device(&md->dev);
0158         goto device_register_err;
0159     }
0160 
0161     /* add shortcuts to improve code readability/compactness */
0162     md->bus = bus;
0163     bus->dev = &md->dev;
0164     bus->md = md;
0165 
0166     pm_runtime_set_autosuspend_delay(&bus->md->dev, SDW_MASTER_SUSPEND_DELAY_MS);
0167     pm_runtime_use_autosuspend(&bus->md->dev);
0168     pm_runtime_mark_last_busy(&bus->md->dev);
0169     pm_runtime_set_active(&bus->md->dev);
0170     pm_runtime_enable(&bus->md->dev);
0171     pm_runtime_idle(&bus->md->dev);
0172 device_register_err:
0173     return ret;
0174 }
0175 
0176 /**
0177  * sdw_master_device_del() - delete a Linux Master Device representation.
0178  * @bus: bus handle
0179  *
0180  * This function is the dual of sdw_master_device_add()
0181  */
0182 int sdw_master_device_del(struct sdw_bus *bus)
0183 {
0184     pm_runtime_disable(&bus->md->dev);
0185     device_unregister(bus->dev);
0186 
0187     return 0;
0188 }