Commit | Line | Data |
---|---|---|
705e0984 RV |
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 <mach/hardware.h> | |
15 | #include "board-mop500.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 | ||
58402b6e | 28 | static struct uib __initdata mop500_uibs[] = { |
705e0984 RV |
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 | ||
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 | */ | |
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 | ||
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 | */ | |
99 | static 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()) | |
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 | ||
135 | module_init(mop500_uib_init); |