• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) ST-Ericsson SA 2010
3  *
4  * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
5  * License terms: GNU General Public License (GPL), version 2
6  */
7 
8 #define pr_fmt(fmt)	"mop500-uib: " fmt
9 
10 #include <linux/kernel.h>
11 #include <linux/init.h>
12 #include <linux/i2c.h>
13 
14 #include "board-mop500.h"
15 #include "id.h"
16 
17 enum mop500_uib {
18 	STUIB,
19 	U8500UIB,
20 };
21 
22 struct uib {
23 	const char *name;
24 	const char *option;
25 	void (*init)(void);
26 };
27 
28 static struct uib __initdata mop500_uibs[] = {
29 	[STUIB] = {
30 		.name	= "ST-UIB",
31 		.option	= "stuib",
32 		.init	= mop500_stuib_init,
33 	},
34 	[U8500UIB] = {
35 		.name	= "U8500-UIB",
36 		.option	= "u8500uib",
37 		.init	= mop500_u8500uib_init,
38 	},
39 };
40 
41 static struct uib *mop500_uib;
42 
mop500_uib_setup(char * str)43 static int __init mop500_uib_setup(char *str)
44 {
45 	int i;
46 
47 	for (i = 0; i < ARRAY_SIZE(mop500_uibs); i++) {
48 		struct uib *uib = &mop500_uibs[i];
49 
50 		if (!strcmp(str, uib->option)) {
51 			mop500_uib = uib;
52 			break;
53 		}
54 	}
55 
56 	if (i == ARRAY_SIZE(mop500_uibs))
57 		pr_err("invalid uib= option (%s)\n", str);
58 
59 	return 1;
60 }
61 __setup("uib=", mop500_uib_setup);
62 
63 /*
64  * The UIBs are detected after the I2C host controllers are registered, so
65  * i2c_register_board_info() can't be used.
66  */
mop500_uib_i2c_add(int busnum,struct i2c_board_info * info,unsigned n)67 void mop500_uib_i2c_add(int busnum, struct i2c_board_info *info,
68 		unsigned n)
69 {
70 	struct i2c_adapter *adap;
71 	struct i2c_client *client;
72 	int i;
73 
74 	adap = i2c_get_adapter(busnum);
75 	if (!adap) {
76 		pr_err("failed to get adapter i2c%d\n", busnum);
77 		return;
78 	}
79 
80 	for (i = 0; i < n; i++) {
81 		client = i2c_new_device(adap, &info[i]);
82 		if (!client)
83 			pr_err("failed to register %s to i2c%d\n",
84 					info[i].type, busnum);
85 	}
86 
87 	i2c_put_adapter(adap);
88 }
89 
__mop500_uib_init(struct uib * uib,const char * why)90 static void __init __mop500_uib_init(struct uib *uib, const char *why)
91 {
92 	pr_info("%s (%s)\n", uib->name, why);
93 	uib->init();
94 }
95 
96 /*
97  * Detect the UIB attached based on the presence or absence of i2c devices.
98  */
mop500_uib_init(void)99 int __init mop500_uib_init(void)
100 {
101 	struct uib *uib = mop500_uib;
102 	struct i2c_adapter *i2c0;
103 	int ret;
104 
105 	if (!cpu_is_u8500_family())
106 		return -ENODEV;
107 
108 	if (uib) {
109 		__mop500_uib_init(uib, "from uib= boot argument");
110 		return 0;
111 	}
112 
113 	i2c0 = i2c_get_adapter(0);
114 	if (!i2c0) {
115 		__mop500_uib_init(&mop500_uibs[STUIB],
116 				"fallback, could not get i2c0");
117 		return -ENODEV;
118 	}
119 
120 	/* U8500-UIB has the TC35893 at 0x44 on I2C0, the ST-UIB doesn't. */
121 	ret = i2c_smbus_xfer(i2c0, 0x44, 0, I2C_SMBUS_WRITE, 0,
122 			I2C_SMBUS_QUICK, NULL);
123 	i2c_put_adapter(i2c0);
124 
125 	if (ret == 0)
126 		uib = &mop500_uibs[U8500UIB];
127 	else
128 		uib = &mop500_uibs[STUIB];
129 
130 	__mop500_uib_init(uib, "detected");
131 
132 	return 0;
133 }
134