File Index
Files and directories
Sign in
FILE

ipu6-bus.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/pci/intel/ipu6/ipu6-bus.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (C) 2013 - 2024 Intel Corporation
  4 */
  5
  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>
 16
 17#include "ipu6.h"
 18#include "ipu6-bus.h"
 19#include "ipu6-buttress.h"
 20#include "ipu6-dma.h"
 21
 22static int bus_pm_runtime_suspend(struct device *dev)
 23{
 24	struct ipu6_bus_device *adev = to_ipu6_bus_device(dev);
 25	int ret;
 26
 27	ret = pm_generic_runtime_suspend(dev);
 28	if (ret)
 29		return ret;
 30
 31	ret = ipu6_buttress_power(dev, adev->ctrl, false);
 32	if (!ret)
 33		return 0;
 34
 35	dev_err(dev, "power down failed!\n");
 36
 37	/* Powering down failed, attempt to resume device now */
 38	ret = pm_generic_runtime_resume(dev);
 39	if (!ret)
 40		return -EBUSY;
 41
 42	return -EIO;
 43}
 44
 45static int bus_pm_runtime_resume(struct device *dev)
 46{
 47	struct ipu6_bus_device *adev = to_ipu6_bus_device(dev);
 48	int ret;
 49
 50	ret = ipu6_buttress_power(dev, adev->ctrl, true);
 51	if (ret)
 52		return ret;
 53
 54	ret = pm_generic_runtime_resume(dev);
 55	if (ret)
 56		goto out_err;
 57
 58	return 0;
 59
 60out_err:
 61	ipu6_buttress_power(dev, adev->ctrl, false);
 62
 63	return -EBUSY;
 64}
 65
 66static struct dev_pm_domain ipu6_bus_pm_domain = {
 67	.ops = {
 68		.runtime_suspend = bus_pm_runtime_suspend,
 69		.runtime_resume = bus_pm_runtime_resume,
 70	},
 71};
 72
 73static DEFINE_MUTEX(ipu6_bus_mutex);
 74
 75static void ipu6_bus_release(struct device *dev)
 76{
 77	struct ipu6_bus_device *adev = to_ipu6_bus_device(dev);
 78
 79	kfree(adev->pdata);
 80	kfree(adev);
 81}
 82
 83struct ipu6_bus_device *
 84ipu6_bus_initialize_device(struct pci_dev *pdev, struct device *parent,
 85			   void *pdata, const struct ipu6_buttress_ctrl *ctrl,
 86			   char *name)
 87{
 88	struct auxiliary_device *auxdev;
 89	struct ipu6_bus_device *adev;
 90	struct ipu6_device *isp = pci_get_drvdata(pdev);
 91	int ret;
 92
 93	adev = kzalloc(sizeof(*adev), GFP_KERNEL);
 94	if (!adev)
 95		return ERR_PTR(-ENOMEM);
 96
 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);
104
105	auxdev->dev.parent = parent;
106	auxdev->dev.release = ipu6_bus_release;
107
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);
114	}
115
116	dev_pm_domain_set(&auxdev->dev, &ipu6_bus_pm_domain);
117
118	pm_runtime_forbid(&adev->auxdev.dev);
119	pm_runtime_enable(&adev->auxdev.dev);
120
121	return adev;
122}
123
124int ipu6_bus_add_device(struct ipu6_bus_device *adev)
125{
126	struct auxiliary_device *auxdev = &adev->auxdev;
127	int ret;
128
129	ret = auxiliary_device_add(auxdev);
130	if (ret) {
131		auxiliary_device_uninit(auxdev);
132		return ret;
133	}
134
135	mutex_lock(&ipu6_bus_mutex);
136	list_add(&adev->list, &adev->isp->devices);
137	mutex_unlock(&ipu6_bus_mutex);
138
139	pm_runtime_allow(&auxdev->dev);
140
141	return 0;
142}
143
144void ipu6_bus_del_devices(struct pci_dev *pdev)
145{
146	struct ipu6_device *isp = pci_get_drvdata(pdev);
147	struct ipu6_bus_device *adev, *save;
148
149	mutex_lock(&ipu6_bus_mutex);
150
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);
156	}
157
158	mutex_unlock(&ipu6_bus_mutex);
159}
~/ Read-only file preview.