Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / drivers / media / pci / intel / ipu6 / ipu6-bus.c
blob37d88ddb6ee7cda6340b6b591a376f8dc507c272
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2013 - 2024 Intel Corporation
4 */
6 #include <linux/auxiliary_bus.h>
7 #include <linux/device.h>
8 #include <linux/dma-mapping.h>
9 #include <linux/err.h>
10 #include <linux/list.h>
11 #include <linux/mutex.h>
12 #include <linux/pci.h>
13 #include <linux/pm_domain.h>
14 #include <linux/pm_runtime.h>
15 #include <linux/slab.h>
17 #include "ipu6.h"
18 #include "ipu6-bus.h"
19 #include "ipu6-buttress.h"
20 #include "ipu6-dma.h"
22 static int bus_pm_runtime_suspend(struct device *dev)
24 struct ipu6_bus_device *adev = to_ipu6_bus_device(dev);
25 int ret;
27 ret = pm_generic_runtime_suspend(dev);
28 if (ret)
29 return ret;
31 ret = ipu6_buttress_power(dev, adev->ctrl, false);
32 if (!ret)
33 return 0;
35 dev_err(dev, "power down failed!\n");
37 /* Powering down failed, attempt to resume device now */
38 ret = pm_generic_runtime_resume(dev);
39 if (!ret)
40 return -EBUSY;
42 return -EIO;
45 static int bus_pm_runtime_resume(struct device *dev)
47 struct ipu6_bus_device *adev = to_ipu6_bus_device(dev);
48 int ret;
50 ret = ipu6_buttress_power(dev, adev->ctrl, true);
51 if (ret)
52 return ret;
54 ret = pm_generic_runtime_resume(dev);
55 if (ret)
56 goto out_err;
58 return 0;
60 out_err:
61 ipu6_buttress_power(dev, adev->ctrl, false);
63 return -EBUSY;
66 static struct dev_pm_domain ipu6_bus_pm_domain = {
67 .ops = {
68 .runtime_suspend = bus_pm_runtime_suspend,
69 .runtime_resume = bus_pm_runtime_resume,
73 static DEFINE_MUTEX(ipu6_bus_mutex);
75 static void ipu6_bus_release(struct device *dev)
77 struct ipu6_bus_device *adev = to_ipu6_bus_device(dev);
79 kfree(adev->pdata);
80 kfree(adev);
83 struct ipu6_bus_device *
84 ipu6_bus_initialize_device(struct pci_dev *pdev, struct device *parent,
85 void *pdata, struct ipu6_buttress_ctrl *ctrl,
86 char *name)
88 struct auxiliary_device *auxdev;
89 struct ipu6_bus_device *adev;
90 struct ipu6_device *isp = pci_get_drvdata(pdev);
91 int ret;
93 adev = kzalloc(sizeof(*adev), GFP_KERNEL);
94 if (!adev)
95 return ERR_PTR(-ENOMEM);
97 adev->isp = isp;
98 adev->ctrl = ctrl;
99 adev->pdata = pdata;
100 auxdev = &adev->auxdev;
101 auxdev->name = name;
102 auxdev->id = (pci_domain_nr(pdev->bus) << 16) |
103 PCI_DEVID(pdev->bus->number, pdev->devfn);
105 auxdev->dev.parent = parent;
106 auxdev->dev.release = ipu6_bus_release;
108 ret = auxiliary_device_init(auxdev);
109 if (ret < 0) {
110 dev_err(&isp->pdev->dev, "auxiliary device init failed (%d)\n",
111 ret);
112 kfree(adev);
113 return ERR_PTR(ret);
116 dev_pm_domain_set(&auxdev->dev, &ipu6_bus_pm_domain);
118 pm_runtime_forbid(&adev->auxdev.dev);
119 pm_runtime_enable(&adev->auxdev.dev);
121 return adev;
124 int ipu6_bus_add_device(struct ipu6_bus_device *adev)
126 struct auxiliary_device *auxdev = &adev->auxdev;
127 int ret;
129 ret = auxiliary_device_add(auxdev);
130 if (ret) {
131 auxiliary_device_uninit(auxdev);
132 return ret;
135 mutex_lock(&ipu6_bus_mutex);
136 list_add(&adev->list, &adev->isp->devices);
137 mutex_unlock(&ipu6_bus_mutex);
139 pm_runtime_allow(&auxdev->dev);
141 return 0;
144 void ipu6_bus_del_devices(struct pci_dev *pdev)
146 struct ipu6_device *isp = pci_get_drvdata(pdev);
147 struct ipu6_bus_device *adev, *save;
149 mutex_lock(&ipu6_bus_mutex);
151 list_for_each_entry_safe(adev, save, &isp->devices, list) {
152 pm_runtime_disable(&adev->auxdev.dev);
153 list_del(&adev->list);
154 auxiliary_device_delete(&adev->auxdev);
155 auxiliary_device_uninit(&adev->auxdev);
158 mutex_unlock(&ipu6_bus_mutex);