cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

fimc-is-i2c.c (3895B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
      4 *
      5 * Copyright (C) 2013 Samsung Electronics Co., Ltd.
      6 *
      7 * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
      8 */
      9
     10#include <linux/clk.h>
     11#include <linux/module.h>
     12#include <linux/i2c.h>
     13#include <linux/platform_device.h>
     14#include <linux/pm_runtime.h>
     15#include <linux/slab.h>
     16#include "fimc-is-i2c.h"
     17
     18struct fimc_is_i2c {
     19	struct i2c_adapter adapter;
     20	struct clk *clock;
     21};
     22
     23/*
     24 * An empty algorithm is used as the actual I2C bus controller driver
     25 * is implemented in the FIMC-IS subsystem firmware and the host CPU
     26 * doesn't access the I2C bus controller.
     27 */
     28static u32 is_i2c_func(struct i2c_adapter *adap)
     29{
     30	return I2C_FUNC_I2C;
     31}
     32
     33static const struct i2c_algorithm fimc_is_i2c_algorithm = {
     34	.functionality	= is_i2c_func,
     35};
     36
     37static int fimc_is_i2c_probe(struct platform_device *pdev)
     38{
     39	struct device_node *node = pdev->dev.of_node;
     40	struct fimc_is_i2c *isp_i2c;
     41	struct i2c_adapter *i2c_adap;
     42	int ret;
     43
     44	isp_i2c = devm_kzalloc(&pdev->dev, sizeof(*isp_i2c), GFP_KERNEL);
     45	if (!isp_i2c)
     46		return -ENOMEM;
     47
     48	isp_i2c->clock = devm_clk_get(&pdev->dev, "i2c_isp");
     49	if (IS_ERR(isp_i2c->clock)) {
     50		dev_err(&pdev->dev, "failed to get the clock\n");
     51		return PTR_ERR(isp_i2c->clock);
     52	}
     53
     54	i2c_adap = &isp_i2c->adapter;
     55	i2c_adap->dev.of_node = node;
     56	i2c_adap->dev.parent = &pdev->dev;
     57	strscpy(i2c_adap->name, "exynos4x12-isp-i2c", sizeof(i2c_adap->name));
     58	i2c_adap->owner = THIS_MODULE;
     59	i2c_adap->algo = &fimc_is_i2c_algorithm;
     60	i2c_adap->class = I2C_CLASS_SPD;
     61
     62	platform_set_drvdata(pdev, isp_i2c);
     63	pm_runtime_enable(&pdev->dev);
     64
     65	ret = i2c_add_adapter(i2c_adap);
     66	if (ret < 0)
     67		goto err_pm_dis;
     68	/*
     69	 * Client drivers of this adapter don't do any I2C transfers as that
     70	 * is handled by the ISP firmware.  But we rely on the runtime PM
     71	 * state propagation from the clients up to the adapter driver so
     72	 * clear the ignore_children flags here.  PM rutnime calls are not
     73	 * used in probe() handler of clients of this adapter so there is
     74	 * no issues with clearing the flag right after registering the I2C
     75	 * adapter.
     76	 */
     77	pm_suspend_ignore_children(&i2c_adap->dev, false);
     78	return 0;
     79
     80err_pm_dis:
     81	pm_runtime_disable(&pdev->dev);
     82	return ret;
     83}
     84
     85static int fimc_is_i2c_remove(struct platform_device *pdev)
     86{
     87	struct fimc_is_i2c *isp_i2c = platform_get_drvdata(pdev);
     88
     89	pm_runtime_disable(&pdev->dev);
     90	i2c_del_adapter(&isp_i2c->adapter);
     91
     92	return 0;
     93}
     94
     95#ifdef CONFIG_PM
     96static int fimc_is_i2c_runtime_suspend(struct device *dev)
     97{
     98	struct fimc_is_i2c *isp_i2c = dev_get_drvdata(dev);
     99
    100	clk_disable_unprepare(isp_i2c->clock);
    101	return 0;
    102}
    103
    104static int fimc_is_i2c_runtime_resume(struct device *dev)
    105{
    106	struct fimc_is_i2c *isp_i2c = dev_get_drvdata(dev);
    107
    108	return clk_prepare_enable(isp_i2c->clock);
    109}
    110#endif
    111
    112#ifdef CONFIG_PM_SLEEP
    113static int fimc_is_i2c_suspend(struct device *dev)
    114{
    115	if (pm_runtime_suspended(dev))
    116		return 0;
    117
    118	return fimc_is_i2c_runtime_suspend(dev);
    119}
    120
    121static int fimc_is_i2c_resume(struct device *dev)
    122{
    123	if (pm_runtime_suspended(dev))
    124		return 0;
    125
    126	return fimc_is_i2c_runtime_resume(dev);
    127}
    128#endif
    129
    130static const struct dev_pm_ops fimc_is_i2c_pm_ops = {
    131	SET_RUNTIME_PM_OPS(fimc_is_i2c_runtime_suspend,
    132					fimc_is_i2c_runtime_resume, NULL)
    133	SET_SYSTEM_SLEEP_PM_OPS(fimc_is_i2c_suspend, fimc_is_i2c_resume)
    134};
    135
    136static const struct of_device_id fimc_is_i2c_of_match[] = {
    137	{ .compatible = FIMC_IS_I2C_COMPATIBLE },
    138	{ },
    139};
    140
    141static struct platform_driver fimc_is_i2c_driver = {
    142	.probe		= fimc_is_i2c_probe,
    143	.remove		= fimc_is_i2c_remove,
    144	.driver = {
    145		.of_match_table = fimc_is_i2c_of_match,
    146		.name		= "fimc-isp-i2c",
    147		.pm		= &fimc_is_i2c_pm_ops,
    148	}
    149};
    150
    151int fimc_is_register_i2c_driver(void)
    152{
    153	return platform_driver_register(&fimc_is_i2c_driver);
    154}
    155
    156void fimc_is_unregister_i2c_driver(void)
    157{
    158	platform_driver_unregister(&fimc_is_i2c_driver);
    159}