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

i2c-pasemi-platform.c (2955B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2021 The Asahi Linux Contributors
      4 *
      5 * PA Semi PWRficient SMBus host driver for Apple SoCs
      6 */
      7
      8#include <linux/clk.h>
      9#include <linux/i2c.h>
     10#include <linux/io.h>
     11#include <linux/kernel.h>
     12#include <linux/module.h>
     13#include <linux/platform_device.h>
     14#include <linux/types.h>
     15
     16#include "i2c-pasemi-core.h"
     17
     18struct pasemi_platform_i2c_data {
     19	struct pasemi_smbus smbus;
     20	struct clk *clk_ref;
     21};
     22
     23static int
     24pasemi_platform_i2c_calc_clk_div(struct pasemi_platform_i2c_data *data,
     25				 u32 frequency)
     26{
     27	unsigned long clk_rate = clk_get_rate(data->clk_ref);
     28
     29	if (!clk_rate)
     30		return -EINVAL;
     31
     32	data->smbus.clk_div = DIV_ROUND_UP(clk_rate, 16 * frequency);
     33	if (data->smbus.clk_div < 4)
     34		return dev_err_probe(data->smbus.dev, -EINVAL,
     35				     "Bus frequency %d is too fast.\n",
     36				     frequency);
     37	if (data->smbus.clk_div > 0xff)
     38		return dev_err_probe(data->smbus.dev, -EINVAL,
     39				     "Bus frequency %d is too slow.\n",
     40				     frequency);
     41
     42	return 0;
     43}
     44
     45static int pasemi_platform_i2c_probe(struct platform_device *pdev)
     46{
     47	struct device *dev = &pdev->dev;
     48	struct pasemi_platform_i2c_data *data;
     49	struct pasemi_smbus *smbus;
     50	u32 frequency;
     51	int error;
     52
     53	data = devm_kzalloc(dev, sizeof(struct pasemi_platform_i2c_data),
     54			    GFP_KERNEL);
     55	if (!data)
     56		return -ENOMEM;
     57
     58	smbus = &data->smbus;
     59	smbus->dev = dev;
     60
     61	smbus->ioaddr = devm_platform_ioremap_resource(pdev, 0);
     62	if (IS_ERR(smbus->ioaddr))
     63		return PTR_ERR(smbus->ioaddr);
     64
     65	if (of_property_read_u32(dev->of_node, "clock-frequency", &frequency))
     66		frequency = I2C_MAX_STANDARD_MODE_FREQ;
     67
     68	data->clk_ref = devm_clk_get(dev, NULL);
     69	if (IS_ERR(data->clk_ref))
     70		return PTR_ERR(data->clk_ref);
     71
     72	error = clk_prepare_enable(data->clk_ref);
     73	if (error)
     74		return error;
     75
     76	error = pasemi_platform_i2c_calc_clk_div(data, frequency);
     77	if (error)
     78		goto out_clk_disable;
     79
     80	smbus->adapter.dev.of_node = pdev->dev.of_node;
     81	error = pasemi_i2c_common_probe(smbus);
     82	if (error)
     83		goto out_clk_disable;
     84
     85	platform_set_drvdata(pdev, data);
     86
     87	return 0;
     88
     89out_clk_disable:
     90	clk_disable_unprepare(data->clk_ref);
     91
     92	return error;
     93}
     94
     95static int pasemi_platform_i2c_remove(struct platform_device *pdev)
     96{
     97	struct pasemi_platform_i2c_data *data = platform_get_drvdata(pdev);
     98
     99	clk_disable_unprepare(data->clk_ref);
    100	return 0;
    101}
    102
    103static const struct of_device_id pasemi_platform_i2c_of_match[] = {
    104	{ .compatible = "apple,t8103-i2c" },
    105	{ .compatible = "apple,i2c" },
    106	{},
    107};
    108MODULE_DEVICE_TABLE(of, pasemi_platform_i2c_of_match);
    109
    110static struct platform_driver pasemi_platform_i2c_driver = {
    111	.driver	= {
    112		.name			= "i2c-apple",
    113		.of_match_table		= pasemi_platform_i2c_of_match,
    114	},
    115	.probe	= pasemi_platform_i2c_probe,
    116	.remove	= pasemi_platform_i2c_remove,
    117};
    118module_platform_driver(pasemi_platform_i2c_driver);
    119
    120MODULE_LICENSE("GPL");
    121MODULE_AUTHOR("Sven Peter <sven@svenpeter.dev>");
    122MODULE_DESCRIPTION("Apple/PASemi SMBus platform driver");