18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Helper module for board specific I2C bus registration
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2009 Nokia Corporation.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/i2c.h>
98c2ecf20Sopenharmony_ci#include <linux/platform_data/i2c-omap.h>
108c2ecf20Sopenharmony_ci#include <mach/mux.h>
118c2ecf20Sopenharmony_ci#include "soc.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#define OMAP_I2C_SIZE		0x3f
148c2ecf20Sopenharmony_ci#define OMAP1_I2C_BASE		0xfffb3800
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cistatic const char name[] = "omap_i2c";
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic struct resource i2c_resources[2] = {
198c2ecf20Sopenharmony_ci};
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic struct platform_device omap_i2c_devices[1] = {
228c2ecf20Sopenharmony_ci};
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistatic void __init omap1_i2c_mux_pins(int bus_id)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	if (cpu_is_omap7xx()) {
278c2ecf20Sopenharmony_ci		omap_cfg_reg(I2C_7XX_SDA);
288c2ecf20Sopenharmony_ci		omap_cfg_reg(I2C_7XX_SCL);
298c2ecf20Sopenharmony_ci	} else {
308c2ecf20Sopenharmony_ci		omap_cfg_reg(I2C_SDA);
318c2ecf20Sopenharmony_ci		omap_cfg_reg(I2C_SCL);
328c2ecf20Sopenharmony_ci	}
338c2ecf20Sopenharmony_ci}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ciint __init omap_i2c_add_bus(struct omap_i2c_bus_platform_data *pdata,
368c2ecf20Sopenharmony_ci				int bus_id)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	struct platform_device *pdev;
398c2ecf20Sopenharmony_ci	struct resource *res;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	if (bus_id > 1)
428c2ecf20Sopenharmony_ci		return -EINVAL;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	omap1_i2c_mux_pins(bus_id);
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	pdev = &omap_i2c_devices[bus_id - 1];
478c2ecf20Sopenharmony_ci	pdev->id = bus_id;
488c2ecf20Sopenharmony_ci	pdev->name = name;
498c2ecf20Sopenharmony_ci	pdev->num_resources = ARRAY_SIZE(i2c_resources);
508c2ecf20Sopenharmony_ci	res = i2c_resources;
518c2ecf20Sopenharmony_ci	res[0].start = OMAP1_I2C_BASE;
528c2ecf20Sopenharmony_ci	res[0].end = res[0].start + OMAP_I2C_SIZE;
538c2ecf20Sopenharmony_ci	res[0].flags = IORESOURCE_MEM;
548c2ecf20Sopenharmony_ci	res[1].start = INT_I2C;
558c2ecf20Sopenharmony_ci	res[1].flags = IORESOURCE_IRQ;
568c2ecf20Sopenharmony_ci	pdev->resource = res;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	/* all OMAP1 have IP version 1 register set */
598c2ecf20Sopenharmony_ci	pdata->rev = OMAP_I2C_IP_VERSION_1;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	/* all OMAP1 I2C are implemented like this */
628c2ecf20Sopenharmony_ci	pdata->flags = OMAP_I2C_FLAG_NO_FIFO |
638c2ecf20Sopenharmony_ci		       OMAP_I2C_FLAG_SIMPLE_CLOCK |
648c2ecf20Sopenharmony_ci		       OMAP_I2C_FLAG_16BIT_DATA_REG |
658c2ecf20Sopenharmony_ci		       OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	/* how the cpu bus is wired up differs for 7xx only */
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	if (cpu_is_omap7xx())
708c2ecf20Sopenharmony_ci		pdata->flags |= OMAP_I2C_FLAG_BUS_SHIFT_1;
718c2ecf20Sopenharmony_ci	else
728c2ecf20Sopenharmony_ci		pdata->flags |= OMAP_I2C_FLAG_BUS_SHIFT_2;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	pdev->dev.platform_data = pdata;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	return platform_device_register(pdev);
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci#define OMAP_I2C_MAX_CONTROLLERS 4
808c2ecf20Sopenharmony_cistatic struct omap_i2c_bus_platform_data i2c_pdata[OMAP_I2C_MAX_CONTROLLERS];
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci#define OMAP_I2C_CMDLINE_SETUP	(BIT(31))
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci/**
858c2ecf20Sopenharmony_ci * omap_i2c_bus_setup - Process command line options for the I2C bus speed
868c2ecf20Sopenharmony_ci * @str: String of options
878c2ecf20Sopenharmony_ci *
888c2ecf20Sopenharmony_ci * This function allow to override the default I2C bus speed for given I2C
898c2ecf20Sopenharmony_ci * bus with a command line option.
908c2ecf20Sopenharmony_ci *
918c2ecf20Sopenharmony_ci * Format: i2c_bus=bus_id,clkrate (in kHz)
928c2ecf20Sopenharmony_ci *
938c2ecf20Sopenharmony_ci * Returns 1 on success, 0 otherwise.
948c2ecf20Sopenharmony_ci */
958c2ecf20Sopenharmony_cistatic int __init omap_i2c_bus_setup(char *str)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	int ints[3];
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	get_options(str, 3, ints);
1008c2ecf20Sopenharmony_ci	if (ints[0] < 2 || ints[1] < 1 ||
1018c2ecf20Sopenharmony_ci			ints[1] > OMAP_I2C_MAX_CONTROLLERS)
1028c2ecf20Sopenharmony_ci		return 0;
1038c2ecf20Sopenharmony_ci	i2c_pdata[ints[1] - 1].clkrate = ints[2];
1048c2ecf20Sopenharmony_ci	i2c_pdata[ints[1] - 1].clkrate |= OMAP_I2C_CMDLINE_SETUP;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	return 1;
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci__setup("i2c_bus=", omap_i2c_bus_setup);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci/*
1118c2ecf20Sopenharmony_ci * Register busses defined in command line but that are not registered with
1128c2ecf20Sopenharmony_ci * omap_register_i2c_bus from board initialization code.
1138c2ecf20Sopenharmony_ci */
1148c2ecf20Sopenharmony_ciint __init omap_register_i2c_bus_cmdline(void)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	int i, err = 0;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(i2c_pdata); i++)
1198c2ecf20Sopenharmony_ci		if (i2c_pdata[i].clkrate & OMAP_I2C_CMDLINE_SETUP) {
1208c2ecf20Sopenharmony_ci			i2c_pdata[i].clkrate &= ~OMAP_I2C_CMDLINE_SETUP;
1218c2ecf20Sopenharmony_ci			err = omap_i2c_add_bus(&i2c_pdata[i], i + 1);
1228c2ecf20Sopenharmony_ci			if (err)
1238c2ecf20Sopenharmony_ci				goto out;
1248c2ecf20Sopenharmony_ci		}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ciout:
1278c2ecf20Sopenharmony_ci	return err;
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci/**
1318c2ecf20Sopenharmony_ci * omap_register_i2c_bus - register I2C bus with device descriptors
1328c2ecf20Sopenharmony_ci * @bus_id: bus id counting from number 1
1338c2ecf20Sopenharmony_ci * @clkrate: clock rate of the bus in kHz
1348c2ecf20Sopenharmony_ci * @info: pointer into I2C device descriptor table or NULL
1358c2ecf20Sopenharmony_ci * @len: number of descriptors in the table
1368c2ecf20Sopenharmony_ci *
1378c2ecf20Sopenharmony_ci * Returns 0 on success or an error code.
1388c2ecf20Sopenharmony_ci */
1398c2ecf20Sopenharmony_ciint __init omap_register_i2c_bus(int bus_id, u32 clkrate,
1408c2ecf20Sopenharmony_ci			  struct i2c_board_info const *info,
1418c2ecf20Sopenharmony_ci			  unsigned len)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	int err;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	BUG_ON(bus_id < 1 || bus_id > OMAP_I2C_MAX_CONTROLLERS);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	if (info) {
1488c2ecf20Sopenharmony_ci		err = i2c_register_board_info(bus_id, info, len);
1498c2ecf20Sopenharmony_ci		if (err)
1508c2ecf20Sopenharmony_ci			return err;
1518c2ecf20Sopenharmony_ci	}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	if (!i2c_pdata[bus_id - 1].clkrate)
1548c2ecf20Sopenharmony_ci		i2c_pdata[bus_id - 1].clkrate = clkrate;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	i2c_pdata[bus_id - 1].clkrate &= ~OMAP_I2C_CMDLINE_SETUP;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	return omap_i2c_add_bus(&i2c_pdata[bus_id - 1], bus_id);
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic  int __init omap_i2c_cmdline(void)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	return omap_register_i2c_bus_cmdline();
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_cisubsys_initcall(omap_i2c_cmdline);
166