LCOV - code coverage report
Current view: top level - ipu4 - ipu6-bus.c (source / functions) Coverage Total Hit
Test: ipu4.info Lines: 57.8 % 64 37
Test Date: 2026-05-12 04:57:36 Functions: 57.1 % 7 4

            Line data    Source code
       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              : 
      22            4 : static 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            4 :         ret = pm_generic_runtime_suspend(dev);
      28            4 :         if (ret)
      29              :                 return ret;
      30              : 
      31            4 :         ret = ipu6_buttress_power(dev, adev->ctrl, false);
      32            4 :         if (!ret)
      33              :                 return 0;
      34              : 
      35            0 :         dev_err(dev, "power down failed!\n");
      36              : 
      37              :         /* Powering down failed, attempt to resume device now */
      38            0 :         ret = pm_generic_runtime_resume(dev);
      39            0 :         if (!ret)
      40            0 :                 return -EBUSY;
      41              : 
      42              :         return -EIO;
      43              : }
      44              : 
      45            4 : static 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            4 :         ret = ipu6_buttress_power(dev, adev->ctrl, true);
      51            4 :         if (ret)
      52              :                 return ret;
      53              : 
      54            4 :         ret = pm_generic_runtime_resume(dev);
      55            4 :         if (ret)
      56            0 :                 goto out_err;
      57              : 
      58              :         return 0;
      59              : 
      60              : out_err:
      61            0 :         ipu6_buttress_power(dev, adev->ctrl, false);
      62              : 
      63            0 :         return -EBUSY;
      64              : }
      65              : 
      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,
      70              :         },
      71              : };
      72              : 
      73              : static DEFINE_MUTEX(ipu6_bus_mutex);
      74              : 
      75            0 : static void ipu6_bus_release(struct device *dev)
      76              : {
      77              :         struct ipu6_bus_device *adev = to_ipu6_bus_device(dev);
      78              : 
      79            0 :         kfree(adev->pdata);
      80            0 :         kfree(adev);
      81            0 : }
      82              : 
      83              : struct ipu6_bus_device *
      84            2 : ipu6_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            2 :         adev = kzalloc(sizeof(*adev), GFP_KERNEL);
      94            2 :         if (!adev)
      95              :                 return ERR_PTR(-ENOMEM);
      96              : 
      97            2 :         adev->isp = isp;
      98            2 :         adev->ctrl = ctrl;
      99            2 :         adev->pdata = pdata;
     100            2 :         auxdev = &adev->auxdev;
     101            2 :         auxdev->name = name;
     102            2 :         auxdev->id = (pci_domain_nr(pdev->bus) << 16) |
     103            2 :                       PCI_DEVID(pdev->bus->number, pdev->devfn);
     104              : 
     105            2 :         auxdev->dev.parent = parent;
     106            2 :         auxdev->dev.release = ipu6_bus_release;
     107              : 
     108            2 :         ret = auxiliary_device_init(auxdev);
     109            2 :         if (ret < 0) {
     110            0 :                 dev_err(&isp->pdev->dev, "auxiliary device init failed (%d)\n",
     111              :                         ret);
     112            0 :                 kfree(adev);
     113            0 :                 return ERR_PTR(ret);
     114              :         }
     115              : 
     116            2 :         dev_pm_domain_set(&auxdev->dev, &ipu6_bus_pm_domain);
     117              : 
     118            2 :         pm_runtime_forbid(&adev->auxdev.dev);
     119            2 :         pm_runtime_enable(&adev->auxdev.dev);
     120              : 
     121            2 :         return adev;
     122              : }
     123              : 
     124            2 : int ipu6_bus_add_device(struct ipu6_bus_device *adev)
     125              : {
     126            2 :         struct auxiliary_device *auxdev = &adev->auxdev;
     127              :         int ret;
     128              : 
     129            2 :         ret = auxiliary_device_add(auxdev);
     130            2 :         if (ret) {
     131              :                 auxiliary_device_uninit(auxdev);
     132            0 :                 return ret;
     133              :         }
     134              : 
     135            2 :         mutex_lock(&ipu6_bus_mutex);
     136            2 :         list_add(&adev->list, &adev->isp->devices);
     137            2 :         mutex_unlock(&ipu6_bus_mutex);
     138              : 
     139            2 :         pm_runtime_allow(&auxdev->dev);
     140              : 
     141            2 :         return 0;
     142              : }
     143              : 
     144            0 : void 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            0 :         mutex_lock(&ipu6_bus_mutex);
     150              : 
     151            0 :         list_for_each_entry_safe(adev, save, &isp->devices, list) {
     152            0 :                 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            0 :         mutex_unlock(&ipu6_bus_mutex);
     159            0 : }
     160              : 
     161              : // Implemented by Ambu for silent_reset feature
     162            0 : int ipu6_bus_reset_device(struct ipu6_bus_device *adev)
     163              : {
     164              :         int ret = 0;
     165            0 :         struct device *dev = &adev->auxdev.dev;
     166              : 
     167            0 :         ret = bus_pm_runtime_suspend(dev);
     168            0 :         if (ret < 0)
     169              :                 return ret;
     170              : 
     171            0 :         ret = bus_pm_runtime_resume(dev);
     172            0 :         return ret;
     173              : }
     174              : EXPORT_SYMBOL(ipu6_bus_reset_device);
        

Generated by: LCOV version 2.0-1