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