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