162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Helper module for board specific I2C bus registration
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2009 Nokia Corporation.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/i2c.h>
962306a36Sopenharmony_ci#include <linux/platform_data/i2c-omap.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "mux.h"
1262306a36Sopenharmony_ci#include "soc.h"
1362306a36Sopenharmony_ci#include "i2c.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define OMAP_I2C_SIZE		0x3f
1662306a36Sopenharmony_ci#define OMAP1_I2C_BASE		0xfffb3800
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistatic const char name[] = "omap_i2c";
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic struct resource i2c_resources[2] = {
2162306a36Sopenharmony_ci};
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic struct platform_device omap_i2c_devices[1] = {
2462306a36Sopenharmony_ci};
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic void __init omap1_i2c_mux_pins(int bus_id)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	omap_cfg_reg(I2C_SDA);
2962306a36Sopenharmony_ci	omap_cfg_reg(I2C_SCL);
3062306a36Sopenharmony_ci}
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ciint __init omap_i2c_add_bus(struct omap_i2c_bus_platform_data *pdata,
3362306a36Sopenharmony_ci				int bus_id)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	struct platform_device *pdev;
3662306a36Sopenharmony_ci	struct resource *res;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	if (bus_id > 1)
3962306a36Sopenharmony_ci		return -EINVAL;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	omap1_i2c_mux_pins(bus_id);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	pdev = &omap_i2c_devices[bus_id - 1];
4462306a36Sopenharmony_ci	pdev->id = bus_id;
4562306a36Sopenharmony_ci	pdev->name = name;
4662306a36Sopenharmony_ci	pdev->num_resources = ARRAY_SIZE(i2c_resources);
4762306a36Sopenharmony_ci	res = i2c_resources;
4862306a36Sopenharmony_ci	res[0].start = OMAP1_I2C_BASE;
4962306a36Sopenharmony_ci	res[0].end = res[0].start + OMAP_I2C_SIZE;
5062306a36Sopenharmony_ci	res[0].flags = IORESOURCE_MEM;
5162306a36Sopenharmony_ci	res[1].start = INT_I2C;
5262306a36Sopenharmony_ci	res[1].flags = IORESOURCE_IRQ;
5362306a36Sopenharmony_ci	pdev->resource = res;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	/* all OMAP1 have IP version 1 register set */
5662306a36Sopenharmony_ci	pdata->rev = OMAP_I2C_IP_VERSION_1;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	/* all OMAP1 I2C are implemented like this */
5962306a36Sopenharmony_ci	pdata->flags = OMAP_I2C_FLAG_NO_FIFO |
6062306a36Sopenharmony_ci		       OMAP_I2C_FLAG_SIMPLE_CLOCK |
6162306a36Sopenharmony_ci		       OMAP_I2C_FLAG_16BIT_DATA_REG |
6262306a36Sopenharmony_ci		       OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	/* how the cpu bus is wired up differs for 7xx only */
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	pdata->flags |= OMAP_I2C_FLAG_BUS_SHIFT_2;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	pdev->dev.platform_data = pdata;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	return platform_device_register(pdev);
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci#define OMAP_I2C_MAX_CONTROLLERS 4
7462306a36Sopenharmony_cistatic struct omap_i2c_bus_platform_data i2c_pdata[OMAP_I2C_MAX_CONTROLLERS];
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci#define OMAP_I2C_CMDLINE_SETUP	(BIT(31))
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci/**
7962306a36Sopenharmony_ci * omap_i2c_bus_setup - Process command line options for the I2C bus speed
8062306a36Sopenharmony_ci * @str: String of options
8162306a36Sopenharmony_ci *
8262306a36Sopenharmony_ci * This function allow to override the default I2C bus speed for given I2C
8362306a36Sopenharmony_ci * bus with a command line option.
8462306a36Sopenharmony_ci *
8562306a36Sopenharmony_ci * Format: i2c_bus=bus_id,clkrate (in kHz)
8662306a36Sopenharmony_ci *
8762306a36Sopenharmony_ci * Returns 1 on success, 0 otherwise.
8862306a36Sopenharmony_ci */
8962306a36Sopenharmony_cistatic int __init omap_i2c_bus_setup(char *str)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	int ints[3];
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	get_options(str, 3, ints);
9462306a36Sopenharmony_ci	if (ints[0] < 2 || ints[1] < 1 ||
9562306a36Sopenharmony_ci			ints[1] > OMAP_I2C_MAX_CONTROLLERS)
9662306a36Sopenharmony_ci		return 0;
9762306a36Sopenharmony_ci	i2c_pdata[ints[1] - 1].clkrate = ints[2];
9862306a36Sopenharmony_ci	i2c_pdata[ints[1] - 1].clkrate |= OMAP_I2C_CMDLINE_SETUP;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	return 1;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci__setup("i2c_bus=", omap_i2c_bus_setup);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci/*
10562306a36Sopenharmony_ci * Register busses defined in command line but that are not registered with
10662306a36Sopenharmony_ci * omap_register_i2c_bus from board initialization code.
10762306a36Sopenharmony_ci */
10862306a36Sopenharmony_ciint __init omap_register_i2c_bus_cmdline(void)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	int i, err = 0;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(i2c_pdata); i++)
11362306a36Sopenharmony_ci		if (i2c_pdata[i].clkrate & OMAP_I2C_CMDLINE_SETUP) {
11462306a36Sopenharmony_ci			i2c_pdata[i].clkrate &= ~OMAP_I2C_CMDLINE_SETUP;
11562306a36Sopenharmony_ci			err = omap_i2c_add_bus(&i2c_pdata[i], i + 1);
11662306a36Sopenharmony_ci			if (err)
11762306a36Sopenharmony_ci				goto out;
11862306a36Sopenharmony_ci		}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ciout:
12162306a36Sopenharmony_ci	return err;
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci/**
12562306a36Sopenharmony_ci * omap_register_i2c_bus - register I2C bus with device descriptors
12662306a36Sopenharmony_ci * @bus_id: bus id counting from number 1
12762306a36Sopenharmony_ci * @clkrate: clock rate of the bus in kHz
12862306a36Sopenharmony_ci * @info: pointer into I2C device descriptor table or NULL
12962306a36Sopenharmony_ci * @len: number of descriptors in the table
13062306a36Sopenharmony_ci *
13162306a36Sopenharmony_ci * Returns 0 on success or an error code.
13262306a36Sopenharmony_ci */
13362306a36Sopenharmony_ciint __init omap_register_i2c_bus(int bus_id, u32 clkrate,
13462306a36Sopenharmony_ci			  struct i2c_board_info const *info,
13562306a36Sopenharmony_ci			  unsigned len)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	int err;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	BUG_ON(bus_id < 1 || bus_id > OMAP_I2C_MAX_CONTROLLERS);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	if (info) {
14262306a36Sopenharmony_ci		err = i2c_register_board_info(bus_id, info, len);
14362306a36Sopenharmony_ci		if (err)
14462306a36Sopenharmony_ci			return err;
14562306a36Sopenharmony_ci	}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	if (!i2c_pdata[bus_id - 1].clkrate)
14862306a36Sopenharmony_ci		i2c_pdata[bus_id - 1].clkrate = clkrate;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	i2c_pdata[bus_id - 1].clkrate &= ~OMAP_I2C_CMDLINE_SETUP;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	return omap_i2c_add_bus(&i2c_pdata[bus_id - 1], bus_id);
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic  int __init omap_i2c_cmdline(void)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	return omap_register_i2c_bus_cmdline();
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_cisubsys_initcall(omap_i2c_cmdline);
160